Commit b0980748 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] Simplify computation of max semi-space size.

The size is now computed as a fraction of the old space size:
- for low memory devices (<512MB) the fraction is 1 / 256.
- for all other devices the fraction is 1 / 128.

The values were chosen to minimize the difference between the new
and the old heuristics.

Bug: v8:9306

Change-Id: I3246fe2d6fc589af6220e2566e3f10fb13470b82
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1632158Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61947}
parent b5a0e7d9
......@@ -972,9 +972,11 @@ ResourceConstraints::ResourceConstraints()
void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory,
uint64_t virtual_memory_limit) {
set_max_semi_space_size_in_kb(
i::Heap::ComputeMaxSemiSpaceSize(physical_memory));
set_max_old_space_size(i::Heap::ComputeMaxOldGenerationSize(physical_memory));
size_t old_space_size, semi_space_size;
i::Heap::ComputeMaxSpaceSizes(physical_memory, &old_space_size,
&semi_space_size);
set_max_semi_space_size_in_kb(semi_space_size / i::KB);
set_max_old_space_size(old_space_size / i::MB);
if (virtual_memory_limit > 0 && i::kRequiresCodeRange) {
// Reserve no more than 1/8 of the memory for the code range, but at most
......
......@@ -33,20 +33,20 @@ double MemoryController<Trait>::MaxGrowingFactor(size_t max_heap_size) {
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);
size_t max_size = max_heap_size;
max_size = Max(max_size, 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) {
if (max_size >= Trait::kMaxSize) {
return kHighFactor;
}
DCHECK_GE(max_size_in_mb, Trait::kMinSize);
DCHECK_LT(max_size_in_mb, Trait::kMaxSize);
DCHECK_GE(max_size, Trait::kMinSize);
DCHECK_LT(max_size, 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) *
double factor = (max_size - Trait::kMinSize) *
(kMaxSmallFactor - kMinSmallFactor) /
(Trait::kMaxSize - Trait::kMinSize) +
kMinSmallFactor;
......
......@@ -14,9 +14,8 @@ namespace v8 {
namespace internal {
struct BaseControllerTrait {
// Sizes are in MB.
static constexpr size_t kMinSize = 128 * Heap::kPointerMultiplier;
static constexpr size_t kMaxSize = 1024 * Heap::kPointerMultiplier;
static constexpr size_t kMinSize = 128u * Heap::kPointerMultiplier * MB;
static constexpr size_t kMaxSize = 1024u * Heap::kPointerMultiplier * MB;
static constexpr double kMinGrowingFactor = 1.1;
static constexpr double kMaxGrowingFactor = 4.0;
......
......@@ -207,23 +207,37 @@ size_t Heap::MaxReserved() {
max_old_generation_size_);
}
size_t Heap::ComputeMaxOldGenerationSize(uint64_t physical_memory) {
const size_t old_space_physical_memory_factor = 4;
size_t computed_size = static_cast<size_t>(physical_memory / i::MB /
old_space_physical_memory_factor *
kPointerMultiplier);
size_t max_size_in_mb = V8HeapTrait::kMaxSize;
void Heap::ComputeMaxSpaceSizes(uint64_t physical_memory,
size_t* old_space_size,
size_t* semi_space_size) {
// Compute the old space size and cap it.
uint64_t old_space =
physical_memory / kPhysicalMemoryToOldSpaceRatio * kPointerMultiplier;
uint64_t max_size = V8HeapTrait::kMaxSize;
// Finch experiment: Increase the heap size from 2GB to 4GB for 64-bit
// systems with physical memory bigger than 16GB.
constexpr bool x64_bit = Heap::kPointerMultiplier >= 2;
if (FLAG_huge_max_old_generation_size && x64_bit &&
physical_memory / GB > 16) {
DCHECK_LE(max_size_in_mb, 4096);
max_size_in_mb = 4096; // 4GB
DCHECK_EQ(max_size / GB, 2048);
max_size *= 2;
}
old_space = Min<uint64_t>(old_space, max_size);
old_space = Max<uint64_t>(old_space, V8HeapTrait::kMinSize);
old_space = RoundUp(old_space, Page::kPageSize);
// Compute the semi space size and cap it.
size_t ratio = physical_memory <= kLowMemory
? kOldSpaceToSemiSpaceRatioLowMemory
: kOldSpaceToSemiSpaceRatio;
uint64_t semi_space = old_space / ratio;
semi_space = Min<uint64_t>(semi_space, kMaxSemiSpaceSize);
semi_space = Max<uint64_t>(semi_space, kMinSemiSpaceSize);
semi_space = RoundUp(semi_space, Page::kPageSize);
return Max(Min(computed_size, max_size_in_mb), V8HeapTrait::kMinSize);
// Write the results back.
*old_space_size = static_cast<size_t>(old_space);
*semi_space_size = static_cast<size_t>(semi_space);
}
size_t Heap::Capacity() {
......@@ -4299,7 +4313,7 @@ void Heap::ConfigureHeap(size_t max_semi_space_size_in_kb,
max_semi_space_size_ = static_cast<size_t>(base::bits::RoundUpToPowerOfTwo64(
static_cast<uint64_t>(max_semi_space_size_)));
if (max_semi_space_size_ == kMaxSemiSpaceSizeInKB * KB) {
if (max_semi_space_size_ == kMaxSemiSpaceSize) {
// Start with at least 1*MB semi-space on machines with a lot of memory.
initial_semispace_size_ =
Max(initial_semispace_size_, static_cast<size_t>(1 * MB));
......
......@@ -250,12 +250,16 @@ class Heap {
static const size_t kMaxInitialOldGenerationSize =
256 * MB * kPointerMultiplier;
// Semi-space size needs to be a multiple of page size.
static const size_t kMinSemiSpaceSizeInKB = 512 * kPointerMultiplier;
static const size_t kMaxSemiSpaceSizeInKB = 8192 * kPointerMultiplier;
// These constants control heap configuration based on the physical memory.
static const size_t kPhysicalMemoryToOldSpaceRatio = 4;
static const size_t kOldSpaceToSemiSpaceRatio = 128;
static const size_t kOldSpaceToSemiSpaceRatioLowMemory = 256;
static const size_t kLowMemory = 512 * MB;
static const size_t kMinSemiSpaceSize = 512 * KB * kPointerMultiplier;
static const size_t kMaxSemiSpaceSize = 8192 * KB * kPointerMultiplier;
STATIC_ASSERT(kMinSemiSpaceSizeInKB* KB % (1 << kPageSizeBits) == 0);
STATIC_ASSERT(kMaxSemiSpaceSizeInKB* KB % (1 << kPageSizeBits) == 0);
STATIC_ASSERT(kMinSemiSpaceSize % (1 << kPageSizeBits) == 0);
STATIC_ASSERT(kMaxSemiSpaceSize % (1 << kPageSizeBits) == 0);
static const int kTraceRingBufferSize = 512;
static const int kStacktraceBufferSize = 512;
......@@ -1042,23 +1046,9 @@ class Heap {
size_t InitialSemiSpaceSize() { return initial_semispace_size_; }
size_t MaxOldGenerationSize() { return max_old_generation_size_; }
V8_EXPORT_PRIVATE static size_t ComputeMaxOldGenerationSize(
uint64_t physical_memory);
static size_t ComputeMaxSemiSpaceSize(uint64_t physical_memory) {
const uint64_t min_physical_memory = 512 * MB;
const uint64_t max_physical_memory = 3 * static_cast<uint64_t>(GB);
uint64_t capped_physical_memory =
Max(Min(physical_memory, max_physical_memory), min_physical_memory);
// linearly scale max semi-space size: (X-A)/(B-A)*(D-C)+C
size_t semi_space_size_in_kb =
static_cast<size_t>(((capped_physical_memory - min_physical_memory) *
(kMaxSemiSpaceSizeInKB - kMinSemiSpaceSizeInKB)) /
(max_physical_memory - min_physical_memory) +
kMinSemiSpaceSizeInKB);
return RoundUp(semi_space_size_in_kb, (1 << kPageSizeBits) / KB);
}
V8_EXPORT_PRIVATE static void ComputeMaxSpaceSizes(uint64_t physical_memory,
size_t* old_space_size,
size_t* semi_space_size);
// Returns the capacity of the heap in bytes w/o growing. Heap grows when
// more spaces are needed until it reaches the limit.
......@@ -1818,7 +1808,7 @@ class Heap {
size_t code_range_size_ = 0;
size_t max_semi_space_size_ = 8 * (kSystemPointerSize / 4) * MB;
size_t initial_semispace_size_ = kMinSemiSpaceSizeInKB * KB;
size_t initial_semispace_size_ = kMinSemiSpaceSize;
size_t max_old_generation_size_ = 700ul * (kSystemPointerSize / 4) * MB;
// TODO(mlippautz): Clarify whether this should be take some embedder
// configurable limit into account.
......
......@@ -53,15 +53,14 @@ TEST_F(MemoryControllerTest, HeapGrowingFactor) {
}
TEST_F(MemoryControllerTest, MaxHeapGrowingFactor) {
CheckEqualRounded(1.3,
V8Controller::MaxGrowingFactor(V8HeapTrait::kMinSize * MB));
CheckEqualRounded(
1.600, V8Controller::MaxGrowingFactor(V8HeapTrait::kMaxSize / 2 * MB));
CheckEqualRounded(
1.999, V8Controller::MaxGrowingFactor(
(V8HeapTrait::kMaxSize - Heap::kPointerMultiplier) * MB));
CheckEqualRounded(1.3, V8Controller::MaxGrowingFactor(V8HeapTrait::kMinSize));
CheckEqualRounded(1.600,
V8Controller::MaxGrowingFactor(V8HeapTrait::kMaxSize / 2));
CheckEqualRounded(2.0,
V8Controller::MaxGrowingFactor(
(V8HeapTrait::kMaxSize - Heap::kPointerMultiplier)));
CheckEqualRounded(4.0, V8Controller::MaxGrowingFactor(
static_cast<size_t>(V8HeapTrait::kMaxSize) * MB));
static_cast<size_t>(V8HeapTrait::kMaxSize)));
}
TEST_F(MemoryControllerTest, OldGenerationAllocationLimit) {
......@@ -99,21 +98,5 @@ TEST_F(MemoryControllerTest, OldGenerationAllocationLimit) {
factor, Heap::HeapGrowingMode::kMinimal));
}
TEST_F(MemoryControllerTest, MaxOldGenerationSize) {
uint64_t configurations[][2] = {
{0, V8HeapTrait::kMinSize},
{512, V8HeapTrait::kMinSize},
{1 * GB, 256 * Heap::kPointerMultiplier},
{2 * static_cast<uint64_t>(GB), 512 * Heap::kPointerMultiplier},
{4 * static_cast<uint64_t>(GB), V8HeapTrait::kMaxSize},
{8 * static_cast<uint64_t>(GB), V8HeapTrait::kMaxSize}};
for (auto configuration : configurations) {
ASSERT_EQ(configuration[1],
static_cast<uint64_t>(
Heap::ComputeMaxOldGenerationSize(configuration[0])));
}
}
} // namespace internal
} // namespace v8
......@@ -19,14 +19,37 @@ namespace internal {
using HeapTest = TestWithIsolate;
using HeapWithPointerCompressionTest = TestWithIsolateAndPointerCompression;
TEST(Heap, SemiSpaceSize) {
TEST(Heap, MaxSpaceSizes) {
const size_t MB = static_cast<size_t>(i::MB);
const size_t KB = static_cast<size_t>(i::KB);
const size_t pm = i::Heap::kPointerMultiplier;
ASSERT_EQ(512u * pm, i::Heap::ComputeMaxSemiSpaceSize(0u));
ASSERT_EQ(512u * pm, i::Heap::ComputeMaxSemiSpaceSize(512u * MB));
ASSERT_EQ(2048u * pm, i::Heap::ComputeMaxSemiSpaceSize(1024u * MB));
ASSERT_EQ(5120u * pm, i::Heap::ComputeMaxSemiSpaceSize(2024u * MB));
ASSERT_EQ(8192u * pm, i::Heap::ComputeMaxSemiSpaceSize(4095u * MB));
size_t old_space, semi_space;
i::Heap::ComputeMaxSpaceSizes(0u, &old_space, &semi_space);
ASSERT_EQ(128u * pm * MB, old_space);
ASSERT_EQ(512u * pm * KB, semi_space);
i::Heap::ComputeMaxSpaceSizes(512u * MB, &old_space, &semi_space);
ASSERT_EQ(128u * pm * MB, old_space);
ASSERT_EQ(512u * pm * KB, semi_space);
i::Heap::ComputeMaxSpaceSizes(1024u * MB, &old_space, &semi_space);
ASSERT_EQ(256u * pm * MB, old_space);
ASSERT_EQ(2048u * pm * KB, semi_space);
i::Heap::ComputeMaxSpaceSizes(2048u * MB, &old_space, &semi_space);
ASSERT_EQ(512u * pm * MB, old_space);
ASSERT_EQ(4096u * pm * KB, semi_space);
i::Heap::ComputeMaxSpaceSizes(static_cast<uint64_t>(4096u) * MB, &old_space,
&semi_space);
ASSERT_EQ(1024u * pm * MB, old_space);
ASSERT_EQ(8192u * pm * KB, semi_space);
i::Heap::ComputeMaxSpaceSizes(static_cast<uint64_t>(8192u) * MB, &old_space,
&semi_space);
ASSERT_EQ(1024u * pm * MB, old_space);
ASSERT_EQ(8192u * pm * KB, semi_space);
}
TEST_F(HeapTest, ASLR) {
......
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