From c96a2d3a742fe789af64387c4796d7aa0a5a494f Mon Sep 17 00:00:00 2001 From: hpayer Date: Thu, 16 Apr 2015 09:31:41 -0700 Subject: [PATCH] Use smaller heap growing factor in idle notification to start incremental marking when there is idle time >16ms. BUG=chromium:477323 LOG=y Review URL: https://codereview.chromium.org/1090963002 Cr-Commit-Position: refs/heads/master@{#27897} --- src/heap/gc-idle-time-handler.h | 5 +++- src/heap/heap.cc | 51 +++++++++++++++++++++++---------- src/heap/heap.h | 23 +++++++++++---- src/heap/incremental-marking.cc | 4 ++- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/heap/gc-idle-time-handler.h b/src/heap/gc-idle-time-handler.h index f953c87b3..ed89b8bc7 100644 --- a/src/heap/gc-idle-time-handler.h +++ b/src/heap/gc-idle-time-handler.h @@ -119,9 +119,12 @@ class GCIdleTimeHandler { static const int kIdleScavengeThreshold; // This is the maximum scheduled idle time. Note that it can be more than - // 16 ms when there is currently no rendering going on. + // 16.66 ms when there is currently no rendering going on. static const size_t kMaxScheduledIdleTime = 50; + // The maximum idle time when frames are rendered is 16.66ms. + static const size_t kMaxFrameRenderingIdleTime = 17; + // We conservatively assume that in the next kTimeUntilNextIdleEvent ms // no idle notification happens. static const size_t kTimeUntilNextIdleEvent = 100; diff --git a/src/heap/heap.cc b/src/heap/heap.cc index 81a446b88..82589c7fd 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -1131,8 +1131,7 @@ bool Heap::PerformGarbageCollection( // Temporarily set the limit for case when PostGarbageCollectionProcessing // allocates and triggers GC. The real limit is set at after // PostGarbageCollectionProcessing. - old_generation_allocation_limit_ = - OldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), 0); + SetOldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), 0); old_gen_exhausted_ = false; old_generation_size_configured_ = true; } else { @@ -1166,8 +1165,8 @@ bool Heap::PerformGarbageCollection( // Register the amount of external allocated memory. amount_of_external_allocated_memory_at_last_global_gc_ = amount_of_external_allocated_memory_; - old_generation_allocation_limit_ = OldGenerationAllocationLimit( - PromotedSpaceSizeOfObjects(), freed_global_handles); + SetOldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), + freed_global_handles); // We finished a marking cycle. We can uncommit the marking deque until // we start marking again. mark_compact_collector_.UncommitMarkingDeque(); @@ -4548,7 +4547,7 @@ bool Heap::TryFinalizeIdleIncrementalMarking( bool Heap::WorthActivatingIncrementalMarking() { return incremental_marking()->IsStopped() && - incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull(); + incremental_marking()->ShouldActivate(); } @@ -4573,6 +4572,7 @@ bool Heap::IdleNotification(double deadline_in_seconds) { static_cast(base::Time::kMillisecondsPerSecond); HistogramTimerScope idle_notification_scope( isolate_->counters()->gc_idle_notification()); + double idle_time_in_ms = deadline_in_ms - MonotonicallyIncreasingTimeInMs(); GCIdleTimeHandler::HeapState heap_state; heap_state.contexts_disposed = contexts_disposed_; @@ -4581,8 +4581,15 @@ bool Heap::IdleNotification(double deadline_in_seconds) { heap_state.size_of_objects = static_cast(SizeOfObjects()); heap_state.incremental_marking_stopped = incremental_marking()->IsStopped(); // TODO(ulan): Start incremental marking only for large heaps. + intptr_t limit = old_generation_allocation_limit_; + if (static_cast(idle_time_in_ms) > + GCIdleTimeHandler::kMaxFrameRenderingIdleTime) { + limit = idle_old_generation_allocation_limit_; + } + heap_state.can_start_incremental_marking = - incremental_marking()->ShouldActivate() && FLAG_incremental_marking && + incremental_marking()->WorthActivating() && + NextGCIsLikelyToBeFull(limit) && FLAG_incremental_marking && !mark_compact_collector()->sweeping_in_progress(); heap_state.sweeping_in_progress = mark_compact_collector()->sweeping_in_progress(); @@ -4603,7 +4610,6 @@ bool Heap::IdleNotification(double deadline_in_seconds) { static_cast( tracer()->NewSpaceAllocationThroughputInBytesPerMillisecond()); - double idle_time_in_ms = deadline_in_ms - MonotonicallyIncreasingTimeInMs(); GCIdleTimeAction action = gc_idle_time_handler_.Compute(idle_time_in_ms, heap_state); isolate()->counters()->gc_idle_time_allotted_in_ms()->AddSample( @@ -5192,21 +5198,37 @@ int64_t Heap::PromotedExternalMemorySize() { } -intptr_t Heap::OldGenerationAllocationLimit(intptr_t old_gen_size, - int freed_global_handles) { +intptr_t Heap::CalculateOldGenerationAllocationLimit(double factor, + intptr_t old_gen_size) { + CHECK(factor > 1.0); + CHECK(old_gen_size > 0); + intptr_t limit = static_cast(old_gen_size * factor); + limit = Max(limit, kMinimumOldGenerationAllocationLimit); + limit += new_space_.Capacity(); + intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; + return Min(limit, halfway_to_the_max); +} + + +void Heap::SetOldGenerationAllocationLimit(intptr_t old_gen_size, + int freed_global_handles) { const int kMaxHandles = 1000; const int kMinHandles = 100; - double min_factor = 1.1; + const double min_factor = 1.1; double max_factor = 4; + const double idle_max_factor = 1.5; // We set the old generation growing factor to 2 to grow the heap slower on // memory-constrained devices. if (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) { max_factor = 2; } + // If there are many freed global handles, then the next full GC will // likely collect a lot of garbage. Choose the heap growing factor // depending on freed global handles. // TODO(ulan, hpayer): Take into account mutator utilization. + // TODO(hpayer): The idle factor could make the handles heuristic obsolete. + // Look into that. double factor; if (freed_global_handles <= kMinHandles) { factor = max_factor; @@ -5225,11 +5247,10 @@ intptr_t Heap::OldGenerationAllocationLimit(intptr_t old_gen_size, factor = min_factor; } - intptr_t limit = static_cast(old_gen_size * factor); - limit = Max(limit, kMinimumOldGenerationAllocationLimit); - limit += new_space_.Capacity(); - intptr_t halfway_to_the_max = (old_gen_size + max_old_generation_size_) / 2; - return Min(limit, halfway_to_the_max); + old_generation_allocation_limit_ = + CalculateOldGenerationAllocationLimit(factor, old_gen_size); + idle_old_generation_allocation_limit_ = CalculateOldGenerationAllocationLimit( + Min(factor, idle_max_factor), old_gen_size); } diff --git a/src/heap/heap.h b/src/heap/heap.h index aa18fba17..5dfae06c3 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -634,6 +634,10 @@ class Heap { // Returns of size of all objects residing in the heap. intptr_t SizeOfObjects(); + intptr_t old_generation_allocation_limit() const { + return old_generation_allocation_limit_; + } + // Return the starting address and a mask for the new space. And-masking an // address with the mask will result in the start address of the new space // for all addresses in either semispace. @@ -1120,8 +1124,14 @@ class Heap { static const int kMaxExecutableSizeHugeMemoryDevice = 256 * kPointerMultiplier; - intptr_t OldGenerationAllocationLimit(intptr_t old_gen_size, - int freed_global_handles); + // Calculates the allocation limit based on a given growing factor and a + // given old generation size. + intptr_t CalculateOldGenerationAllocationLimit(double factor, + intptr_t old_gen_size); + + // Sets the allocation limit to trigger the next full garbage collection. + void SetOldGenerationAllocationLimit(intptr_t old_gen_size, + int freed_global_handles); // Indicates whether inline bump-pointer allocation has been disabled. bool inline_allocation_disabled() { return inline_allocation_disabled_; } @@ -1231,13 +1241,12 @@ class Heap { survived_since_last_expansion_ += survived; } - inline bool NextGCIsLikelyToBeFull() { + inline bool NextGCIsLikelyToBeFull(intptr_t limit) { if (FLAG_gc_global) return true; if (FLAG_stress_compaction && (gc_count_ & 1) != 0) return true; - intptr_t adjusted_allocation_limit = - old_generation_allocation_limit_ - new_space_.Capacity(); + intptr_t adjusted_allocation_limit = limit - new_space_.Capacity(); if (PromotedTotalSize() >= adjusted_allocation_limit) return true; @@ -1640,6 +1649,10 @@ class Heap { // generation and on every allocation in large object space. intptr_t old_generation_allocation_limit_; + // The allocation limit when there is >16.66ms idle time in the idle time + // handler. + intptr_t idle_old_generation_allocation_limit_; + // Indicates that an allocation has failed in the old generation since the // last GC. bool old_gen_exhausted_; diff --git a/src/heap/incremental-marking.cc b/src/heap/incremental-marking.cc index b61f633a4..ef2e11378 100644 --- a/src/heap/incremental-marking.cc +++ b/src/heap/incremental-marking.cc @@ -387,7 +387,9 @@ void IncrementalMarking::ActivateIncrementalWriteBarrier() { bool IncrementalMarking::ShouldActivate() { - return WorthActivating() && heap_->NextGCIsLikelyToBeFull(); + return WorthActivating() && + heap_->NextGCIsLikelyToBeFull( + heap_->old_generation_allocation_limit()); } -- 2.34.1