Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: runtime/vm/scavenger.cc

Issue 329163003: Grow new gen (1M -> 4M -> 16M on 32-bit) when there is little garbage. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/scavenger.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/scavenger.h" 5 #include "vm/scavenger.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 #include <utility> 9 #include <utility>
10 10
11 #include "vm/dart.h" 11 #include "vm/dart.h"
12 #include "vm/dart_api_state.h" 12 #include "vm/dart_api_state.h"
13 #include "vm/isolate.h" 13 #include "vm/isolate.h"
14 #include "vm/object.h" 14 #include "vm/object.h"
15 #include "vm/stack_frame.h" 15 #include "vm/stack_frame.h"
16 #include "vm/store_buffer.h" 16 #include "vm/store_buffer.h"
17 #include "vm/thread.h" 17 #include "vm/thread.h"
18 #include "vm/verifier.h" 18 #include "vm/verifier.h"
19 #include "vm/visitor.h" 19 #include "vm/visitor.h"
20 #include "vm/weak_table.h" 20 #include "vm/weak_table.h"
21 #include "vm/object_id_ring.h" 21 #include "vm/object_id_ring.h"
22 22
23 namespace dart { 23 namespace dart {
24 24
25 DEFINE_FLAG(int, early_tenuring_threshold, 66, 25 DEFINE_FLAG(int, early_tenuring_threshold, 66,
26 "When more than this percentage of promotion candidates survive, " 26 "When more than this percentage of promotion candidates survive, "
27 "promote all survivors of next scavenge."); 27 "promote all survivors of next scavenge.");
28 DEFINE_FLAG(int, new_gen_garbage_threshold, 90,
29 "Grow new gen when less than this percentage is garbage.");
30 DEFINE_FLAG(int, new_gen_growth_factor, 4, "Grow new gen by this factor.");
28 31
29 // Scavenger uses RawObject::kMarkBit to distinguish forwaded and non-forwarded 32 // Scavenger uses RawObject::kMarkBit to distinguish forwaded and non-forwarded
30 // objects. The kMarkBit does not intersect with the target address because of 33 // objects. The kMarkBit does not intersect with the target address because of
31 // object alignment. 34 // object alignment.
32 enum { 35 enum {
33 kForwardingMask = 1 << RawObject::kMarkBit, 36 kForwardingMask = 1 << RawObject::kMarkBit,
34 kNotForwarded = 0, 37 kNotForwarded = 0,
35 kForwarded = kForwardingMask, 38 kForwarded = kForwardingMask,
36 }; 39 };
37 40
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
311 : reserved_(reserved), region_(NULL, 0) { 314 : reserved_(reserved), region_(NULL, 0) {
312 if (reserved != NULL) { 315 if (reserved != NULL) {
313 region_ = MemoryRegion(reserved_->address(), reserved_->size()); 316 region_ = MemoryRegion(reserved_->address(), reserved_->size());
314 } 317 }
315 } 318 }
316 319
317 320
318 SemiSpace::~SemiSpace() { 321 SemiSpace::~SemiSpace() {
319 if (reserved_ != NULL) { 322 if (reserved_ != NULL) {
320 #if defined(DEBUG) 323 #if defined(DEBUG)
321 memset(reserved_->address(), 0xf3, size()); 324 memset(reserved_->address(), 0xf3, size_in_words() << kWordSizeLog2);
322 #endif // defined(DEBUG) 325 #endif // defined(DEBUG)
323 delete reserved_; 326 delete reserved_;
324 } 327 }
325 } 328 }
326 329
327 330
328 Mutex* SemiSpace::mutex_ = NULL; 331 Mutex* SemiSpace::mutex_ = NULL;
329 SemiSpace* SemiSpace::cache_ = NULL; 332 SemiSpace* SemiSpace::cache_ = NULL;
330 333
331 334
332 void SemiSpace::InitOnce() { 335 void SemiSpace::InitOnce() {
333 ASSERT(mutex_ == NULL); 336 ASSERT(mutex_ == NULL);
334 mutex_ = new Mutex(); 337 mutex_ = new Mutex();
335 ASSERT(mutex_ != NULL); 338 ASSERT(mutex_ != NULL);
336 } 339 }
337 340
338 341
339 SemiSpace* SemiSpace::New(intptr_t size) { 342 SemiSpace* SemiSpace::New(intptr_t size_in_words) {
340 { 343 {
341 MutexLocker locker(mutex_); 344 MutexLocker locker(mutex_);
342 if (cache_ != NULL && cache_->size() == size) { 345 // TODO(koda): Cache one entry per size.
346 if (cache_ != NULL && cache_->size_in_words() == size_in_words) {
343 SemiSpace* result = cache_; 347 SemiSpace* result = cache_;
344 cache_ = NULL; 348 cache_ = NULL;
345 return result; 349 return result;
346 } 350 }
347 } 351 }
348 if (size == 0) { 352 if (size_in_words == 0) {
349 return new SemiSpace(NULL); 353 return new SemiSpace(NULL);
350 } else { 354 } else {
351 VirtualMemory* reserved = VirtualMemory::Reserve(size); 355 intptr_t size_in_bytes = size_in_words << kWordSizeLog2;
356 VirtualMemory* reserved = VirtualMemory::Reserve(size_in_bytes);
352 if ((reserved == NULL) || !reserved->Commit(VirtualMemory::kReadWrite)) { 357 if ((reserved == NULL) || !reserved->Commit(VirtualMemory::kReadWrite)) {
353 // TODO(koda): If cache_ is not empty, we could try to delete it. 358 // TODO(koda): If cache_ is not empty, we could try to delete it.
354 delete reserved; 359 delete reserved;
355 return NULL; 360 return NULL;
356 } 361 }
357 #if defined(DEBUG) 362 #if defined(DEBUG)
358 memset(reserved->address(), 0xf3, size); 363 memset(reserved->address(), 0xf3, size_in_bytes);
359 #endif // defined(DEBUG) 364 #endif // defined(DEBUG)
360 return new SemiSpace(reserved); 365 return new SemiSpace(reserved);
361 } 366 }
362 } 367 }
363 368
364 369
365 void SemiSpace::Delete() { 370 void SemiSpace::Delete() {
366 SemiSpace* old_cache = NULL; 371 SemiSpace* old_cache = NULL;
367 { 372 {
368 MutexLocker locker(mutex_); 373 MutexLocker locker(mutex_);
369 old_cache = cache_; 374 old_cache = cache_;
370 cache_ = this; 375 cache_ = this;
371 } 376 }
372 delete old_cache; 377 delete old_cache;
373 } 378 }
374 379
375 380
376 void SemiSpace::WriteProtect(bool read_only) { 381 void SemiSpace::WriteProtect(bool read_only) {
377 if (reserved_ != NULL) { 382 if (reserved_ != NULL) {
378 bool success = reserved_->Protect( 383 bool success = reserved_->Protect(
379 read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite); 384 read_only ? VirtualMemory::kReadOnly : VirtualMemory::kReadWrite);
380 ASSERT(success); 385 ASSERT(success);
381 } 386 }
382 } 387 }
383 388
384 389
385 Scavenger::Scavenger(Heap* heap, 390 Scavenger::Scavenger(Heap* heap,
386 intptr_t max_capacity_in_words, 391 intptr_t max_semi_capacity_in_words,
387 uword object_alignment) 392 uword object_alignment)
388 : heap_(heap), 393 : heap_(heap),
394 max_semi_capacity_in_words_(max_semi_capacity_in_words),
389 object_alignment_(object_alignment), 395 object_alignment_(object_alignment),
390 scavenging_(false), 396 scavenging_(false),
391 gc_time_micros_(0), 397 gc_time_micros_(0),
392 collections_(0), 398 collections_(0),
393 external_size_(0) { 399 external_size_(0) {
394 // Verify assumptions about the first word in objects which the scavenger is 400 // Verify assumptions about the first word in objects which the scavenger is
395 // going to use for forwarding pointers. 401 // going to use for forwarding pointers.
396 ASSERT(Object::tags_offset() == 0); 402 ASSERT(Object::tags_offset() == 0);
397 403
398 const intptr_t semi_space_size = (max_capacity_in_words / 2) * kWordSize; 404 // Set initial size resulting in a total of three different levels.
399 to_ = SemiSpace::New(semi_space_size); 405 const intptr_t initial_semi_capacity_in_words = max_semi_capacity_in_words /
406 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor);
407 to_ = SemiSpace::New(initial_semi_capacity_in_words);
400 if (to_ == NULL) { 408 if (to_ == NULL) {
401 FATAL("Out of memory.\n"); 409 FATAL("Out of memory.\n");
402 } 410 }
403 from_ = NULL; 411 from_ = NULL;
404 412
405 // Setup local fields. 413 // Setup local fields.
406 top_ = FirstObjectStart(); 414 top_ = FirstObjectStart();
407 resolved_top_ = top_; 415 resolved_top_ = top_;
408 end_ = to_->end(); 416 end_ = to_->end();
409 417
410 survivor_end_ = FirstObjectStart(); 418 survivor_end_ = FirstObjectStart();
411 } 419 }
412 420
413 421
414 Scavenger::~Scavenger() { 422 Scavenger::~Scavenger() {
415 ASSERT(!scavenging_); 423 ASSERT(!scavenging_);
416 ASSERT(from_ == NULL); 424 ASSERT(from_ == NULL);
417 to_->Delete(); 425 to_->Delete();
418 } 426 }
419 427
420 428
429 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const {
430 if (stats_history_.Size() == 0) {
431 return old_size_in_words;
432 }
433 double garbage = stats_history_.Get(0).GarbageFraction();
434 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) {
435 return Utils::Minimum(max_semi_capacity_in_words_,
436 old_size_in_words * FLAG_new_gen_growth_factor);
437 } else {
438 return old_size_in_words;
439 }
440 }
441
442
421 void Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { 443 void Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) {
422 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { 444 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) {
423 (isolate->gc_prologue_callback())(); 445 (isolate->gc_prologue_callback())();
424 } 446 }
425 // Flip the two semi-spaces so that to_ is always the space for allocating 447 // Flip the two semi-spaces so that to_ is always the space for allocating
426 // objects. 448 // objects.
427 from_ = to_; 449 from_ = to_;
428 // TODO(koda): Use stats_history_ to decide new to-space size. 450 to_ = SemiSpace::New(NewSizeInWords(from_->size_in_words()));
429 to_ = SemiSpace::New(from_->size());
430 if (to_ == NULL) { 451 if (to_ == NULL) {
431 // TODO(koda): We could try to recover (collect old space, wait for another 452 // TODO(koda): We could try to recover (collect old space, wait for another
432 // isolate to finish scavenge, etc.). 453 // isolate to finish scavenge, etc.).
433 FATAL("Out of memory.\n"); 454 FATAL("Out of memory.\n");
434 } 455 }
435 top_ = FirstObjectStart(); 456 top_ = FirstObjectStart();
436 resolved_top_ = top_; 457 resolved_top_ = top_;
437 end_ = to_->end(); 458 end_ = to_->end();
438 } 459 }
439 460
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after
834 } 855 }
835 856
836 857
837 void Scavenger::FreeExternal(intptr_t size) { 858 void Scavenger::FreeExternal(intptr_t size) {
838 ASSERT(size >= 0); 859 ASSERT(size >= 0);
839 external_size_ -= size; 860 external_size_ -= size;
840 ASSERT(external_size_ >= 0); 861 ASSERT(external_size_ >= 0);
841 } 862 }
842 863
843 } // namespace dart 864 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/scavenger.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698