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}
This commit is contained in:
hpayer 2015-04-16 09:31:41 -07:00 committed by Commit bot
parent 8924a9e1b7
commit c96a2d3a74
4 changed files with 61 additions and 22 deletions

View File

@ -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;

View File

@ -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<double>(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<size_t>(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<size_t>(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<size_t>(
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<intptr_t>(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<intptr_t>(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);
}

View File

@ -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_;

View File

@ -387,7 +387,9 @@ void IncrementalMarking::ActivateIncrementalWriteBarrier() {
bool IncrementalMarking::ShouldActivate() {
return WorthActivating() && heap_->NextGCIsLikelyToBeFull();
return WorthActivating() &&
heap_->NextGCIsLikelyToBeFull(
heap_->old_generation_allocation_limit());
}