Chromium Code Reviews| Index: src/heap/heap.cc |
| diff --git a/src/heap/heap.cc b/src/heap/heap.cc |
| index 76209c42b5ec1cd198118589b78909cf3329478a..85a5e3023f4571956539c5869c0f3531ba976689 100644 |
| --- a/src/heap/heap.cc |
| +++ b/src/heap/heap.cc |
| @@ -1218,6 +1218,12 @@ bool Heap::PerformGarbageCollection( |
| // Perform mark-sweep with optional compaction. |
| MarkCompact(); |
| sweep_generation_++; |
| + // Temporarily set the limit for case when PostGarbageCollectionProcessing |
| + // allocates and triggers GC. The real limit is set at after |
| + // PostGarbageCollectionProcessing. |
| + const double kConservativeFactor = 1.5; |
| + SetOldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), |
| + kConservativeFactor); |
| old_gen_exhausted_ = false; |
| old_generation_size_configured_ = true; |
| } else { |
| @@ -1251,13 +1257,24 @@ bool Heap::PerformGarbageCollection( |
| // Update relocatables. |
| Relocatable::PostGarbageCollectionProcessing(isolate_); |
| + size_t total_committed = 0; |
| + int fragmentation_percent = |
| + FragmentationOfCompactedSpacesInPercent(&total_committed); |
|
Hannes Payer (out of office)
2015/06/03 06:32:57
Can we have a separate function which returns tota
|
| + // Ignore fragmentation of non-compactable heaps and small heaps. |
| + const size_t kSmallHeapThreshold = 8 * Page::kPageSize; |
| + if (FLAG_never_compact || total_committed <= kSmallHeapThreshold) { |
| + fragmentation_percent = 0; |
| + } |
| + |
| if (collector == MARK_COMPACTOR) { |
| // Register the amount of external allocated memory. |
| amount_of_external_allocated_memory_at_last_global_gc_ = |
| amount_of_external_allocated_memory_; |
| - SetOldGenerationAllocationLimit( |
| - PromotedSpaceSizeOfObjects(), |
| - tracer()->CurrentAllocationThroughputInBytesPerMillisecond()); |
| + double factor = HeapGrowingFactor( |
| + freed_global_handles, |
| + tracer()->CurrentAllocationThroughputInBytesPerMillisecond(), |
| + fragmentation_percent); |
| + SetOldGenerationAllocationLimit(PromotedSpaceSizeOfObjects(), factor); |
| // We finished a marking cycle. We can uncommit the marking deque until |
| // we start marking again. |
| mark_compact_collector_.UncommitMarkingDeque(); |
| @@ -1280,7 +1297,7 @@ bool Heap::PerformGarbageCollection( |
| } |
| #endif |
| - return freed_global_handles > 0; |
| + return NextGCLikelyToFreeMore(freed_global_handles, fragmentation_percent); |
| } |
| @@ -5390,52 +5407,84 @@ intptr_t Heap::CalculateOldGenerationAllocationLimit(double factor, |
| } |
| -void Heap::SetOldGenerationAllocationLimit( |
| - intptr_t old_gen_size, size_t current_allocation_throughput) { |
| -// Allocation throughput on Android devices is typically lower than on |
| -// non-mobile devices. |
| -#if V8_OS_ANDROID |
| - const size_t kHighThroughput = 2500; |
| - const size_t kLowThroughput = 250; |
| -#else |
| - const size_t kHighThroughput = 10000; |
| - const size_t kLowThroughput = 1000; |
| -#endif |
| - const double min_scaling_factor = 1.1; |
| - const double max_scaling_factor = 1.5; |
| - 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; |
| - } |
| - |
| - double factor; |
| - double idle_factor; |
| - if (current_allocation_throughput == 0 || |
| - current_allocation_throughput >= kHighThroughput) { |
| - factor = max_factor; |
| - } else if (current_allocation_throughput <= kLowThroughput) { |
| - factor = min_scaling_factor; |
| - } else { |
| - // Compute factor using linear interpolation between points |
| - // (kHighThroughput, max_scaling_factor) and (kLowThroughput, min_factor). |
| - factor = min_scaling_factor + |
| - (current_allocation_throughput - kLowThroughput) * |
| - (max_scaling_factor - min_scaling_factor) / |
| - (kHighThroughput - kLowThroughput); |
| +double LinearInterpolation(double x1, double y1, double x2, double y2, |
| + double x) { |
| + DCHECK(x1 < x2); |
| + if (x <= x1) return y1; |
| + if (x >= x2) return y2; |
| + return y1 + (y2 - y1) / (x2 - x1) * (x - x1); |
| +} |
| + |
| + |
| +double Heap::HeapGrowingFactor(int freed_handles, size_t allocation_throughput, |
| + int fragmentation_percent) { |
| + const int kLowHandles = 100; |
| + const int kHighHandles = 1000; |
| + |
| + const size_t kPointerMultiplier = i::kPointerSize / 4; |
| + // We use kHighThroughputFactor if allocation_throughput >= kHighThroughput. |
| + // Otherwise, we linearly interpolate between (kLowThroughput, kMinFactor) |
| + // and (kMediumThroughput, kMaxFactor). |
| + const size_t kHighThroughput = 10000 * kPointerMultiplier; |
| + const size_t kMediumThroughput = 5000 * kPointerMultiplier; |
| + const size_t kLowThroughput = 500 * kPointerMultiplier; |
| + |
| + const double kHighThroughputFactor = 4.0; |
| + const double kHighThroughputFactorForMemoryConstrained = 2.0; |
| + const double kMaxFactor = 2.0; |
| + const double kMinFactor = 1.1; |
| + |
| + if (allocation_throughput == 0) { |
| + // If we have no allocation throughput estimate, we conservatively assume |
| + // that it is medium. |
| + allocation_throughput = kMediumThroughput; |
| + } |
| + double factor1 = LinearInterpolation(kLowHandles, kMaxFactor, kHighHandles, |
| + kMinFactor, freed_handles); |
| + double factor2 = |
| + LinearInterpolation(kLowThroughput, kMinFactor, kMediumThroughput, |
| + kMaxFactor, allocation_throughput); |
| + double factor3 = LinearInterpolation(kLowFragmentationPercent, kMaxFactor, |
| + kHighFragmentationPercent, kMinFactor, |
| + fragmentation_percent); |
| + |
|
Hannes Payer (out of office)
2015/06/03 06:32:57
This function needs more comments about the magic
|
| + double factor = (factor1 + factor2 + factor3) / 3; |
| + if (allocation_throughput >= kHighThroughput && freed_handles < kLowHandles) { |
| + // We need high throughput, schedule GC late. |
| + // We set the old generation growing factor to 2 to grow the heap slower on |
| + // memory-constrained devices. |
| + if (max_old_generation_size_ <= kMaxOldSpaceSizeMediumMemoryDevice) { |
| + factor = kHighThroughputFactorForMemoryConstrained; |
| + } else { |
| + factor = kHighThroughputFactor; |
| + } |
| } |
| if (FLAG_stress_compaction || |
| mark_compact_collector()->reduce_memory_footprint_) { |
| - factor = min_scaling_factor; |
| + factor = kMinFactor; |
| } |
| + if (FLAG_trace_gc_verbose) { |
| + PrintIsolate(isolate_, |
| + "Freed handles: %d (factor %.1f)," |
| + "allocation throughput: %u (factor %.1f)," |
| + "fragmentation: %d (factor %.1f), combined factor: %.1f\n", |
| + freed_handles, factor1, allocation_throughput, factor2, |
| + fragmentation_percent, factor3, factor); |
| + } |
| + return factor; |
| +} |
| + |
| + |
| +void Heap::SetOldGenerationAllocationLimit(intptr_t old_gen_size, |
| + double factor) { |
| + const double idle_max_factor = 1.5; |
| + |
| // TODO(hpayer): Investigate if idle_old_generation_allocation_limit_ is still |
| // needed after taking the allocation rate for the old generation limit into |
| // account. |
| - idle_factor = Min(factor, idle_max_factor); |
| + const double idle_factor = Min(factor, idle_max_factor); |
| old_generation_allocation_limit_ = |
| CalculateOldGenerationAllocationLimit(factor, old_gen_size); |