Skip to content

Commit 2a8127d

Browse files
rmacnak-googlecommit-bot@chromium.org
authored andcommitted
[vm, gc] Take heap size into account when deciding when to start concurrent marking.
Begin concurrent marking when available space in old-space is less than 5% or than the size of new-space, whichever comes first. Avoids concurrent marking starting too late in larger heaps, where the program would exceed the hard threshold before concurrent marking would finish. Change-Id: I6a1991331a1450ffa647bf0e21dfc19e82537268 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/134466 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Siva Annamalai <[email protected]>
1 parent 0649115 commit 2a8127d

2 files changed

Lines changed: 66 additions & 41 deletions

File tree

runtime/vm/heap/pages.cc

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,8 +1038,10 @@ void PageSpace::CollectGarbage(bool compact, bool finalize) {
10381038
const int64_t pre_wait_for_sweepers = OS::GetCurrentMonotonicMicros();
10391039

10401040
// Wait for pending tasks to complete and then account for the driver task.
1041+
Phase waited_for;
10411042
{
10421043
MonitorLocker locker(tasks_lock());
1044+
waited_for = phase();
10431045
if (!finalize &&
10441046
(phase() == kMarking || phase() == kAwaitingFinalization)) {
10451047
// Concurrent mark is already running.
@@ -1054,6 +1056,16 @@ void PageSpace::CollectGarbage(bool compact, bool finalize) {
10541056
}
10551057

10561058
const int64_t pre_safe_point = OS::GetCurrentMonotonicMicros();
1059+
if (FLAG_verbose_gc) {
1060+
const int64_t wait = pre_safe_point - pre_wait_for_sweepers;
1061+
if (waited_for == kMarking) {
1062+
THR_Print("Waited %" Pd64 " us for concurrent marking to finish.\n",
1063+
wait);
1064+
} else if (waited_for == kSweepingRegular || waited_for == kSweepingLarge) {
1065+
THR_Print("Waited %" Pd64 " us for concurrent sweeping to finish.\n",
1066+
wait);
1067+
}
1068+
}
10571069

10581070
// Ensure that all threads for this isolate are at a safepoint (either
10591071
// stopped or in native code). We have guards around Newgen GC and oldgen GC
@@ -1483,9 +1495,8 @@ PageSpaceController::PageSpaceController(Heap* heap,
14831495
heap_growth_max_(heap_growth_max),
14841496
garbage_collection_time_ratio_(garbage_collection_time_ratio),
14851497
idle_gc_threshold_in_words_(0) {
1486-
intptr_t grow_heap = heap_growth_max / 2;
1487-
gc_threshold_in_words_ =
1488-
last_usage_.capacity_in_words + (kPageSizeInWords * grow_heap);
1498+
const intptr_t growth_in_pages = heap_growth_max / 2;
1499+
RecordUpdate(last_usage_, last_usage_, growth_in_pages, "initial");
14891500
}
14901501

14911502
PageSpaceController::~PageSpaceController() {}
@@ -1497,12 +1508,7 @@ bool PageSpaceController::NeedsGarbageCollection(SpaceUsage after) const {
14971508
if (heap_growth_ratio_ == 100) {
14981509
return false;
14991510
}
1500-
#if defined(TARGET_ARCH_IA32)
1501-
intptr_t headroom = 0;
1502-
#else
1503-
intptr_t headroom = heap_->new_space()->CapacityInWords();
1504-
#endif
1505-
return after.CombinedUsedInWords() > (gc_threshold_in_words_ + headroom);
1511+
return after.CombinedUsedInWords() > hard_gc_threshold_in_words_;
15061512
}
15071513

15081514
bool PageSpaceController::AlmostNeedsGarbageCollection(SpaceUsage after) const {
@@ -1512,7 +1518,7 @@ bool PageSpaceController::AlmostNeedsGarbageCollection(SpaceUsage after) const {
15121518
if (heap_growth_ratio_ == 100) {
15131519
return false;
15141520
}
1515-
return after.CombinedUsedInWords() > gc_threshold_in_words_;
1521+
return after.CombinedUsedInWords() > soft_gc_threshold_in_words_;
15161522
}
15171523

15181524
bool PageSpaceController::NeedsIdleGarbageCollection(SpaceUsage current) const {
@@ -1613,15 +1619,7 @@ void PageSpaceController::EvaluateGarbageCollection(SpaceUsage before,
16131619
heap_->RecordData(PageSpace::kAllowedGrowth, grow_heap);
16141620
last_usage_ = after;
16151621

1616-
// Save final threshold compared before growing.
1617-
gc_threshold_in_words_ =
1618-
after.CombinedUsedInWords() + (kPageSizeInWords * grow_heap);
1619-
1620-
// Set a tight idle threshold.
1621-
idle_gc_threshold_in_words_ =
1622-
after.CombinedUsedInWords() + (2 * kPageSizeInWords);
1623-
1624-
RecordUpdate(before, after, "gc");
1622+
RecordUpdate(before, after, grow_heap, "gc");
16251623
}
16261624

16271625
void PageSpaceController::EvaluateAfterLoading(SpaceUsage after) {
@@ -1637,38 +1635,57 @@ void PageSpaceController::EvaluateAfterLoading(SpaceUsage after) {
16371635
growth_in_pages =
16381636
Utils::Minimum(static_cast<intptr_t>(heap_growth_max_), growth_in_pages);
16391637

1638+
RecordUpdate(after, after, growth_in_pages, "loaded");
1639+
}
1640+
1641+
void PageSpaceController::RecordUpdate(SpaceUsage before,
1642+
SpaceUsage after,
1643+
intptr_t growth_in_pages,
1644+
const char* reason) {
16401645
// Save final threshold compared before growing.
1641-
gc_threshold_in_words_ =
1646+
hard_gc_threshold_in_words_ =
16421647
after.CombinedUsedInWords() + (kPageSizeInWords * growth_in_pages);
16431648

1649+
// Start concurrent marking when old-space has less than half of new-space
1650+
// available or less than 5% available.
1651+
#if defined(TARGET_ARCH_IA32)
1652+
const intptr_t headroom = 0; // No concurrent marking.
1653+
#else
1654+
// Note that heap_ can be null in some unit tests.
1655+
const intptr_t new_space =
1656+
heap_ == nullptr ? 0 : heap_->new_space()->CapacityInWords();
1657+
const intptr_t headroom =
1658+
Utils::Maximum(new_space / 2, hard_gc_threshold_in_words_ / 20);
1659+
#endif
1660+
soft_gc_threshold_in_words_ = hard_gc_threshold_in_words_ - headroom;
1661+
16441662
// Set a tight idle threshold.
16451663
idle_gc_threshold_in_words_ =
16461664
after.CombinedUsedInWords() + (2 * kPageSizeInWords);
16471665

1648-
RecordUpdate(after, after, "loaded");
1649-
}
1650-
1651-
void PageSpaceController::RecordUpdate(SpaceUsage before,
1652-
SpaceUsage after,
1653-
const char* reason) {
16541666
#if defined(SUPPORT_TIMELINE)
1655-
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "UpdateGrowthLimit");
1656-
tbes.SetNumArguments(5);
1657-
tbes.CopyArgument(0, "Reason", reason);
1658-
tbes.FormatArgument(1, "Before.CombinedUsed (kB)", "%" Pd "",
1659-
RoundWordsToKB(before.CombinedUsedInWords()));
1660-
tbes.FormatArgument(2, "After.CombinedUsed (kB)", "%" Pd "",
1661-
RoundWordsToKB(after.CombinedUsedInWords()));
1662-
tbes.FormatArgument(3, "Threshold (kB)", "%" Pd "",
1663-
RoundWordsToKB(gc_threshold_in_words_));
1664-
tbes.FormatArgument(4, "Idle Threshold (kB)", "%" Pd "",
1665-
RoundWordsToKB(idle_gc_threshold_in_words_));
1667+
Thread* thread = Thread::Current();
1668+
if (thread != nullptr) {
1669+
TIMELINE_FUNCTION_GC_DURATION(thread, "UpdateGrowthLimit");
1670+
tbes.SetNumArguments(6);
1671+
tbes.CopyArgument(0, "Reason", reason);
1672+
tbes.FormatArgument(1, "Before.CombinedUsed (kB)", "%" Pd "",
1673+
RoundWordsToKB(before.CombinedUsedInWords()));
1674+
tbes.FormatArgument(2, "After.CombinedUsed (kB)", "%" Pd "",
1675+
RoundWordsToKB(after.CombinedUsedInWords()));
1676+
tbes.FormatArgument(3, "Hard Threshold (kB)", "%" Pd "",
1677+
RoundWordsToKB(hard_gc_threshold_in_words_));
1678+
tbes.FormatArgument(4, "Soft Threshold (kB)", "%" Pd "",
1679+
RoundWordsToKB(soft_gc_threshold_in_words_));
1680+
tbes.FormatArgument(5, "Idle Threshold (kB)", "%" Pd "",
1681+
RoundWordsToKB(idle_gc_threshold_in_words_));
1682+
}
16661683
#endif
16671684

16681685
if (FLAG_log_growth) {
16691686
THR_Print("%s: threshold=%" Pd "kB, idle_threshold=%" Pd "kB, reason=%s\n",
16701687
heap_->isolate_group()->source()->name,
1671-
gc_threshold_in_words_ / KBInWords,
1688+
hard_gc_threshold_in_words_ / KBInWords,
16721689
idle_gc_threshold_in_words_ / KBInWords, reason);
16731690
}
16741691
}

runtime/vm/heap/pages.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,11 @@ class PageSpaceController {
242242
void RecordUpdate(SpaceUsage before, SpaceUsage after, const char* reason);
243243
void MergeOtherPageSpaceController(PageSpaceController* other);
244244

245+
void RecordUpdate(SpaceUsage before,
246+
SpaceUsage after,
247+
intptr_t growth_in_pages,
248+
const char* reason);
249+
245250
Heap* heap_;
246251

247252
bool is_enabled_;
@@ -264,10 +269,13 @@ class PageSpaceController {
264269
// we grow the heap more aggressively.
265270
const int garbage_collection_time_ratio_;
266271

267-
// Perform a GC when capacity exceeds this amount.
268-
intptr_t gc_threshold_in_words_;
272+
// Perform a stop-the-world GC when usage exceeds this amount.
273+
intptr_t hard_gc_threshold_in_words_;
274+
275+
// Begin concurrent marking when usage exceeds this amount.
276+
intptr_t soft_gc_threshold_in_words_;
269277

270-
// Start considering idle GC when capacity exceeds this amount.
278+
// Run idle GC if time permits when usage exceeds this amount.
271279
intptr_t idle_gc_threshold_in_words_;
272280

273281
PageSpaceGarbageCollectionHistory history_;

0 commit comments

Comments
 (0)