Skip to content

Commit 500ea00

Browse files
neildharfacebook-github-bot
authored andcommitted
Make Hades YG 2MB
Summary: In order to reduce pause times, make the YG allocation area in Hades 2MB. There are a few additional considerations handled in this diff: 1. During YG promotion, keep the YG segment size as 4MB. This avoids wasting space in the OG by having partially full segments. There is also no pause time benefit to having 2MB YG in during promotion. 2. If we're making an allocation >2MB, temporarily increase the size of the YG. We can then adjust it back at the end of a YG collection. The alternative is to directly allocate that object in the OG, but I chose not to do that in the interest of minimising direct to OG allocations, particularly since this is such a rare case. 3. In future, we may want to adjust this size dynamically, based on the measured YG times. Then we could dynamically trade off the latency and throughput. Reviewed By: dulinriley Differential Revision: D27245952 fbshipit-source-id: 961daae111501b4c48ddb98a6888c2c532679f1b
1 parent ddf51ba commit 500ea00

3 files changed

Lines changed: 30 additions & 10 deletions

File tree

lib/VM/gcs/HadesGC.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ static const char *kGCName =
2929

3030
static const char *kCompacteeNameForCrashMgr = "COMPACT";
3131

32+
// Since YG collection times are the primary driver of pause times, it is useful
33+
// to have a knob to reduce the effective size of the YG. This can be any value
34+
// smaller than the segment size.
35+
// Note that we only set this at the end of the first real YG, since doing it
36+
// for direct promotions would waste OG memory without a pause time benefit.
37+
static constexpr size_t kYGSegmentSize = HadesGC::HeapSegment::maxSize() / 2;
38+
3239
// A free list cell is always variable-sized.
3340
const VTable HadesGC::OldGen::FreelistCell::vt{
3441
CellKind::FreelistKind,
@@ -2075,10 +2082,18 @@ bool HadesGC::isMostRecentFinalizableObj(const GCCell *cell) const {
20752082
#endif
20762083

20772084
void *HadesGC::allocSlow(uint32_t sz) {
2085+
AllocResult res;
20782086
// Failed to alloc in young gen, do a young gen collection.
20792087
youngGenCollection(
20802088
kNaturalCauseForAnalytics, /*forceOldGenCollection*/ false);
2081-
auto res = youngGen().bumpAlloc(sz);
2089+
res = youngGen().bumpAlloc(sz);
2090+
if (res.success)
2091+
return res.ptr;
2092+
2093+
// Still fails after YG collection, perhaps it is a large alloc, try growing
2094+
// the YG to full size.
2095+
youngGen().clearExternalMemoryCharge();
2096+
res = youngGen().bumpAlloc(sz);
20822097
if (res.success)
20832098
return res.ptr;
20842099

@@ -2399,9 +2414,15 @@ void HadesGC::youngGenCollection(
23992414
// Move external memory accounting from YG to OG as well.
24002415
transferExternalMemoryToOldGen();
24012416

2417+
// transferExternalMemoryToOldGen resets the effectiveEnd to be the end.
2418+
// Move the effectiveEnd back to represent the YG size. This also handles
2419+
// the case where we had to create a large alloc in the YG and increased the
2420+
// effectiveEnd. In the future, we could also use this line to dynamically
2421+
// size the YG based on pause times.
2422+
youngGen().setEffectiveEnd(youngGen().start() + kYGSegmentSize);
2423+
24022424
// We have to set these after the collection, in case a compaction took
2403-
// place
2404-
// and updated these metrics.
2425+
// place and updated these metrics.
24052426
ygCollectionStats_->setBeforeSizes(
24062427
heapBytes.before, externalBytes.before, heapFootprint());
24072428

test/hermes/set_regress.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
// RUN: %hermes -O -gc-sanitize-handles=0 -gc-max-heap=4M %s | %FileCheck --match-full-lines %s
8+
// RUN: %hermes -O -gc-sanitize-handles=0 -gc-max-heap=12M %s | %FileCheck --match-full-lines %s
99

1010
function testCompact() {
1111
print("testCompact");

unittests/VMRuntime/GCFragmentationTest.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ MetadataTableForTests getMetadataTable() {
5858
TEST(GCFragmentationTest, TestCoalescing) {
5959
// Fill the heap with increasingly larger cells, in order to test
6060
// defragmentation code.
61-
static const size_t kNumSegments = 3;
61+
static const size_t kNumSegments = 4;
62+
static const size_t kNumOGSegments = kNumSegments - 1;
6263
static const size_t kHeapSize = AlignedHeapSegment::maxSize() * kNumSegments;
6364
static const GCConfig kGCConfig = TestGCConfigFixedSize(kHeapSize);
6465

@@ -71,7 +72,7 @@ TEST(GCFragmentationTest, TestCoalescing) {
7172

7273
{
7374
GCScope scope(&rt);
74-
for (size_t i = 0; i < 16 * kNumSegments; i++)
75+
for (size_t i = 0; i < 16 * kNumOGSegments; i++)
7576
rt.makeHandle(SixteenthCell::create(rt));
7677
}
7778

@@ -83,19 +84,17 @@ TEST(GCFragmentationTest, TestCoalescing) {
8384

8485
{
8586
GCScope scope(&rt);
86-
for (size_t i = 0; i < 8 * kNumSegments; i++)
87+
for (size_t i = 0; i < 8 * kNumOGSegments; i++)
8788
rt.makeHandle(EighthCell::create(rt));
8889
}
8990

90-
rt.pointerRoots.clear();
91-
9291
#if defined(HERMESVM_GC_HADES) || defined(HERMESVM_GC_RUNTIME)
9392
rt.collect();
9493
#endif
9594

9695
{
9796
GCScope scope(&rt);
98-
for (size_t i = 0; i < 4 * kNumSegments; i++)
97+
for (size_t i = 0; i < 4 * kNumOGSegments; i++)
9998
rt.makeHandle(QuarterCell::create(rt));
10099
}
101100
}

0 commit comments

Comments
 (0)