| Index: runtime/vm/pages.cc
|
| diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
|
| index 80527f2f4bf0bb8baa8e56c6b574090a84ee8316..80c5c507ae643140e1ac5d67492a2db054dc6693 100644
|
| --- a/runtime/vm/pages.cc
|
| +++ b/runtime/vm/pages.cc
|
| @@ -1153,16 +1153,19 @@ void PageSpaceController::EvaluateGarbageCollection(
|
| SpaceUsage before, SpaceUsage after, int64_t start, int64_t end) {
|
| ASSERT(end >= start);
|
| history_.AddGarbageCollectionTime(start, end);
|
| - int gc_time_fraction = history_.GarbageCollectionTimeFraction();
|
| + const int gc_time_fraction = history_.GarbageCollectionTimeFraction();
|
| heap_->RecordData(PageSpace::kGCTimeFraction, gc_time_fraction);
|
|
|
| // Assume garbage increases linearly with allocation:
|
| // G = kA, and estimate k from the previous cycle.
|
| - intptr_t allocated_since_previous_gc =
|
| + const intptr_t allocated_since_previous_gc =
|
| before.used_in_words - last_usage_.used_in_words;
|
| - intptr_t garbage = before.used_in_words - after.used_in_words;
|
| - double k = garbage / static_cast<double>(allocated_since_previous_gc);
|
| - heap_->RecordData(PageSpace::kGarbageRatio, static_cast<int>(k * 100));
|
| + ASSERT(allocated_since_previous_gc > 0);
|
| + const intptr_t garbage = before.used_in_words - after.used_in_words;
|
| + ASSERT(garbage >= 0);
|
| + const double k = garbage / static_cast<double>(allocated_since_previous_gc);
|
| + const int garbage_ratio = static_cast<int>(k * 100);
|
| + heap_->RecordData(PageSpace::kGarbageRatio, garbage_ratio);
|
|
|
| // Define GC to be 'worthwhile' iff at least fraction t of heap is garbage.
|
| double t = 1.0 - desired_utilization_;
|
| @@ -1171,21 +1174,48 @@ void PageSpaceController::EvaluateGarbageCollection(
|
| t += (gc_time_fraction - garbage_collection_time_ratio_) / 100.0;
|
| }
|
|
|
| - // Find minimum 'grow_heap_' such that after increasing capacity by
|
| - // 'grow_heap_' pages and filling them, we expect a GC to be worthwhile.
|
| - for (grow_heap_ = 0; grow_heap_ < heap_growth_max_; ++grow_heap_) {
|
| - intptr_t limit =
|
| - after.capacity_in_words + (grow_heap_ * PageSpace::kPageSizeInWords);
|
| - intptr_t allocated_before_next_gc = limit - after.used_in_words;
|
| - double estimated_garbage = k * allocated_before_next_gc;
|
| - if (t <= estimated_garbage / limit) {
|
| - break;
|
| + const intptr_t grow_ratio = (
|
| + static_cast<intptr_t>(after.capacity_in_words / desired_utilization_) -
|
| + after.capacity_in_words) / PageSpace::kPageSizeInWords;
|
| + if (garbage_ratio == 0) {
|
| + // No garbage in the previous cycle so it would be hard to compute a
|
| + // grow_heap_ size based on estimated garbage so we use growth ratio
|
| + // heuristics instead.
|
| + grow_heap_ = Utils::Maximum(static_cast<intptr_t>(heap_growth_max_),
|
| + grow_ratio);
|
| + } else {
|
| + // Find minimum 'grow_heap_' such that after increasing capacity by
|
| + // 'grow_heap_' pages and filling them, we expect a GC to be worthwhile.
|
| + intptr_t max = heap_growth_max_;
|
| + intptr_t min = 0;
|
| + intptr_t adjustment = 0;
|
| + intptr_t local_grow_heap = 0;
|
| + while (min < max) {
|
| + local_grow_heap = (max + min) / 2;
|
| + const intptr_t limit =
|
| + after.capacity_in_words + (grow_heap_ * PageSpace::kPageSizeInWords);
|
| + const intptr_t allocated_before_next_gc = limit - after.used_in_words;
|
| + const double estimated_garbage = k * allocated_before_next_gc;
|
| + if (t <= estimated_garbage / limit) {
|
| + max = local_grow_heap - 1;
|
| + adjustment = -1;
|
| + } else {
|
| + min = local_grow_heap + 1;
|
| + adjustment = 1;
|
| + }
|
| + }
|
| + grow_heap_ = local_grow_heap + adjustment;
|
| + ASSERT(grow_heap_ >= 0);
|
| + // If we are going to grow by heap_grow_max_ then ensure that we
|
| + // will be growing the heap at least by the growth ratio heuristics.
|
| + if ((grow_heap_ == heap_growth_max_) && (grow_ratio > grow_heap_)) {
|
| + grow_heap_ = grow_ratio;
|
| }
|
| }
|
| heap_->RecordData(PageSpace::kPageGrowth, grow_heap_);
|
|
|
| // Limit shrinkage: allow growth by at least half the pages freed by GC.
|
| - intptr_t freed_pages =
|
| + const intptr_t freed_pages =
|
| (before.capacity_in_words - after.capacity_in_words) /
|
| PageSpace::kPageSizeInWords;
|
| grow_heap_ = Utils::Maximum(grow_heap_, freed_pages / 2);
|
|
|