Commit 22b2b34c authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[heap] Refactor HeapController

Split off from
  https://chromium-review.googlesource.com/c/v8/v8/+/1196484

Bug: chromium:879045
Change-Id: I58b1a2ad10729f54c9a452dcfecd7511660460f6
Reviewed-on: https://chromium-review.googlesource.com/1216285
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55764}
parent b0edf8e6
......@@ -10,16 +10,16 @@ namespace internal {
// Given GC speed in bytes per ms, the allocation throughput in bytes per ms
// (mutator speed), this function returns the heap growing factor that will
// achieve the kTargetMutatorUtilisation if the GC speed and the mutator speed
// achieve the target_mutator_utilization_ if the GC speed and the mutator speed
// remain the same until the next GC.
//
// For a fixed time-frame T = TM + TG, the mutator utilization is the ratio
// TM / (TM + TG), where TM is the time spent in the mutator and TG is the
// time spent in the garbage collector.
//
// Let MU be kTargetMutatorUtilisation, the desired mutator utilization for the
// time-frame from the end of the current GC to the end of the next GC. Based
// on the MU we can compute the heap growing factor F as
// Let MU be target_mutator_utilization_, the desired mutator utilization for
// the time-frame from the end of the current GC to the end of the next GC.
// Based on the MU we can compute the heap growing factor F as
//
// F = R * (1 - MU) / (R * (1 - MU) - MU), where R = gc_speed / mutator_speed.
//
......@@ -49,69 +49,44 @@ namespace internal {
// F = R * (1 - MU) / (R * (1 - MU) - MU)
double MemoryController::GrowingFactor(double gc_speed, double mutator_speed,
double max_factor) {
DCHECK_LE(kMinGrowingFactor, max_factor);
DCHECK_GE(kMaxGrowingFactor, max_factor);
DCHECK_LE(min_growing_factor_, max_factor);
DCHECK_GE(max_growing_factor_, max_factor);
if (gc_speed == 0 || mutator_speed == 0) return max_factor;
const double speed_ratio = gc_speed / mutator_speed;
const double a = speed_ratio * (1 - kTargetMutatorUtilization);
const double b =
speed_ratio * (1 - kTargetMutatorUtilization) - kTargetMutatorUtilization;
const double a = speed_ratio * (1 - target_mutator_utilization_);
const double b = speed_ratio * (1 - target_mutator_utilization_) -
target_mutator_utilization_;
// The factor is a / b, but we need to check for small b first.
double factor = (a < b * max_factor) ? a / b : max_factor;
factor = Min(factor, max_factor);
factor = Max(factor, kMinGrowingFactor);
return factor;
}
double MemoryController::MaxGrowingFactor(size_t curr_max_size) {
const double min_small_factor = 1.3;
const double max_small_factor = 2.0;
const double high_factor = 4.0;
size_t max_size_in_mb = curr_max_size / MB;
max_size_in_mb = Max(max_size_in_mb, kMinSize);
// If we are on a device with lots of memory, we allow a high heap
// growing factor.
if (max_size_in_mb >= kMaxSize) {
return high_factor;
}
DCHECK_GE(max_size_in_mb, kMinSize);
DCHECK_LT(max_size_in_mb, kMaxSize);
// On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C
double factor = (max_size_in_mb - kMinSize) *
(max_small_factor - min_small_factor) /
(kMaxSize - kMinSize) +
min_small_factor;
factor = Max(factor, min_growing_factor_);
return factor;
}
size_t MemoryController::CalculateAllocationLimit(
size_t curr_size, size_t max_size, double gc_speed, double mutator_speed,
size_t new_space_capacity, Heap::HeapGrowingMode growing_mode) {
double max_factor = MaxGrowingFactor(max_size);
size_t curr_size, size_t max_size, double max_factor, double gc_speed,
double mutator_speed, size_t new_space_capacity,
Heap::HeapGrowingMode growing_mode) {
double factor = GrowingFactor(gc_speed, mutator_speed, max_factor);
if (FLAG_trace_gc_verbose) {
heap_->isolate()->PrintWithTimestamp(
"%s factor %.1f based on mu=%.3f, speed_ratio=%.f "
"(gc=%.f, mutator=%.f)\n",
ControllerName(), factor, kTargetMutatorUtilization,
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, kConservativeGrowingFactor);
factor = Min(factor, conservative_growing_factor_);
}
if (growing_mode == Heap::HeapGrowingMode::kMinimal) {
factor = kMinGrowingFactor;
factor = min_growing_factor_;
}
if (FLAG_heap_growing_percent > 0) {
......@@ -147,5 +122,30 @@ size_t MemoryController::MinimumAllocationLimitGrowingStep(
: kRegularAllocationLimitGrowingStep);
}
double HeapController::MaxGrowingFactor(size_t curr_max_size) {
const double min_small_factor = 1.3;
const double max_small_factor = 2.0;
const double high_factor = 4.0;
size_t max_size_in_mb = curr_max_size / MB;
max_size_in_mb = Max(max_size_in_mb, kMinSize);
// If we are on a device with lots of memory, we allow a high heap
// growing factor.
if (max_size_in_mb >= kMaxSize) {
return high_factor;
}
DCHECK_GE(max_size_in_mb, kMinSize);
DCHECK_LT(max_size_in_mb, kMaxSize);
// On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C
double factor = (max_size_in_mb - kMinSize) *
(max_small_factor - min_small_factor) /
(kMaxSize - kMinSize) +
min_small_factor;
return factor;
}
} // namespace internal
} // namespace v8
......@@ -18,20 +18,18 @@ class V8_EXPORT_PRIVATE MemoryController {
MemoryController(Heap* heap, double min_growing_factor,
double max_growing_factor,
double conservative_growing_factor,
double target_mutator_utilization, size_t min_size,
size_t max_size)
double target_mutator_utilization)
: heap_(heap),
kMinGrowingFactor(min_growing_factor),
kMaxGrowingFactor(max_growing_factor),
kConservativeGrowingFactor(conservative_growing_factor),
kTargetMutatorUtilization(target_mutator_utilization),
kMinSize(min_size),
kMaxSize(max_size) {}
min_growing_factor_(min_growing_factor),
max_growing_factor_(max_growing_factor),
conservative_growing_factor_(conservative_growing_factor),
target_mutator_utilization_(target_mutator_utilization) {}
virtual ~MemoryController() {}
// Computes the allocation limit to trigger the next garbage collection.
size_t CalculateAllocationLimit(size_t curr_size, size_t max_size,
double gc_speed, double mutator_speed,
double max_factor, double gc_speed,
double mutator_speed,
size_t new_space_capacity,
Heap::HeapGrowingMode growing_mode);
......@@ -41,18 +39,13 @@ class V8_EXPORT_PRIVATE MemoryController {
protected:
double GrowingFactor(double gc_speed, double mutator_speed,
double max_factor);
double MaxGrowingFactor(size_t curr_max_size);
virtual const char* ControllerName() = 0;
Heap* const heap_;
const double kMinGrowingFactor;
const double kMaxGrowingFactor;
const double kConservativeGrowingFactor;
const double kTargetMutatorUtilization;
// Sizes are in MB.
const size_t kMinSize;
const size_t kMaxSize;
const double min_growing_factor_;
const double max_growing_factor_;
const double conservative_growing_factor_;
const double target_mutator_utilization_;
FRIEND_TEST(HeapControllerTest, HeapGrowingFactor);
FRIEND_TEST(HeapControllerTest, MaxHeapGrowingFactor);
......@@ -60,15 +53,15 @@ class V8_EXPORT_PRIVATE MemoryController {
FRIEND_TEST(HeapControllerTest, OldGenerationAllocationLimit);
};
class HeapController : public MemoryController {
class V8_EXPORT_PRIVATE HeapController : public MemoryController {
public:
explicit HeapController(Heap* heap)
: MemoryController(heap, 1.1, 4.0, 1.3, 0.97, kMinHeapSize,
kMaxHeapSize) {}
// Sizes are in MB.
static const size_t kMinHeapSize = 128 * Heap::kPointerMultiplier;
static const size_t kMaxHeapSize = 1024 * Heap::kPointerMultiplier;
static constexpr size_t kMinSize = 128 * Heap::kPointerMultiplier;
static constexpr size_t kMaxSize = 1024 * Heap::kPointerMultiplier;
explicit HeapController(Heap* heap)
: MemoryController(heap, 1.1, 4.0, 1.3, 0.97) {}
double MaxGrowingFactor(size_t curr_max_size);
protected:
const char* ControllerName() { return "HeapController"; }
......
......@@ -259,8 +259,8 @@ size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) {
size_t computed_size = static_cast<size_t>(physical_memory / i::MB /
old_space_physical_memory_factor *
kPointerMultiplier);
return Max(Min(computed_size, HeapController::kMaxHeapSize),
HeapController::kMinHeapSize);
return Max(Min(computed_size, HeapController::kMaxSize),
HeapController::kMinSize);
}
size_t Heap::Capacity() {
......@@ -1785,18 +1785,22 @@ bool Heap::PerformGarbageCollection(
external_memory_at_last_mark_compact_ = external_memory_;
external_memory_limit_ = external_memory_ + kExternalAllocationSoftLimit;
double max_factor =
heap_controller()->MaxGrowingFactor(max_old_generation_size_);
size_t new_limit = heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size_, gc_speed, mutator_speed,
new_space()->Capacity(), CurrentHeapGrowingMode());
old_gen_size, max_old_generation_size_, max_factor, gc_speed,
mutator_speed, new_space()->Capacity(), CurrentHeapGrowingMode());
old_generation_allocation_limit_ = new_limit;
CheckIneffectiveMarkCompact(
old_gen_size, tracer()->AverageMarkCompactMutatorUtilization());
} else if (HasLowYoungGenerationAllocationRate() &&
old_generation_size_configured_) {
double max_factor =
heap_controller()->MaxGrowingFactor(max_old_generation_size_);
size_t new_limit = heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size_, gc_speed, mutator_speed,
new_space()->Capacity(), CurrentHeapGrowingMode());
old_gen_size, max_old_generation_size_, max_factor, gc_speed,
mutator_speed, new_space()->Capacity(), CurrentHeapGrowingMode());
if (new_limit < old_generation_allocation_limit_) {
old_generation_allocation_limit_ = new_limit;
}
......
......@@ -34,8 +34,8 @@ void CheckEqualRounded(double expected, double actual) {
TEST_F(HeapControllerTest, HeapGrowingFactor) {
HeapController heap_controller(i_isolate()->heap());
double min_factor = heap_controller.kMinGrowingFactor;
double max_factor = heap_controller.kMaxGrowingFactor;
double min_factor = heap_controller.min_growing_factor_;
double max_factor = heap_controller.max_growing_factor_;
CheckEqualRounded(max_factor, heap_controller.GrowingFactor(34, 1, 4.0));
CheckEqualRounded(3.553, heap_controller.GrowingFactor(45, 1, 4.0));
......@@ -51,15 +51,15 @@ TEST_F(HeapControllerTest, HeapGrowingFactor) {
TEST_F(HeapControllerTest, MaxHeapGrowingFactor) {
HeapController heap_controller(i_isolate()->heap());
CheckEqualRounded(
1.3, heap_controller.MaxGrowingFactor(heap_controller.kMinSize * MB));
1.3, heap_controller.MaxGrowingFactor(HeapController::kMinSize * MB));
CheckEqualRounded(1.600, heap_controller.MaxGrowingFactor(
heap_controller.kMaxSize / 2 * MB));
HeapController::kMaxSize / 2 * MB));
CheckEqualRounded(
1.999, heap_controller.MaxGrowingFactor(
(heap_controller.kMaxSize - Heap::kPointerMultiplier) * MB));
(HeapController::kMaxSize - Heap::kPointerMultiplier) * MB));
CheckEqualRounded(4.0,
heap_controller.MaxGrowingFactor(
static_cast<size_t>(heap_controller.kMaxSize) * MB));
static_cast<size_t>(HeapController::kMaxSize) * MB));
}
TEST_F(HeapControllerTest, OldGenerationAllocationLimit) {
......@@ -75,39 +75,43 @@ TEST_F(HeapControllerTest, OldGenerationAllocationLimit) {
double factor =
heap_controller.GrowingFactor(gc_speed, mutator_speed, max_factor);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
new_space_capacity, Heap::HeapGrowingMode::kDefault));
EXPECT_EQ(
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed,
mutator_speed, new_space_capacity, Heap::HeapGrowingMode::kDefault));
factor = Min(factor, heap_controller.kConservativeGrowingFactor);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
new_space_capacity, Heap::HeapGrowingMode::kSlow));
factor = Min(factor, heap_controller.kConservativeGrowingFactor);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
new_space_capacity, Heap::HeapGrowingMode::kConservative));
factor = Min(factor, heap_controller.conservative_growing_factor_);
EXPECT_EQ(
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed,
mutator_speed, new_space_capacity, Heap::HeapGrowingMode::kSlow));
factor = heap_controller.kMinGrowingFactor;
factor = Min(factor, heap_controller.conservative_growing_factor_);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed,
new_space_capacity, Heap::HeapGrowingMode::kMinimal));
old_gen_size, max_old_generation_size, max_factor, gc_speed,
mutator_speed, new_space_capacity,
Heap::HeapGrowingMode::kConservative));
factor = heap_controller.min_growing_factor_;
EXPECT_EQ(
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
heap->heap_controller()->CalculateAllocationLimit(
old_gen_size, max_old_generation_size, max_factor, gc_speed,
mutator_speed, new_space_capacity, Heap::HeapGrowingMode::kMinimal));
}
TEST_F(HeapControllerTest, MaxOldGenerationSize) {
HeapController heap_controller(i_isolate()->heap());
uint64_t configurations[][2] = {
{0, heap_controller.kMinSize},
{512, heap_controller.kMinSize},
{0, HeapController::kMinSize},
{512, HeapController::kMinSize},
{1 * GB, 256 * Heap::kPointerMultiplier},
{2 * static_cast<uint64_t>(GB), 512 * Heap::kPointerMultiplier},
{4 * static_cast<uint64_t>(GB), heap_controller.kMaxSize},
{8 * static_cast<uint64_t>(GB), heap_controller.kMaxSize}};
{4 * static_cast<uint64_t>(GB), HeapController::kMaxSize},
{8 * static_cast<uint64_t>(GB), HeapController::kMaxSize}};
for (auto configuration : configurations) {
ASSERT_EQ(configuration[1],
......
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