Commit aa1b81b6 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[heap] Fix global memory scheduling

Rework limit computation:
- Model controller as static classes based on traits.
- Compute growing factors for both controllers and pick the
  larger growing factor for both controllers.
- Factor out limit computation in its own function.

Bug: chromium:948807
Change-Id: Id466a66d7aa573de91ad388ea9218e9f6721d19a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1627534
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61801}
parent e448740e
...@@ -10,6 +10,49 @@ ...@@ -10,6 +10,49 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
template <typename Trait>
double MemoryController<Trait>::GrowingFactor(Heap* heap, size_t max_heap_size,
double gc_speed,
double mutator_speed) {
const double max_factor = MaxGrowingFactor(max_heap_size);
const double factor =
DynamicGrowingFactor(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",
Trait::kName, factor, Trait::kTargetMutatorUtilization,
gc_speed / mutator_speed, gc_speed, mutator_speed);
}
return factor;
}
template <typename Trait>
double MemoryController<Trait>::MaxGrowingFactor(size_t max_heap_size) {
constexpr double kMinSmallFactor = 1.3;
constexpr double kMaxSmallFactor = 2.0;
constexpr double kHighFactor = 4.0;
size_t max_size_in_mb = max_heap_size / MB;
max_size_in_mb = Max(max_size_in_mb, Trait::kMinSize);
// If we are on a device with lots of memory, we allow a high heap
// growing factor.
if (max_size_in_mb >= Trait::kMaxSize) {
return kHighFactor;
}
DCHECK_GE(max_size_in_mb, Trait::kMinSize);
DCHECK_LT(max_size_in_mb, Trait::kMaxSize);
// On smaller devices we linearly scale the factor: (X-A)/(B-A)*(D-C)+C
double factor = (max_size_in_mb - Trait::kMinSize) *
(kMaxSmallFactor - kMinSmallFactor) /
(Trait::kMaxSize - Trait::kMinSize) +
kMinSmallFactor;
return factor;
}
// Given GC speed in bytes per ms, the allocation throughput in bytes per ms // 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 // (mutator speed), this function returns the heap growing factor that will
// achieve the target_mutator_utilization_ if the GC speed and the mutator speed // achieve the target_mutator_utilization_ if the GC speed and the mutator speed
...@@ -49,35 +92,49 @@ namespace internal { ...@@ -49,35 +92,49 @@ 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, template <typename Trait>
double MemoryController<Trait>::DynamicGrowingFactor(double gc_speed,
double mutator_speed,
double max_factor) { double max_factor) {
DCHECK_LE(min_growing_factor_, max_factor); DCHECK_LE(Trait::kMinGrowingFactor, max_factor);
DCHECK_GE(max_growing_factor_, max_factor); DCHECK_GE(Trait::kMaxGrowingFactor, max_factor);
if (gc_speed == 0 || mutator_speed == 0) return max_factor; if (gc_speed == 0 || mutator_speed == 0) return max_factor;
const double speed_ratio = gc_speed / mutator_speed; const double speed_ratio = gc_speed / mutator_speed;
const double a = speed_ratio * (1 - target_mutator_utlization_); const double a = speed_ratio * (1 - Trait::kTargetMutatorUtilization);
const double b = speed_ratio * (1 - target_mutator_utlization_) - const double b = speed_ratio * (1 - Trait::kTargetMutatorUtilization) -
target_mutator_utlization_; Trait::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;
factor = Min(factor, max_factor); factor = Min(factor, max_factor);
factor = Max(factor, min_growing_factor_); factor = Max(factor, Trait::kMinGrowingFactor);
return factor; return factor;
} }
size_t MemoryController::CalculateAllocationLimitBase( template <typename Trait>
size_t curr_size, size_t max_size, double factor, size_t additional_bytes, size_t MemoryController<Trait>::MinimumAllocationLimitGrowingStep(
Heap::HeapGrowingMode growing_mode) { Heap::HeapGrowingMode growing_mode) {
const size_t kRegularAllocationLimitGrowingStep = 8;
const size_t kLowMemoryAllocationLimitGrowingStep = 2;
size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB);
return limit * (growing_mode == Heap::HeapGrowingMode::kConservative
? kLowMemoryAllocationLimitGrowingStep
: kRegularAllocationLimitGrowingStep);
}
template <typename Trait>
size_t MemoryController<Trait>::CalculateAllocationLimit(
Heap* heap, size_t current_size, size_t max_size, size_t new_space_capacity,
double factor, Heap::HeapGrowingMode growing_mode) {
switch (growing_mode) { switch (growing_mode) {
case Heap::HeapGrowingMode::kConservative: case Heap::HeapGrowingMode::kConservative:
case Heap::HeapGrowingMode::kSlow: case Heap::HeapGrowingMode::kSlow:
factor = Min(factor, conservative_growing_factor_); factor = Min(factor, Trait::kConservativeGrowingFactor);
break; break;
case Heap::HeapGrowingMode::kMinimal: case Heap::HeapGrowingMode::kMinimal:
factor = min_growing_factor_; factor = Trait::kMinGrowingFactor;
break; break;
case Heap::HeapGrowingMode::kDefault: case Heap::HeapGrowingMode::kDefault:
break; break;
...@@ -87,119 +144,33 @@ size_t MemoryController::CalculateAllocationLimitBase( ...@@ -87,119 +144,33 @@ size_t MemoryController::CalculateAllocationLimitBase(
factor = 1.0 + FLAG_heap_growing_percent / 100.0; factor = 1.0 + FLAG_heap_growing_percent / 100.0;
} }
if (FLAG_heap_growing_percent > 0) {
factor = 1.0 + FLAG_heap_growing_percent / 100.0;
}
CHECK_LT(1.0, factor); CHECK_LT(1.0, factor);
CHECK_LT(0, curr_size); CHECK_LT(0, current_size);
const uint64_t limit = const uint64_t limit =
Max(static_cast<uint64_t>(curr_size * factor), Max(static_cast<uint64_t>(current_size * factor),
static_cast<uint64_t>(curr_size) + static_cast<uint64_t>(current_size) +
MinimumAllocationLimitGrowingStep(growing_mode)) + MinimumAllocationLimitGrowingStep(growing_mode)) +
additional_bytes; new_space_capacity;
const uint64_t halfway_to_the_max = const uint64_t halfway_to_the_max =
(static_cast<uint64_t>(curr_size) + max_size) / 2; (static_cast<uint64_t>(current_size) + max_size) / 2;
const 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); Trait::kName, current_size / KB, result / KB, factor);
} }
return result; return result;
} }
size_t MemoryController::MinimumAllocationLimitGrowingStep( template class V8_EXPORT_PRIVATE MemoryController<V8HeapTrait>;
Heap::HeapGrowingMode growing_mode) { template class V8_EXPORT_PRIVATE MemoryController<GlobalMemoryTrait>;
const size_t kRegularAllocationLimitGrowingStep = 8;
const size_t kLowMemoryAllocationLimitGrowingStep = 2;
size_t limit = (Page::kPageSize > MB ? Page::kPageSize : MB);
return limit * (growing_mode == Heap::HeapGrowingMode::kConservative
? kLowMemoryAllocationLimitGrowingStep
: kRegularAllocationLimitGrowingStep);
}
double HeapController::MaxGrowingFactor(size_t curr_max_size) {
constexpr double kMinSmallFactor = 1.3;
constexpr double kMaxSmallFactor = 2.0;
constexpr double kHighFactor = 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 kHighFactor;
}
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) *
(kMaxSmallFactor - kMinSmallFactor) /
(kMaxSize - kMinSize) +
kMinSmallFactor;
return factor;
}
double GlobalMemoryController::MaxGrowingFactor(size_t curr_max_size) {
constexpr double kMinSmallFactor = 1.3;
constexpr double kMaxSmallFactor = 2.0;
constexpr double kHighFactor = 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 kHighFactor;
}
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) *
(kMaxSmallFactor - kMinSmallFactor) /
(kMaxSize - kMinSize) +
kMinSmallFactor;
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, target_mutator_utlization_,
gc_speed / mutator_speed, gc_speed, mutator_speed);
}
return CalculateAllocationLimitBase(curr_size, max_size, factor,
new_space_capacity, growing_mode);
}
size_t GlobalMemoryController::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, target_mutator_utlization_,
gc_speed / mutator_speed, gc_speed, mutator_speed);
}
return CalculateAllocationLimitBase(curr_size, max_size, factor, const char* V8HeapTrait::kName = "HeapController";
new_space_capacity, growing_mode); const char* GlobalMemoryTrait::kName = "GlobalMemoryController";
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -13,85 +13,48 @@ ...@@ -13,85 +13,48 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class V8_EXPORT_PRIVATE MemoryController { struct BaseControllerTrait {
public:
// Computes the growing step when the limit increases.
static size_t MinimumAllocationLimitGrowingStep(
Heap::HeapGrowingMode growing_mode);
virtual ~MemoryController() = default;
protected:
MemoryController(Heap* heap, double min_growing_factor,
double max_growing_factor,
double conservative_growing_factor,
double target_mutator_utlization)
: heap_(heap),
min_growing_factor_(min_growing_factor),
max_growing_factor_(max_growing_factor),
conservative_growing_factor_(conservative_growing_factor),
target_mutator_utlization_(target_mutator_utlization) {}
// Computes the allocation limit to trigger the next garbage collection.
size_t CalculateAllocationLimitBase(size_t curr_size, size_t max_size,
double factor, size_t additional_bytes,
Heap::HeapGrowingMode growing_mode);
double GrowingFactor(double gc_speed, double mutator_speed,
double max_factor);
virtual const char* ControllerName() = 0;
Heap* const heap_;
const double min_growing_factor_;
const double max_growing_factor_;
const double conservative_growing_factor_;
const double target_mutator_utlization_;
};
class V8_EXPORT_PRIVATE HeapController : public MemoryController {
public:
// 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;
explicit HeapController(Heap* heap) static constexpr double kMinGrowingFactor = 1.1;
: MemoryController(heap, 1.1, 4.0, 1.3, 0.97) {} static constexpr double kMaxGrowingFactor = 4.0;
static constexpr double kConservativeGrowingFactor = 1.3;
size_t CalculateAllocationLimit(size_t curr_size, size_t max_size, static constexpr double kTargetMutatorUtilization = 0.97;
double gc_speed, double mutator_speed, };
size_t new_space_capacity,
Heap::HeapGrowingMode growing_mode);
protected:
double MaxGrowingFactor(size_t curr_max_size);
const char* ControllerName() override { return "HeapController"; } struct V8HeapTrait : public BaseControllerTrait {
static const char* kName;
};
FRIEND_TEST(HeapControllerTest, HeapGrowingFactor); struct GlobalMemoryTrait : public BaseControllerTrait {
FRIEND_TEST(HeapControllerTest, MaxHeapGrowingFactor); static const char* kName;
FRIEND_TEST(HeapControllerTest, MaxOldGenerationSize);
FRIEND_TEST(HeapControllerTest, OldGenerationAllocationLimit);
}; };
class V8_EXPORT_PRIVATE GlobalMemoryController : public MemoryController { template <typename Trait>
class V8_EXPORT_PRIVATE MemoryController : public AllStatic {
public: public:
// Sizes are in MB. // Computes the growing step when the limit increases.
static constexpr size_t kMinSize = 128 * Heap::kPointerMultiplier; static size_t MinimumAllocationLimitGrowingStep(
static constexpr size_t kMaxSize = 1024 * Heap::kPointerMultiplier; Heap::HeapGrowingMode growing_mode);
explicit GlobalMemoryController(Heap* heap) static double GrowingFactor(Heap* heap, size_t max_heap_size, double gc_speed,
: MemoryController(heap, 1.1, 4.0, 1.3, 0.97) {} double mutator_speed);
size_t CalculateAllocationLimit(size_t curr_size, size_t max_size, static size_t CalculateAllocationLimit(Heap* heap, size_t current_size,
double gc_speed, double mutator_speed, size_t max_size,
size_t new_space_capacity, size_t new_space_capacity,
double factor,
Heap::HeapGrowingMode growing_mode); Heap::HeapGrowingMode growing_mode);
protected: private:
double MaxGrowingFactor(size_t curr_max_size); static double MaxGrowingFactor(size_t max_heap_size);
static double DynamicGrowingFactor(double gc_speed, double mutator_speed,
double max_factor);
const char* ControllerName() override { return "GlobalMemoryController"; } FRIEND_TEST(MemoryControllerTest, HeapGrowingFactor);
FRIEND_TEST(MemoryControllerTest, MaxHeapGrowingFactor);
}; };
} // namespace internal } // namespace internal
......
...@@ -212,7 +212,7 @@ size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) { ...@@ -212,7 +212,7 @@ size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) {
size_t computed_size = static_cast<size_t>(physical_memory / i::MB / size_t computed_size = static_cast<size_t>(physical_memory / i::MB /
old_space_physical_memory_factor * old_space_physical_memory_factor *
kPointerMultiplier); kPointerMultiplier);
size_t max_size_in_mb = HeapController::kMaxSize; size_t max_size_in_mb = V8HeapTrait::kMaxSize;
// Finch experiment: Increase the heap size from 2GB to 4GB for 64-bit // Finch experiment: Increase the heap size from 2GB to 4GB for 64-bit
// systems with physical memory bigger than 16GB. // systems with physical memory bigger than 16GB.
...@@ -223,7 +223,7 @@ size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) { ...@@ -223,7 +223,7 @@ size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) {
max_size_in_mb = 4096; // 4GB max_size_in_mb = 4096; // 4GB
} }
return Max(Min(computed_size, max_size_in_mb), HeapController::kMinSize); return Max(Min(computed_size, max_size_in_mb), V8HeapTrait::kMinSize);
} }
size_t Heap::Capacity() { size_t Heap::Capacity() {
...@@ -1928,28 +1928,65 @@ bool Heap::PerformGarbageCollection( ...@@ -1928,28 +1928,65 @@ bool Heap::PerformGarbageCollection(
// Update relocatables. // Update relocatables.
Relocatable::PostGarbageCollectionProcessing(isolate_); Relocatable::PostGarbageCollectionProcessing(isolate_);
double gc_speed = tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond(); RecomputeLimits(collector);
double mutator_speed =
tracer()->CurrentOldGenerationAllocationThroughputInBytesPerMillisecond();
size_t old_gen_size = OldGenerationSizeOfObjects();
double global_mutator_speed; {
double global_gc_speed; GCCallbacksScope scope(this);
size_t global_memory_size; if (scope.CheckReenter()) {
AllowHeapAllocation allow_allocation;
AllowJavascriptExecution allow_js(isolate());
TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_EPILOGUE);
VMState<EXTERNAL> state(isolate_);
HandleScope handle_scope(isolate_);
CallGCEpilogueCallbacks(gc_type, gc_callback_flags);
}
}
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
VerifyStringTable(this->isolate());
}
#endif
return freed_global_handles > 0;
}
void Heap::RecomputeLimits(GarbageCollector collector) {
if (!((collector == MARK_COMPACTOR) ||
(HasLowYoungGenerationAllocationRate() &&
old_generation_size_configured_))) {
return;
}
double v8_gc_speed =
tracer()->CombinedMarkCompactSpeedInBytesPerMillisecond();
double v8_mutator_speed =
tracer()->CurrentOldGenerationAllocationThroughputInBytesPerMillisecond();
double v8_growing_factor = MemoryController<V8HeapTrait>::GrowingFactor(
this, max_old_generation_size_, v8_gc_speed, v8_mutator_speed);
double global_growing_factor = 0;
if (UseGlobalMemoryScheduling()) { if (UseGlobalMemoryScheduling()) {
global_mutator_speed = GCTracer::CombineSpeedsInBytesPerMillisecond( double embedder_gc_speed =
mutator_speed,
local_embedder_heap_tracer() local_embedder_heap_tracer()
? tracer() ? tracer()
->CurrentEmbedderAllocationThroughputInBytesPerMillisecond() ->CurrentEmbedderAllocationThroughputInBytesPerMillisecond()
: 0.0); : 0.0;
global_gc_speed = GCTracer::CombineSpeedsInBytesPerMillisecond( double embedder_speed = local_embedder_heap_tracer()
gc_speed, local_embedder_heap_tracer()
? tracer()->EmbedderSpeedInBytesPerMillisecond() ? tracer()->EmbedderSpeedInBytesPerMillisecond()
: 0.0); : 0.0;
global_memory_size = GlobalSizeOfObjects(); double embedder_growing_factor =
(embedder_gc_speed > 0 && embedder_speed > 0)
? MemoryController<GlobalMemoryTrait>::GrowingFactor(
this, max_global_memory_size_, embedder_gc_speed,
embedder_speed)
: 0;
global_growing_factor = Max(v8_growing_factor, embedder_growing_factor);
} }
size_t old_gen_size = OldGenerationSizeOfObjects();
size_t new_space_capacity = new_space()->Capacity();
HeapGrowingMode mode = CurrentHeapGrowingMode();
if (collector == MARK_COMPACTOR) { if (collector == MARK_COMPACTOR) {
// Register the amount of external allocated memory. // Register the amount of external allocated memory.
isolate()->isolate_data()->external_memory_at_last_mark_compact_ = isolate()->isolate_data()->external_memory_at_last_mark_compact_ =
...@@ -1959,60 +1996,40 @@ bool Heap::PerformGarbageCollection( ...@@ -1959,60 +1996,40 @@ bool Heap::PerformGarbageCollection(
kExternalAllocationSoftLimit; kExternalAllocationSoftLimit;
old_generation_allocation_limit_ = old_generation_allocation_limit_ =
heap_controller()->CalculateAllocationLimit( MemoryController<V8HeapTrait>::CalculateAllocationLimit(
old_gen_size, max_old_generation_size_, gc_speed, mutator_speed, this, old_gen_size, max_old_generation_size_, new_space_capacity,
new_space()->Capacity(), CurrentHeapGrowingMode()); v8_growing_factor, mode);
if (UseGlobalMemoryScheduling()) { if (UseGlobalMemoryScheduling()) {
DCHECK_GT(global_growing_factor, 0);
global_allocation_limit_ = global_allocation_limit_ =
global_memory_controller()->CalculateAllocationLimit( MemoryController<GlobalMemoryTrait>::CalculateAllocationLimit(
global_memory_size, max_global_memory_size_, global_gc_speed, this, GlobalSizeOfObjects(), max_global_memory_size_,
global_mutator_speed, new_space()->Capacity(), new_space_capacity, global_growing_factor, mode);
CurrentHeapGrowingMode());
} }
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_) {
size_t new_limit = heap_controller()->CalculateAllocationLimit( size_t new_old_generation_limit =
old_gen_size, max_old_generation_size_, gc_speed, mutator_speed, MemoryController<V8HeapTrait>::CalculateAllocationLimit(
new_space()->Capacity(), CurrentHeapGrowingMode()); this, old_gen_size, max_old_generation_size_, new_space_capacity,
if (new_limit < old_generation_allocation_limit_) { v8_growing_factor, mode);
old_generation_allocation_limit_ = new_limit; if (new_old_generation_limit < old_generation_allocation_limit_) {
old_generation_allocation_limit_ = new_old_generation_limit;
} }
if (UseGlobalMemoryScheduling()) { if (UseGlobalMemoryScheduling()) {
const size_t new_global_limit = DCHECK_GT(global_growing_factor, 0);
global_memory_controller()->CalculateAllocationLimit( size_t new_global_limit =
global_memory_size, max_global_memory_size_, global_gc_speed, MemoryController<GlobalMemoryTrait>::CalculateAllocationLimit(
global_mutator_speed, new_space()->Capacity(), this, GlobalSizeOfObjects(), max_global_memory_size_,
CurrentHeapGrowingMode()); new_space_capacity, global_growing_factor, mode);
if (new_global_limit < global_allocation_limit_) { if (new_global_limit < global_allocation_limit_) {
global_allocation_limit_ = new_global_limit; global_allocation_limit_ = new_global_limit;
} }
} }
} }
{
GCCallbacksScope scope(this);
if (scope.CheckReenter()) {
AllowHeapAllocation allow_allocation;
AllowJavascriptExecution allow_js(isolate());
TRACE_GC(tracer(), GCTracer::Scope::HEAP_EXTERNAL_EPILOGUE);
VMState<EXTERNAL> state(isolate_);
HandleScope handle_scope(isolate_);
CallGCEpilogueCallbacks(gc_type, gc_callback_flags);
}
}
#ifdef VERIFY_HEAP
if (FLAG_verify_heap) {
VerifyStringTable(this->isolate());
}
#endif
return freed_global_handles > 0;
} }
void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) { void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
RuntimeCallTimerScope runtime_timer( RuntimeCallTimerScope runtime_timer(
isolate(), RuntimeCallCounterId::kGCPrologueCallback); isolate(), RuntimeCallCounterId::kGCPrologueCallback);
...@@ -2646,7 +2663,7 @@ void Heap::UnregisterArrayBuffer(JSArrayBuffer buffer) { ...@@ -2646,7 +2663,7 @@ void Heap::UnregisterArrayBuffer(JSArrayBuffer buffer) {
void Heap::ConfigureInitialOldGenerationSize() { void Heap::ConfigureInitialOldGenerationSize() {
if (!old_generation_size_configured_ && tracer()->SurvivalEventsRecorded()) { if (!old_generation_size_configured_ && tracer()->SurvivalEventsRecorded()) {
const size_t minimum_growing_step = const size_t minimum_growing_step =
MemoryController::MinimumAllocationLimitGrowingStep( MemoryController<V8HeapTrait>::MinimumAllocationLimitGrowingStep(
CurrentHeapGrowingMode()); CurrentHeapGrowingMode());
const size_t new_old_generation_allocation_limit = const size_t new_old_generation_allocation_limit =
Max(OldGenerationSizeOfObjects() + minimum_growing_step, Max(OldGenerationSizeOfObjects() + minimum_growing_step,
...@@ -4729,9 +4746,6 @@ void Heap::SetUp() { ...@@ -4729,9 +4746,6 @@ void Heap::SetUp() {
store_buffer_.reset(new StoreBuffer(this)); store_buffer_.reset(new StoreBuffer(this));
heap_controller_.reset(new HeapController(this));
global_memory_controller_.reset(new GlobalMemoryController(this));
mark_compact_collector_.reset(new MarkCompactCollector(this)); mark_compact_collector_.reset(new MarkCompactCollector(this));
scavenger_collector_.reset(new ScavengerCollector(this)); scavenger_collector_.reset(new ScavengerCollector(this));
...@@ -5007,9 +5021,6 @@ void Heap::TearDown() { ...@@ -5007,9 +5021,6 @@ void Heap::TearDown() {
stress_scavenge_observer_ = nullptr; stress_scavenge_observer_ = nullptr;
} }
heap_controller_.reset();
global_memory_controller_.reset();
if (mark_compact_collector_) { if (mark_compact_collector_) {
mark_compact_collector_->TearDown(); mark_compact_collector_->TearDown();
mark_compact_collector_.reset(); mark_compact_collector_.reset();
......
...@@ -62,7 +62,6 @@ class ConcurrentMarking; ...@@ -62,7 +62,6 @@ class ConcurrentMarking;
class GCIdleTimeHandler; class GCIdleTimeHandler;
class GCIdleTimeHeapState; class GCIdleTimeHeapState;
class GCTracer; class GCTracer;
class GlobalMemoryController;
class HeapController; class HeapController;
class HeapObjectAllocationTracker; class HeapObjectAllocationTracker;
class HeapObjectsFilter; class HeapObjectsFilter;
...@@ -213,6 +212,8 @@ class Heap { ...@@ -213,6 +212,8 @@ class Heap {
EphemeronRememberedSet ephemeron_remembered_set_; EphemeronRememberedSet ephemeron_remembered_set_;
enum FindMementoMode { kForRuntime, kForGC }; enum FindMementoMode { kForRuntime, kForGC };
enum class HeapGrowingMode { kSlow, kConservative, kMinimal, kDefault };
enum HeapState { enum HeapState {
NOT_IN_GC, NOT_IN_GC,
SCAVENGE, SCAVENGE,
...@@ -1692,10 +1693,6 @@ class Heap { ...@@ -1692,10 +1693,6 @@ class Heap {
// Growing strategy. ========================================================= // Growing strategy. =========================================================
// =========================================================================== // ===========================================================================
HeapController* heap_controller() { return heap_controller_.get(); }
GlobalMemoryController* global_memory_controller() const {
return global_memory_controller_.get();
}
MemoryReducer* memory_reducer() { return memory_reducer_.get(); } MemoryReducer* memory_reducer() { return memory_reducer_.get(); }
// For some webpages RAIL mode does not switch from PERFORMANCE_LOAD. // For some webpages RAIL mode does not switch from PERFORMANCE_LOAD.
...@@ -1716,8 +1713,6 @@ class Heap { ...@@ -1716,8 +1713,6 @@ class Heap {
bool ShouldExpandOldGenerationOnSlowAllocation(); bool ShouldExpandOldGenerationOnSlowAllocation();
enum class HeapGrowingMode { kSlow, kConservative, kMinimal, kDefault };
HeapGrowingMode CurrentHeapGrowingMode(); HeapGrowingMode CurrentHeapGrowingMode();
enum class IncrementalMarkingLimit { kNoLimit, kSoftLimit, kHardLimit }; enum class IncrementalMarkingLimit { kNoLimit, kSoftLimit, kHardLimit };
...@@ -1729,6 +1724,8 @@ class Heap { ...@@ -1729,6 +1724,8 @@ class Heap {
size_t GlobalMemoryAvailable(); size_t GlobalMemoryAvailable();
void RecomputeLimits(GarbageCollector collector);
// =========================================================================== // ===========================================================================
// Idle notification. ======================================================== // Idle notification. ========================================================
// =========================================================================== // ===========================================================================
...@@ -1985,8 +1982,6 @@ class Heap { ...@@ -1985,8 +1982,6 @@ class Heap {
std::unique_ptr<ArrayBufferCollector> array_buffer_collector_; std::unique_ptr<ArrayBufferCollector> array_buffer_collector_;
std::unique_ptr<MemoryAllocator> memory_allocator_; std::unique_ptr<MemoryAllocator> memory_allocator_;
std::unique_ptr<StoreBuffer> store_buffer_; std::unique_ptr<StoreBuffer> store_buffer_;
std::unique_ptr<HeapController> heap_controller_;
std::unique_ptr<GlobalMemoryController> global_memory_controller_;
std::unique_ptr<IncrementalMarking> incremental_marking_; std::unique_ptr<IncrementalMarking> incremental_marking_;
std::unique_ptr<ConcurrentMarking> concurrent_marking_; std::unique_ptr<ConcurrentMarking> concurrent_marking_;
std::unique_ptr<GCIdleTimeHandler> gc_idle_time_handler_; std::unique_ptr<GCIdleTimeHandler> gc_idle_time_handler_;
...@@ -2086,9 +2081,6 @@ class Heap { ...@@ -2086,9 +2081,6 @@ class Heap {
friend class ConcurrentMarking; friend class ConcurrentMarking;
friend class GCCallbacksScope; friend class GCCallbacksScope;
friend class GCTracer; friend class GCTracer;
friend class GlobalMemoryController;
friend class HeapController;
friend class MemoryController;
friend class HeapIterator; friend class HeapIterator;
friend class IdleScavengeObserver; friend class IdleScavengeObserver;
friend class IncrementalMarking; friend class IncrementalMarking;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
using HeapControllerTest = TestWithIsolate; using MemoryControllerTest = TestWithIsolate;
double Round(double x) { double Round(double x) {
// Round to three digits. // Round to three digits.
...@@ -32,82 +32,81 @@ void CheckEqualRounded(double expected, double actual) { ...@@ -32,82 +32,81 @@ void CheckEqualRounded(double expected, double actual) {
EXPECT_DOUBLE_EQ(expected, actual); EXPECT_DOUBLE_EQ(expected, actual);
} }
TEST_F(HeapControllerTest, HeapGrowingFactor) { namespace {
HeapController heap_controller(i_isolate()->heap());
double min_factor = heap_controller.min_growing_factor_; using V8Controller = MemoryController<V8HeapTrait>;
double max_factor = heap_controller.max_growing_factor_;
} // namespace
CheckEqualRounded(max_factor, heap_controller.GrowingFactor(34, 1, 4.0));
CheckEqualRounded(3.553, heap_controller.GrowingFactor(45, 1, 4.0)); TEST_F(MemoryControllerTest, HeapGrowingFactor) {
CheckEqualRounded(2.830, heap_controller.GrowingFactor(50, 1, 4.0)); CheckEqualRounded(V8HeapTrait::kMaxGrowingFactor,
CheckEqualRounded(1.478, heap_controller.GrowingFactor(100, 1, 4.0)); V8Controller::DynamicGrowingFactor(34, 1, 4.0));
CheckEqualRounded(1.193, heap_controller.GrowingFactor(200, 1, 4.0)); CheckEqualRounded(3.553, V8Controller::DynamicGrowingFactor(45, 1, 4.0));
CheckEqualRounded(1.121, heap_controller.GrowingFactor(300, 1, 4.0)); CheckEqualRounded(2.830, V8Controller::DynamicGrowingFactor(50, 1, 4.0));
CheckEqualRounded(heap_controller.GrowingFactor(300, 1, 4.0), CheckEqualRounded(1.478, V8Controller::DynamicGrowingFactor(100, 1, 4.0));
heap_controller.GrowingFactor(600, 2, 4.0)); CheckEqualRounded(1.193, V8Controller::DynamicGrowingFactor(200, 1, 4.0));
CheckEqualRounded(min_factor, heap_controller.GrowingFactor(400, 1, 4.0)); CheckEqualRounded(1.121, V8Controller::DynamicGrowingFactor(300, 1, 4.0));
CheckEqualRounded(V8Controller::DynamicGrowingFactor(300, 1, 4.0),
V8Controller::DynamicGrowingFactor(600, 2, 4.0));
CheckEqualRounded(V8HeapTrait::kMinGrowingFactor,
V8Controller::DynamicGrowingFactor(400, 1, 4.0));
} }
TEST_F(HeapControllerTest, MaxHeapGrowingFactor) { TEST_F(MemoryControllerTest, MaxHeapGrowingFactor) {
HeapController heap_controller(i_isolate()->heap()); CheckEqualRounded(1.3,
V8Controller::MaxGrowingFactor(V8HeapTrait::kMinSize * MB));
CheckEqualRounded( CheckEqualRounded(
1.3, heap_controller.MaxGrowingFactor(HeapController::kMinSize * MB)); 1.600, V8Controller::MaxGrowingFactor(V8HeapTrait::kMaxSize / 2 * MB));
CheckEqualRounded(1.600, heap_controller.MaxGrowingFactor(
HeapController::kMaxSize / 2 * MB));
CheckEqualRounded( CheckEqualRounded(
1.999, heap_controller.MaxGrowingFactor( 1.999, V8Controller::MaxGrowingFactor(
(HeapController::kMaxSize - Heap::kPointerMultiplier) * MB)); (V8HeapTrait::kMaxSize - Heap::kPointerMultiplier) * MB));
CheckEqualRounded(4.0, CheckEqualRounded(4.0, V8Controller::MaxGrowingFactor(
heap_controller.MaxGrowingFactor( static_cast<size_t>(V8HeapTrait::kMaxSize) * MB));
static_cast<size_t>(HeapController::kMaxSize) * MB));
} }
TEST_F(HeapControllerTest, OldGenerationAllocationLimit) { TEST_F(MemoryControllerTest, OldGenerationAllocationLimit) {
Heap* heap = i_isolate()->heap(); Heap* heap = i_isolate()->heap();
HeapController heap_controller(heap);
size_t old_gen_size = 128 * MB; size_t old_gen_size = 128 * MB;
size_t max_old_generation_size = 512 * MB; size_t max_old_generation_size = 512 * MB;
double gc_speed = 100; double gc_speed = 100;
double mutator_speed = 1; double mutator_speed = 1;
size_t new_space_capacity = 16 * MB; size_t new_space_capacity = 16 * MB;
double max_factor = heap_controller.MaxGrowingFactor(max_old_generation_size); double factor = V8Controller::GrowingFactor(heap, max_old_generation_size,
double factor = gc_speed, mutator_speed);
heap_controller.GrowingFactor(gc_speed, mutator_speed, max_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( V8Controller::CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed, heap, old_gen_size, max_old_generation_size, new_space_capacity,
new_space_capacity, Heap::HeapGrowingMode::kDefault)); factor, Heap::HeapGrowingMode::kDefault));
factor = Min(factor, heap_controller.conservative_growing_factor_); factor = Min(factor, V8HeapTrait::kConservativeGrowingFactor);
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( V8Controller::CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed, heap, old_gen_size, max_old_generation_size, new_space_capacity,
new_space_capacity, Heap::HeapGrowingMode::kSlow)); factor, Heap::HeapGrowingMode::kSlow));
factor = Min(factor, heap_controller.conservative_growing_factor_); factor = Min(factor, V8HeapTrait::kConservativeGrowingFactor);
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( V8Controller::CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed, heap, old_gen_size, max_old_generation_size, new_space_capacity,
new_space_capacity, Heap::HeapGrowingMode::kConservative)); factor, Heap::HeapGrowingMode::kConservative));
factor = heap_controller.min_growing_factor_; factor = V8HeapTrait::kMinGrowingFactor;
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( V8Controller::CalculateAllocationLimit(
old_gen_size, max_old_generation_size, gc_speed, mutator_speed, heap, old_gen_size, max_old_generation_size, new_space_capacity,
new_space_capacity, Heap::HeapGrowingMode::kMinimal)); factor, Heap::HeapGrowingMode::kMinimal));
} }
TEST_F(HeapControllerTest, MaxOldGenerationSize) { TEST_F(MemoryControllerTest, MaxOldGenerationSize) {
HeapController heap_controller(i_isolate()->heap());
uint64_t configurations[][2] = { uint64_t configurations[][2] = {
{0, HeapController::kMinSize}, {0, V8HeapTrait::kMinSize},
{512, HeapController::kMinSize}, {512, V8HeapTrait::kMinSize},
{1 * GB, 256 * Heap::kPointerMultiplier}, {1 * GB, 256 * Heap::kPointerMultiplier},
{2 * static_cast<uint64_t>(GB), 512 * Heap::kPointerMultiplier}, {2 * static_cast<uint64_t>(GB), 512 * Heap::kPointerMultiplier},
{4 * static_cast<uint64_t>(GB), HeapController::kMaxSize}, {4 * static_cast<uint64_t>(GB), V8HeapTrait::kMaxSize},
{8 * static_cast<uint64_t>(GB), HeapController::kMaxSize}}; {8 * static_cast<uint64_t>(GB), V8HeapTrait::kMaxSize}};
for (auto configuration : configurations) { for (auto configuration : configurations) {
ASSERT_EQ(configuration[1], 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