Commit 781fa664 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[heap] Refactor MemoryController and HeapController

- Move generic pieces into MemoryController.
- Keep V8's specific factor computations in HeapController.

Bug: chromium:948807
Change-Id: I1c1fc0516a429b19ce6458f75888b3f9d51824ac
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1617678
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61626}
parent 38f45818
...@@ -49,7 +49,7 @@ namespace internal { ...@@ -49,7 +49,7 @@ namespace internal {
// F * (1 - MU / (R * (1 - MU))) = 1 // F * (1 - MU / (R * (1 - MU))) = 1
// F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1 // F * (R * (1 - MU) - MU) / (R * (1 - MU)) = 1
// F = R * (1 - MU) / (R * (1 - MU) - MU) // F = R * (1 - MU) / (R * (1 - MU) - MU)
double MemoryController::GrowingFactor(double gc_speed, double mutator_speed, double HeapController::GrowingFactor(double gc_speed, double mutator_speed,
double max_factor) { double max_factor) {
DCHECK_LE(min_growing_factor_, max_factor); DCHECK_LE(min_growing_factor_, max_factor);
DCHECK_GE(max_growing_factor_, max_factor); DCHECK_GE(max_growing_factor_, max_factor);
...@@ -57,9 +57,9 @@ double MemoryController::GrowingFactor(double gc_speed, double mutator_speed, ...@@ -57,9 +57,9 @@ double MemoryController::GrowingFactor(double gc_speed, double mutator_speed,
const double speed_ratio = gc_speed / mutator_speed; const double speed_ratio = gc_speed / mutator_speed;
const double a = speed_ratio * (1 - target_mutator_utilization_); const double a = speed_ratio * (1 - kTargetMutatorUtilization);
const double b = speed_ratio * (1 - target_mutator_utilization_) - const double b =
target_mutator_utilization_; speed_ratio * (1 - kTargetMutatorUtilization) - kTargetMutatorUtilization;
// The factor is a / b, but we need to check for small b first. // The factor is a / b, but we need to check for small b first.
double factor = (a < b * max_factor) ? a / b : max_factor; double factor = (a < b * max_factor) ? a / b : max_factor;
...@@ -68,27 +68,19 @@ double MemoryController::GrowingFactor(double gc_speed, double mutator_speed, ...@@ -68,27 +68,19 @@ double MemoryController::GrowingFactor(double gc_speed, double mutator_speed,
return factor; return factor;
} }
size_t MemoryController::CalculateAllocationLimit( size_t MemoryController::CalculateAllocationLimitBase(
size_t curr_size, size_t max_size, double max_factor, double gc_speed, size_t curr_size, size_t max_size, double factor, size_t additional_bytes,
double mutator_speed, size_t new_space_capacity,
Heap::HeapGrowingMode growing_mode) { Heap::HeapGrowingMode growing_mode) {
double factor = GrowingFactor(gc_speed, mutator_speed, max_factor); switch (growing_mode) {
case Heap::HeapGrowingMode::kConservative:
if (FLAG_trace_gc_verbose) { case Heap::HeapGrowingMode::kSlow:
Isolate::FromHeap(heap_)->PrintWithTimestamp(
"%s factor %.1f based on mu=%.3f, speed_ratio=%.f "
"(gc=%.f, mutator=%.f)\n",
ControllerName(), factor, target_mutator_utilization_,
gc_speed / mutator_speed, gc_speed, mutator_speed);
}
if (growing_mode == Heap::HeapGrowingMode::kConservative ||
growing_mode == Heap::HeapGrowingMode::kSlow) {
factor = Min(factor, conservative_growing_factor_); factor = Min(factor, conservative_growing_factor_);
} break;
case Heap::HeapGrowingMode::kMinimal:
if (growing_mode == Heap::HeapGrowingMode::kMinimal) {
factor = min_growing_factor_; factor = min_growing_factor_;
break;
case Heap::HeapGrowingMode::kDefault:
break;
} }
if (FLAG_heap_growing_percent > 0) { if (FLAG_heap_growing_percent > 0) {
...@@ -97,20 +89,19 @@ size_t MemoryController::CalculateAllocationLimit( ...@@ -97,20 +89,19 @@ size_t MemoryController::CalculateAllocationLimit(
CHECK_LT(1.0, factor); CHECK_LT(1.0, factor);
CHECK_LT(0, curr_size); CHECK_LT(0, curr_size);
uint64_t limit = static_cast<uint64_t>(curr_size * factor); const uint64_t limit =
limit = Max(limit, static_cast<uint64_t>(curr_size) + Max(static_cast<uint64_t>(curr_size * factor),
MinimumAllocationLimitGrowingStep(growing_mode)); static_cast<uint64_t>(curr_size) +
limit += new_space_capacity; MinimumAllocationLimitGrowingStep(growing_mode)) +
uint64_t halfway_to_the_max = additional_bytes;
const uint64_t halfway_to_the_max =
(static_cast<uint64_t>(curr_size) + max_size) / 2; (static_cast<uint64_t>(curr_size) + max_size) / 2;
size_t result = static_cast<size_t>(Min(limit, halfway_to_the_max)); const size_t result = static_cast<size_t>(Min(limit, halfway_to_the_max));
if (FLAG_trace_gc_verbose) { if (FLAG_trace_gc_verbose) {
Isolate::FromHeap(heap_)->PrintWithTimestamp( Isolate::FromHeap(heap_)->PrintWithTimestamp(
"%s Limit: old size: %zu KB, new limit: %zu KB (%.1f)\n", "[%s] Limit: old size: %zu KB, new limit: %zu KB (%.1f)\n",
ControllerName(), curr_size / KB, result / KB, factor); ControllerName(), curr_size / KB, result / KB, factor);
} }
return result; return result;
} }
...@@ -125,9 +116,9 @@ size_t MemoryController::MinimumAllocationLimitGrowingStep( ...@@ -125,9 +116,9 @@ size_t MemoryController::MinimumAllocationLimitGrowingStep(
} }
double HeapController::MaxGrowingFactor(size_t curr_max_size) { double HeapController::MaxGrowingFactor(size_t curr_max_size) {
const double min_small_factor = 1.3; constexpr double kMinSmallFactor = 1.3;
const double max_small_factor = 2.0; constexpr double kMaxSmallFactor = 2.0;
const double high_factor = 4.0; constexpr double kHighFactor = 4.0;
size_t max_size_in_mb = curr_max_size / MB; size_t max_size_in_mb = curr_max_size / MB;
max_size_in_mb = Max(max_size_in_mb, kMinSize); max_size_in_mb = Max(max_size_in_mb, kMinSize);
...@@ -135,7 +126,7 @@ double HeapController::MaxGrowingFactor(size_t curr_max_size) { ...@@ -135,7 +126,7 @@ double HeapController::MaxGrowingFactor(size_t curr_max_size) {
// If we are on a device with lots of memory, we allow a high heap // If we are on a device with lots of memory, we allow a high heap
// growing factor. // growing factor.
if (max_size_in_mb >= kMaxSize) { if (max_size_in_mb >= kMaxSize) {
return high_factor; return kHighFactor;
} }
DCHECK_GE(max_size_in_mb, kMinSize); DCHECK_GE(max_size_in_mb, kMinSize);
...@@ -143,11 +134,29 @@ double HeapController::MaxGrowingFactor(size_t curr_max_size) { ...@@ -143,11 +134,29 @@ double HeapController::MaxGrowingFactor(size_t curr_max_size) {
// On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C // On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C
double factor = (max_size_in_mb - kMinSize) * double factor = (max_size_in_mb - kMinSize) *
(max_small_factor - min_small_factor) / (kMaxSmallFactor - kMinSmallFactor) /
(kMaxSize - kMinSize) + (kMaxSize - kMinSize) +
min_small_factor; kMinSmallFactor;
return factor; return factor;
} }
size_t HeapController::CalculateAllocationLimit(
size_t curr_size, size_t max_size, double gc_speed, double mutator_speed,
size_t new_space_capacity, Heap::HeapGrowingMode growing_mode) {
const double max_factor = MaxGrowingFactor(max_size);
const double factor = GrowingFactor(gc_speed, mutator_speed, max_factor);
if (FLAG_trace_gc_verbose) {
Isolate::FromHeap(heap_)->PrintWithTimestamp(
"[%s] factor %.1f based on mu=%.3f, speed_ratio=%.f "
"(gc=%.f, mutator=%.f)\n",
ControllerName(), factor, kTargetMutatorUtilization,
gc_speed / mutator_speed, gc_speed, mutator_speed);
}
return CalculateAllocationLimitBase(curr_size, max_size, factor,
new_space_capacity, growing_mode);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -15,42 +15,31 @@ namespace internal { ...@@ -15,42 +15,31 @@ namespace internal {
class V8_EXPORT_PRIVATE MemoryController { class V8_EXPORT_PRIVATE MemoryController {
public: public:
virtual ~MemoryController() = default;
// Computes the growing step when the limit increases.
size_t MinimumAllocationLimitGrowingStep(Heap::HeapGrowingMode growing_mode);
protected:
MemoryController(Heap* heap, double min_growing_factor, MemoryController(Heap* heap, double min_growing_factor,
double max_growing_factor, double max_growing_factor,
double conservative_growing_factor, double conservative_growing_factor)
double target_mutator_utilization)
: heap_(heap), : heap_(heap),
min_growing_factor_(min_growing_factor), min_growing_factor_(min_growing_factor),
max_growing_factor_(max_growing_factor), max_growing_factor_(max_growing_factor),
conservative_growing_factor_(conservative_growing_factor), conservative_growing_factor_(conservative_growing_factor) {}
target_mutator_utilization_(target_mutator_utilization) {}
virtual ~MemoryController() = default;
// Computes the allocation limit to trigger the next garbage collection. // Computes the allocation limit to trigger the next garbage collection.
size_t CalculateAllocationLimit(size_t curr_size, size_t max_size, size_t CalculateAllocationLimitBase(size_t curr_size, size_t max_size,
double max_factor, double gc_speed, double factor, size_t additional_bytes,
double mutator_speed,
size_t new_space_capacity,
Heap::HeapGrowingMode growing_mode); Heap::HeapGrowingMode growing_mode);
// Computes the growing step when the limit increases.
size_t MinimumAllocationLimitGrowingStep(Heap::HeapGrowingMode growing_mode);
protected:
double GrowingFactor(double gc_speed, double mutator_speed,
double max_factor);
virtual const char* ControllerName() = 0; virtual const char* ControllerName() = 0;
Heap* const heap_; Heap* const heap_;
const double min_growing_factor_; const double min_growing_factor_;
const double max_growing_factor_; const double max_growing_factor_;
const double conservative_growing_factor_; const double conservative_growing_factor_;
const double target_mutator_utilization_;
FRIEND_TEST(HeapControllerTest, HeapGrowingFactor);
FRIEND_TEST(HeapControllerTest, MaxHeapGrowingFactor);
FRIEND_TEST(HeapControllerTest, MaxOldGenerationSize);
FRIEND_TEST(HeapControllerTest, OldGenerationAllocationLimit);
}; };
class V8_EXPORT_PRIVATE HeapController : public MemoryController { class V8_EXPORT_PRIVATE HeapController : public MemoryController {
...@@ -58,13 +47,27 @@ class V8_EXPORT_PRIVATE HeapController : public MemoryController { ...@@ -58,13 +47,27 @@ class V8_EXPORT_PRIVATE HeapController : public MemoryController {
// Sizes are in MB. // Sizes are in MB.
static constexpr size_t kMinSize = 128 * Heap::kPointerMultiplier; static constexpr size_t kMinSize = 128 * Heap::kPointerMultiplier;
static constexpr size_t kMaxSize = 1024 * Heap::kPointerMultiplier; static constexpr size_t kMaxSize = 1024 * Heap::kPointerMultiplier;
static constexpr double kTargetMutatorUtilization = 0.97;
explicit HeapController(Heap* heap) explicit HeapController(Heap* heap) : MemoryController(heap, 1.1, 4.0, 1.3) {}
: MemoryController(heap, 1.1, 4.0, 1.3, 0.97) {}
double MaxGrowingFactor(size_t curr_max_size); size_t CalculateAllocationLimit(size_t curr_size, size_t max_size,
double gc_speed, double mutator_speed,
size_t new_space_capacity,
Heap::HeapGrowingMode growing_mode);
protected: protected:
double GrowingFactor(double gc_speed, double mutator_speed,
double max_factor);
double MaxGrowingFactor(size_t curr_max_size);
const char* ControllerName() override { return "HeapController"; } const char* ControllerName() override { return "HeapController"; }
FRIEND_TEST(HeapControllerTest, HeapGrowingFactor);
FRIEND_TEST(HeapControllerTest, MaxHeapGrowingFactor);
FRIEND_TEST(HeapControllerTest, MaxOldGenerationSize);
FRIEND_TEST(HeapControllerTest, OldGenerationAllocationLimit);
}; };
} // namespace internal } // namespace internal
......
...@@ -1880,22 +1880,18 @@ bool Heap::PerformGarbageCollection( ...@@ -1880,22 +1880,18 @@ bool Heap::PerformGarbageCollection(
isolate()->isolate_data()->external_memory_ + isolate()->isolate_data()->external_memory_ +
kExternalAllocationSoftLimit; kExternalAllocationSoftLimit;
double max_factor = old_generation_allocation_limit_ =
heap_controller()->MaxGrowingFactor(max_old_generation_size_); heap_controller()->CalculateAllocationLimit(
size_t new_limit = heap_controller()->CalculateAllocationLimit( old_gen_size, max_old_generation_size_, gc_speed, mutator_speed,
old_gen_size, max_old_generation_size_, max_factor, gc_speed, new_space()->Capacity(), CurrentHeapGrowingMode());
mutator_speed, new_space()->Capacity(), CurrentHeapGrowingMode());
old_generation_allocation_limit_ = new_limit;
CheckIneffectiveMarkCompact( CheckIneffectiveMarkCompact(
old_gen_size, tracer()->AverageMarkCompactMutatorUtilization()); old_gen_size, tracer()->AverageMarkCompactMutatorUtilization());
} else if (HasLowYoungGenerationAllocationRate() && } else if (HasLowYoungGenerationAllocationRate() &&
old_generation_size_configured_) { old_generation_size_configured_) {
double max_factor =
heap_controller()->MaxGrowingFactor(max_old_generation_size_);
size_t new_limit = heap_controller()->CalculateAllocationLimit( size_t new_limit = heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size_, max_factor, gc_speed, old_gen_size, max_old_generation_size_, gc_speed, mutator_speed,
mutator_speed, new_space()->Capacity(), CurrentHeapGrowingMode()); new_space()->Capacity(), CurrentHeapGrowingMode());
if (new_limit < old_generation_allocation_limit_) { if (new_limit < old_generation_allocation_limit_) {
old_generation_allocation_limit_ = new_limit; old_generation_allocation_limit_ = new_limit;
} }
......
...@@ -2061,6 +2061,7 @@ class Heap { ...@@ -2061,6 +2061,7 @@ class Heap {
friend class ConcurrentMarking; friend class ConcurrentMarking;
friend class GCCallbacksScope; friend class GCCallbacksScope;
friend class GCTracer; friend class GCTracer;
friend class HeapController;
friend class MemoryController; friend class MemoryController;
friend class HeapIterator; friend class HeapIterator;
friend class IdleScavengeObserver; friend class IdleScavengeObserver;
......
...@@ -75,32 +75,28 @@ TEST_F(HeapControllerTest, OldGenerationAllocationLimit) { ...@@ -75,32 +75,28 @@ TEST_F(HeapControllerTest, OldGenerationAllocationLimit) {
double factor = double factor =
heap_controller.GrowingFactor(gc_speed, mutator_speed, max_factor); heap_controller.GrowingFactor(gc_speed, mutator_speed, max_factor);
EXPECT_EQ( EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit( heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed, old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
mutator_speed, new_space_capacity, Heap::HeapGrowingMode::kDefault)); new_space_capacity, Heap::HeapGrowingMode::kDefault));
factor = Min(factor, heap_controller.conservative_growing_factor_); factor = Min(factor, heap_controller.conservative_growing_factor_);
EXPECT_EQ( EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit( heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed, old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
mutator_speed, new_space_capacity, Heap::HeapGrowingMode::kSlow)); new_space_capacity, Heap::HeapGrowingMode::kSlow));
factor = Min(factor, heap_controller.conservative_growing_factor_); factor = Min(factor, heap_controller.conservative_growing_factor_);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity), EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit( heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed, old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
mutator_speed, new_space_capacity, new_space_capacity, Heap::HeapGrowingMode::kConservative));
Heap::HeapGrowingMode::kConservative));
factor = heap_controller.min_growing_factor_; factor = heap_controller.min_growing_factor_;
EXPECT_EQ( EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit( heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed, old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
mutator_speed, new_space_capacity, Heap::HeapGrowingMode::kMinimal)); new_space_capacity, Heap::HeapGrowingMode::kMinimal));
} }
TEST_F(HeapControllerTest, MaxOldGenerationSize) { TEST_F(HeapControllerTest, MaxOldGenerationSize) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment