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

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

Issue 3001423002: Initial idle GC logic. (Closed)
Patch Set: divide-by-zero Created 3 years, 3 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
« 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 "vm/dart.h" 7 #include "vm/dart.h"
8 #include "vm/dart_api_state.h" 8 #include "vm/dart_api_state.h"
9 #include "vm/isolate.h" 9 #include "vm/isolate.h"
10 #include "vm/lockers.h" 10 #include "vm/lockers.h"
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 Scavenger::Scavenger(Heap* heap, 316 Scavenger::Scavenger(Heap* heap,
317 intptr_t max_semi_capacity_in_words, 317 intptr_t max_semi_capacity_in_words,
318 uword object_alignment) 318 uword object_alignment)
319 : heap_(heap), 319 : heap_(heap),
320 max_semi_capacity_in_words_(max_semi_capacity_in_words), 320 max_semi_capacity_in_words_(max_semi_capacity_in_words),
321 object_alignment_(object_alignment), 321 object_alignment_(object_alignment),
322 scavenging_(false), 322 scavenging_(false),
323 delayed_weak_properties_(NULL), 323 delayed_weak_properties_(NULL),
324 gc_time_micros_(0), 324 gc_time_micros_(0),
325 collections_(0), 325 collections_(0),
326 scavenge_words_per_micro_(400),
327 idle_scavenge_threshold_in_words_(0),
326 external_size_(0), 328 external_size_(0),
327 failed_to_promote_(false) { 329 failed_to_promote_(false) {
328 // Verify assumptions about the first word in objects which the scavenger is 330 // Verify assumptions about the first word in objects which the scavenger is
329 // going to use for forwarding pointers. 331 // going to use for forwarding pointers.
330 ASSERT(Object::tags_offset() == 0); 332 ASSERT(Object::tags_offset() == 0);
331 333
332 // Set initial size resulting in a total of three different levels. 334 // Set initial size resulting in a total of three different levels.
333 const intptr_t initial_semi_capacity_in_words = 335 const intptr_t initial_semi_capacity_in_words =
334 max_semi_capacity_in_words / 336 max_semi_capacity_in_words /
335 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor); 337 (FLAG_new_gen_growth_factor * FLAG_new_gen_growth_factor);
336 338
337 const intptr_t kVmNameSize = 128; 339 const intptr_t kVmNameSize = 128;
338 char vm_name[kVmNameSize]; 340 char vm_name[kVmNameSize];
339 Heap::RegionName(heap_, Heap::kNew, vm_name, kVmNameSize); 341 Heap::RegionName(heap_, Heap::kNew, vm_name, kVmNameSize);
340 to_ = SemiSpace::New(initial_semi_capacity_in_words, vm_name); 342 to_ = SemiSpace::New(initial_semi_capacity_in_words, vm_name);
341 if (to_ == NULL) { 343 if (to_ == NULL) {
342 OUT_OF_MEMORY(); 344 OUT_OF_MEMORY();
343 } 345 }
344 // Setup local fields. 346 // Setup local fields.
345 top_ = FirstObjectStart(); 347 top_ = FirstObjectStart();
346 resolved_top_ = top_; 348 resolved_top_ = top_;
347 end_ = to_->end(); 349 end_ = to_->end();
348 350
349 survivor_end_ = FirstObjectStart(); 351 survivor_end_ = FirstObjectStart();
352 idle_scavenge_threshold_in_words_ = initial_semi_capacity_in_words;
350 353
351 UpdateMaxHeapCapacity(); 354 UpdateMaxHeapCapacity();
352 UpdateMaxHeapUsage(); 355 UpdateMaxHeapUsage();
353 } 356 }
354 357
355 Scavenger::~Scavenger() { 358 Scavenger::~Scavenger() {
356 ASSERT(!scavenging_); 359 ASSERT(!scavenging_);
357 to_->Delete(); 360 to_->Delete();
358 } 361 }
359 362
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
420 avg_frac /= 1.0 + 0.5; // Normalize. 423 avg_frac /= 1.0 + 0.5; // Normalize.
421 } 424 }
422 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) { 425 if (avg_frac < (FLAG_early_tenuring_threshold / 100.0)) {
423 // Remember the limit to which objects have been copied. 426 // Remember the limit to which objects have been copied.
424 survivor_end_ = top_; 427 survivor_end_ = top_;
425 } else { 428 } else {
426 // Move survivor end to the end of the to_ space, making all surviving 429 // Move survivor end to the end of the to_ space, making all surviving
427 // objects candidates for promotion next time. 430 // objects candidates for promotion next time.
428 survivor_end_ = end_; 431 survivor_end_ = end_;
429 } 432 }
433
434 // Update estimate of scavenger speed. This statistic assumes survivorship
435 // rates don't change much.
436 intptr_t history_used = 0;
437 intptr_t history_micros = 0;
438 ASSERT(stats_history_.Size() > 0);
439 for (intptr_t i = 0; i < stats_history_.Size(); i++) {
440 history_used += stats_history_.Get(i).UsedBeforeInWords();
441 history_micros += stats_history_.Get(i).DurationMicros();
442 }
443 if (history_micros == 0) {
444 history_micros = 1;
445 }
446 scavenge_words_per_micro_ = history_used / history_micros;
447 if (scavenge_words_per_micro_ == 0) {
448 scavenge_words_per_micro_ = 1;
449 }
450
451 // Update amount of new-space we must allocate before performing an idle
452 // scavenge. This is based on the amount of work we expect to be able to
453 // complete in a typical idle period.
454 intptr_t average_idle_task_micros = 4000;
455 idle_scavenge_threshold_in_words_ =
456 scavenge_words_per_micro_ * average_idle_task_micros;
457 // Even if the scavenge speed is slow, make sure we don't scavenge too
458 // frequently, which just wastes power and falsely increases the promotion
459 // rate.
460 intptr_t lower_bound = 512 * KBInWords;
461 if (idle_scavenge_threshold_in_words_ < lower_bound) {
462 idle_scavenge_threshold_in_words_ = lower_bound;
463 }
464 // Even if the scavenge speed is very high, make sure we start considering
465 // idle scavenges before new space is full to avoid requiring a scavenge in
466 // the middle of a frame.
467 intptr_t upper_bound = 8 * CapacityInWords() / 10;
468 if (idle_scavenge_threshold_in_words_ > upper_bound) {
469 idle_scavenge_threshold_in_words_ = upper_bound;
470 }
471
430 #if defined(DEBUG) 472 #if defined(DEBUG)
431 // We can only safely verify the store buffers from old space if there is no 473 // We can only safely verify the store buffers from old space if there is no
432 // concurrent old space task. At the same time we prevent new tasks from 474 // concurrent old space task. At the same time we prevent new tasks from
433 // being spawned. 475 // being spawned.
434 { 476 {
435 PageSpace* page_space = heap_->old_space(); 477 PageSpace* page_space = heap_->old_space();
436 MonitorLocker ml(page_space->tasks_lock()); 478 MonitorLocker ml(page_space->tasks_lock());
437 if (page_space->tasks() == 0) { 479 if (page_space->tasks() == 0) {
438 VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_); 480 VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_);
439 heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor); 481 heap_->old_space()->VisitObjectPointers(&verify_store_buffer_visitor);
440 } 482 }
441 } 483 }
442 #endif // defined(DEBUG) 484 #endif // defined(DEBUG)
443 from->Delete(); 485 from->Delete();
444 UpdateMaxHeapUsage(); 486 UpdateMaxHeapUsage();
445 if (heap_ != NULL) { 487 if (heap_ != NULL) {
446 heap_->UpdateGlobalMaxUsed(); 488 heap_->UpdateGlobalMaxUsed();
447 } 489 }
448 } 490 }
449 491
492 bool Scavenger::ShouldPerformIdleScavenge(int64_t deadline) {
493 // TODO(rmacnak): Investigate collecting a history of idle period durations.
494 intptr_t used_in_words = UsedInWords();
495 if (used_in_words < idle_scavenge_threshold_in_words_) {
496 return false;
497 }
498 int64_t estimated_scavenge_completion =
499 OS::GetCurrentMonotonicMicros() +
500 used_in_words / scavenge_words_per_micro_;
501 return estimated_scavenge_completion <= deadline;
502 }
503
450 void Scavenger::IterateStoreBuffers(Isolate* isolate, 504 void Scavenger::IterateStoreBuffers(Isolate* isolate,
451 ScavengerVisitor* visitor) { 505 ScavengerVisitor* visitor) {
452 // Iterating through the store buffers. 506 // Iterating through the store buffers.
453 // Grab the deduplication sets out of the isolate's consolidated store buffer. 507 // Grab the deduplication sets out of the isolate's consolidated store buffer.
454 StoreBufferBlock* pending = isolate->store_buffer()->Blocks(); 508 StoreBufferBlock* pending = isolate->store_buffer()->Blocks();
455 intptr_t total_count = 0; 509 intptr_t total_count = 0;
456 while (pending != NULL) { 510 while (pending != NULL) {
457 StoreBufferBlock* next = pending->next(); 511 StoreBufferBlock* next = pending->next();
458 // Generated code appends to store buffers; tell MemorySanitizer. 512 // Generated code appends to store buffers; tell MemorySanitizer.
459 MSAN_UNPOISON(pending, sizeof(*pending)); 513 MSAN_UNPOISON(pending, sizeof(*pending));
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
768 } 822 }
769 823
770 void Scavenger::Scavenge() { 824 void Scavenger::Scavenge() {
771 Isolate* isolate = heap_->isolate(); 825 Isolate* isolate = heap_->isolate();
772 // Ensure that all threads for this isolate are at a safepoint (either stopped 826 // Ensure that all threads for this isolate are at a safepoint (either stopped
773 // or in native code). If two threads are racing at this point, the loser 827 // or in native code). If two threads are racing at this point, the loser
774 // will continue with its scavenge after waiting for the winner to complete. 828 // will continue with its scavenge after waiting for the winner to complete.
775 // TODO(koda): Consider moving SafepointThreads into allocation failure/retry 829 // TODO(koda): Consider moving SafepointThreads into allocation failure/retry
776 // logic to avoid needless collections. 830 // logic to avoid needless collections.
777 831
778 int64_t pre_safe_point = OS::GetCurrentMonotonicMicros(); 832 int64_t start = OS::GetCurrentMonotonicMicros();
779 833
780 Thread* thread = Thread::Current(); 834 Thread* thread = Thread::Current();
781 SafepointOperationScope safepoint_scope(thread); 835 SafepointOperationScope safepoint_scope(thread);
782 836
783 // Scavenging is not reentrant. Make sure that is the case. 837 // Scavenging is not reentrant. Make sure that is the case.
784 ASSERT(!scavenging_); 838 ASSERT(!scavenging_);
785 scavenging_ = true; 839 scavenging_ = true;
786 840
787 failed_to_promote_ = false; 841 failed_to_promote_ = false;
788 842
789 PageSpace* page_space = heap_->old_space(); 843 PageSpace* page_space = heap_->old_space();
790 NoSafepointScope no_safepoints; 844 NoSafepointScope no_safepoints;
791 845
792 int64_t post_safe_point = OS::GetCurrentMonotonicMicros(); 846 int64_t safe_point = OS::GetCurrentMonotonicMicros();
793 heap_->RecordTime(kSafePoint, post_safe_point - pre_safe_point); 847 heap_->RecordTime(kSafePoint, safe_point - start);
794 848
795 // TODO(koda): Make verification more compatible with concurrent sweep. 849 // TODO(koda): Make verification more compatible with concurrent sweep.
796 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) { 850 if (FLAG_verify_before_gc && !FLAG_concurrent_sweep) {
797 OS::PrintErr("Verifying before Scavenge..."); 851 OS::PrintErr("Verifying before Scavenge...");
798 heap_->Verify(kForbidMarked); 852 heap_->Verify(kForbidMarked);
799 OS::PrintErr(" done.\n"); 853 OS::PrintErr(" done.\n");
800 } 854 }
801 855
802 // Prepare for a scavenge. 856 // Prepare for a scavenge.
803 SpaceUsage usage_before = GetCurrentUsage(); 857 SpaceUsage usage_before = GetCurrentUsage();
804 intptr_t promo_candidate_words = 858 intptr_t promo_candidate_words =
805 (survivor_end_ - FirstObjectStart()) / kWordSize; 859 (survivor_end_ - FirstObjectStart()) / kWordSize;
806 SemiSpace* from = Prologue(isolate); 860 SemiSpace* from = Prologue(isolate);
807 // The API prologue/epilogue may create/destroy zones, so we must not 861 // The API prologue/epilogue may create/destroy zones, so we must not
808 // depend on zone allocations surviving beyond the epilogue callback. 862 // depend on zone allocations surviving beyond the epilogue callback.
809 { 863 {
810 StackZone zone(thread); 864 StackZone zone(thread);
811 // Setup the visitor and run the scavenge. 865 // Setup the visitor and run the scavenge.
812 ScavengerVisitor visitor(isolate, this, from); 866 ScavengerVisitor visitor(isolate, this, from);
813 page_space->AcquireDataLock(); 867 page_space->AcquireDataLock();
814 IterateRoots(isolate, &visitor); 868 IterateRoots(isolate, &visitor);
815 int64_t start = OS::GetCurrentMonotonicMicros(); 869 int64_t iterate_roots = OS::GetCurrentMonotonicMicros();
816 ProcessToSpace(&visitor); 870 ProcessToSpace(&visitor);
817 int64_t middle = OS::GetCurrentMonotonicMicros(); 871 int64_t process_to_space = OS::GetCurrentMonotonicMicros();
818 { 872 {
819 TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing"); 873 TIMELINE_FUNCTION_GC_DURATION(thread, "WeakHandleProcessing");
820 ScavengerWeakVisitor weak_visitor(thread, this); 874 ScavengerWeakVisitor weak_visitor(thread, this);
821 IterateWeakRoots(isolate, &weak_visitor); 875 IterateWeakRoots(isolate, &weak_visitor);
822 } 876 }
823 ProcessWeakReferences(); 877 ProcessWeakReferences();
824 page_space->ReleaseDataLock(); 878 page_space->ReleaseDataLock();
825 879
826 // Scavenge finished. Run accounting. 880 // Scavenge finished. Run accounting.
827 int64_t end = OS::GetCurrentMonotonicMicros(); 881 int64_t end = OS::GetCurrentMonotonicMicros();
828 heap_->RecordTime(kProcessToSpace, middle - start); 882 heap_->RecordTime(kProcessToSpace, process_to_space - iterate_roots);
829 heap_->RecordTime(kIterateWeaks, end - middle); 883 heap_->RecordTime(kIterateWeaks, end - process_to_space);
830 stats_history_.Add(ScavengeStats( 884 stats_history_.Add(ScavengeStats(
831 start, end, usage_before, GetCurrentUsage(), promo_candidate_words, 885 start, end, usage_before, GetCurrentUsage(), promo_candidate_words,
832 visitor.bytes_promoted() >> kWordSizeLog2)); 886 visitor.bytes_promoted() >> kWordSizeLog2));
833 } 887 }
834 Epilogue(isolate, from); 888 Epilogue(isolate, from);
835 889
836 // TODO(koda): Make verification more compatible with concurrent sweep. 890 // TODO(koda): Make verification more compatible with concurrent sweep.
837 if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) { 891 if (FLAG_verify_after_gc && !FLAG_concurrent_sweep) {
838 OS::PrintErr("Verifying after Scavenge..."); 892 OS::PrintErr("Verifying after Scavenge...");
839 heap_->Verify(kForbidMarked); 893 heap_->Verify(kForbidMarked);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 } 963 }
910 964
911 Scavenge(); 965 Scavenge();
912 966
913 // It is possible for objects to stay in the new space 967 // It is possible for objects to stay in the new space
914 // if the VM cannot create more pages for these objects. 968 // if the VM cannot create more pages for these objects.
915 ASSERT((UsedInWords() == 0) || failed_to_promote_); 969 ASSERT((UsedInWords() == 0) || failed_to_promote_);
916 } 970 }
917 971
918 } // namespace dart 972 } // 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