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:
parent
8924a9e1b7
commit
c96a2d3a74
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -387,7 +387,9 @@ void IncrementalMarking::ActivateIncrementalWriteBarrier() {
|
||||
|
||||
|
||||
bool IncrementalMarking::ShouldActivate() {
|
||||
return WorthActivating() && heap_->NextGCIsLikelyToBeFull();
|
||||
return WorthActivating() &&
|
||||
heap_->NextGCIsLikelyToBeFull(
|
||||
heap_->old_generation_allocation_limit());
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user