Commit 8c9ca62a authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] Introduce a min heap size and skip GCs below that threshold

If the embedder specifies an initial heap size, then we can take it
as a hint to skip full GCs below that threshold.

Bug: v8:9306
Change-Id: I42a4c597bf75c6ba9845ed7a6bd9946012979005
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1646515Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62030}
parent 699badd5
......@@ -126,8 +126,9 @@ size_t MemoryController<Trait>::MinimumAllocationLimitGrowingStep(
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) {
Heap* heap, size_t current_size, size_t min_size, size_t max_size,
size_t new_space_capacity, double factor,
Heap::HeapGrowingMode growing_mode) {
switch (growing_mode) {
case Heap::HeapGrowingMode::kConservative:
case Heap::HeapGrowingMode::kSlow:
......@@ -155,9 +156,11 @@ size_t MemoryController<Trait>::CalculateAllocationLimit(
static_cast<uint64_t>(current_size) +
MinimumAllocationLimitGrowingStep(growing_mode)) +
new_space_capacity;
const uint64_t limit_above_min_size = Max<uint64_t>(limit, min_size);
const uint64_t halfway_to_the_max =
(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_above_min_size, halfway_to_the_max));
if (FLAG_trace_gc_verbose) {
Isolate::FromHeap(heap)->PrintWithTimestamp(
"[%s] Limit: old size: %zu KB, new limit: %zu KB (%.1f)\n",
......
......@@ -42,7 +42,7 @@ class V8_EXPORT_PRIVATE MemoryController : public AllStatic {
double mutator_speed);
static size_t CalculateAllocationLimit(Heap* heap, size_t current_size,
size_t max_size,
size_t min_size, size_t max_size,
size_t new_space_capacity,
double factor,
Heap::HeapGrowingMode growing_mode);
......
......@@ -2058,14 +2058,16 @@ void Heap::RecomputeLimits(GarbageCollector collector) {
old_generation_allocation_limit_ =
MemoryController<V8HeapTrait>::CalculateAllocationLimit(
this, old_gen_size, max_old_generation_size_, new_space_capacity,
v8_growing_factor, mode);
this, old_gen_size, min_old_generation_size_,
max_old_generation_size_, new_space_capacity, v8_growing_factor,
mode);
if (UseGlobalMemoryScheduling()) {
DCHECK_GT(global_growing_factor, 0);
global_allocation_limit_ =
MemoryController<GlobalMemoryTrait>::CalculateAllocationLimit(
this, GlobalSizeOfObjects(), max_global_memory_size_,
new_space_capacity, global_growing_factor, mode);
this, GlobalSizeOfObjects(), min_global_memory_size_,
max_global_memory_size_, new_space_capacity,
global_growing_factor, mode);
}
CheckIneffectiveMarkCompact(
old_gen_size, tracer()->AverageMarkCompactMutatorUtilization());
......@@ -2073,8 +2075,9 @@ void Heap::RecomputeLimits(GarbageCollector collector) {
old_generation_size_configured_) {
size_t new_old_generation_limit =
MemoryController<V8HeapTrait>::CalculateAllocationLimit(
this, old_gen_size, max_old_generation_size_, new_space_capacity,
v8_growing_factor, mode);
this, old_gen_size, min_old_generation_size_,
max_old_generation_size_, new_space_capacity, v8_growing_factor,
mode);
if (new_old_generation_limit < old_generation_allocation_limit_) {
old_generation_allocation_limit_ = new_old_generation_limit;
}
......@@ -2082,8 +2085,9 @@ void Heap::RecomputeLimits(GarbageCollector collector) {
DCHECK_GT(global_growing_factor, 0);
size_t new_global_limit =
MemoryController<GlobalMemoryTrait>::CalculateAllocationLimit(
this, GlobalSizeOfObjects(), max_global_memory_size_,
new_space_capacity, global_growing_factor, mode);
this, GlobalSizeOfObjects(), min_global_memory_size_,
max_global_memory_size_, new_space_capacity,
global_growing_factor, mode);
if (new_global_limit < global_allocation_limit_) {
global_allocation_limit_ = new_global_limit;
}
......@@ -4401,11 +4405,17 @@ void Heap::ConfigureHeap(const v8::ResourceConstraints& constraints) {
old_generation_size_configured_ = true;
}
initial_old_generation_size_ =
Min(initial_old_generation_size_, max_old_generation_size_);
Min(initial_old_generation_size_, max_old_generation_size_ / 2);
initial_old_generation_size_ =
RoundDown<Page::kPageSize>(initial_old_generation_size_);
}
if (old_generation_size_configured_) {
// If the embedder pre-configures the initial old generation size,
// then allow V8 to skip full GCs below that threshold.
min_old_generation_size_ = initial_old_generation_size_;
}
if (FLAG_semi_space_growth_factor < 2) {
FLAG_semi_space_growth_factor = 2;
}
......
......@@ -1818,9 +1818,15 @@ class Heap {
size_t code_range_size_ = 0;
size_t max_semi_space_size_ = 8 * (kSystemPointerSize / 4) * MB;
size_t initial_semispace_size_ = kMinSemiSpaceSize;
// Full garbage collections can be skipped if the old generation size
// is below this threshold.
size_t min_old_generation_size_ = 0;
// If the old generation size exceeds this limit, then V8 will
// crash with out-of-memory error.
size_t max_old_generation_size_ = 700ul * (kSystemPointerSize / 4) * MB;
// TODO(mlippautz): Clarify whether this should be take some embedder
// TODO(mlippautz): Clarify whether this should take some embedder
// configurable limit into account.
size_t min_global_memory_size_ = 0;
size_t max_global_memory_size_ =
Min(static_cast<uint64_t>(std::numeric_limits<size_t>::max()),
static_cast<uint64_t>(max_old_generation_size_) * 2);
......
......@@ -76,26 +76,36 @@ TEST_F(MemoryControllerTest, OldGenerationAllocationLimit) {
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
V8Controller::CalculateAllocationLimit(
heap, old_gen_size, max_old_generation_size, new_space_capacity,
factor, Heap::HeapGrowingMode::kDefault));
heap, old_gen_size, 0u, max_old_generation_size,
new_space_capacity, factor, Heap::HeapGrowingMode::kDefault));
factor = Min(factor, V8HeapTrait::kConservativeGrowingFactor);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
V8Controller::CalculateAllocationLimit(
heap, old_gen_size, max_old_generation_size, new_space_capacity,
factor, Heap::HeapGrowingMode::kSlow));
heap, old_gen_size, 0u, max_old_generation_size,
new_space_capacity, factor, Heap::HeapGrowingMode::kSlow));
factor = Min(factor, V8HeapTrait::kConservativeGrowingFactor);
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
V8Controller::CalculateAllocationLimit(
heap, old_gen_size, max_old_generation_size, new_space_capacity,
factor, Heap::HeapGrowingMode::kConservative));
EXPECT_EQ(
static_cast<size_t>(old_gen_size * factor + new_space_capacity),
V8Controller::CalculateAllocationLimit(
heap, old_gen_size, 0u, max_old_generation_size, new_space_capacity,
factor, Heap::HeapGrowingMode::kConservative));
factor = V8HeapTrait::kMinGrowingFactor;
EXPECT_EQ(static_cast<size_t>(old_gen_size * factor + new_space_capacity),
V8Controller::CalculateAllocationLimit(
heap, old_gen_size, max_old_generation_size, new_space_capacity,
factor, Heap::HeapGrowingMode::kMinimal));
heap, old_gen_size, 0u, max_old_generation_size,
new_space_capacity, factor, Heap::HeapGrowingMode::kMinimal));
factor = V8HeapTrait::kMinGrowingFactor;
size_t min_old_generation_size =
2 * static_cast<size_t>(old_gen_size * factor + new_space_capacity);
EXPECT_EQ(
min_old_generation_size,
V8Controller::CalculateAllocationLimit(
heap, old_gen_size, min_old_generation_size, max_old_generation_size,
new_space_capacity, factor, Heap::HeapGrowingMode::kMinimal));
}
} // namespace internal
......
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