OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |