Skip to content

Commit f14b740

Browse files
authored
short circuit gen0 collection if surviving set is too large (VSadov#61)
1 parent b01b32a commit f14b740

File tree

2 files changed

+47
-17
lines changed

2 files changed

+47
-17
lines changed

src/coreclr/gc/satori/SatoriRegion.cpp

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,7 @@ void SatoriRegion::MarkFn(PTR_PTR_Object ppObject, ScanContext* sc, uint32_t fla
895895
if (!region->IsMarked(o))
896896
{
897897
region->SetMarked(o);
898+
region->m_occupancy += o->Size();
898899
region->PushToMarkStackIfHasPointers(o);
899900
}
900901

@@ -1081,7 +1082,11 @@ void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion*
10811082

10821083
bool SatoriRegion::ThreadLocalCollect(size_t allocBytes)
10831084
{
1084-
// TUNING: 1/4 is not too greedy? maybe 1/8 ?
1085+
if (m_escapedSize > Satori::MAX_ESCAPE_SIZE)
1086+
{
1087+
return false;
1088+
}
1089+
10851090
if (allocBytes - m_allocBytesAtCollect < Satori::REGION_SIZE_GRANULARITY / 4)
10861091
{
10871092
// this is too soon. last collection did not buy us as much as we wanted
@@ -1095,17 +1100,26 @@ bool SatoriRegion::ThreadLocalCollect(size_t allocBytes)
10951100
size_t count = Recycler()->IncrementGen0Count();
10961101
FIRE_EVENT(GCStart_V2, (int)count, 0, gc_reason::reason_alloc_soh, gc_etw_type_ngc);
10971102

1098-
ThreadLocalMark();
1099-
ThreadLocalPlan();
1100-
ThreadLocalUpdatePointers();
1101-
ThreadLocalCompact();
1103+
bool shouldCollect = ThreadLocalMark();
1104+
if (shouldCollect)
1105+
{
1106+
ThreadLocalPlan();
1107+
ThreadLocalUpdatePointers();
1108+
ThreadLocalCompact();
1109+
}
11021110

1103-
FIRE_EVENT(GCEnd_V1, (int)count, 0);
1111+
// schedule pending finalizables if we have them
1112+
// must be after compaction, since pend may escape objects.
1113+
if (HasPendingFinalizables())
1114+
{
1115+
ThreadLocalPendFinalizables();
1116+
}
11041117

1105-
return true;
1118+
FIRE_EVENT(GCEnd_V1, (int)count, 0);
1119+
return shouldCollect;
11061120
}
11071121

1108-
void SatoriRegion::ThreadLocalMark()
1122+
bool SatoriRegion::ThreadLocalMark()
11091123
{
11101124
Verify();
11111125

@@ -1156,6 +1170,18 @@ void SatoriRegion::ThreadLocalMark()
11561170
_ASSERTE(escaped == this->m_escapedSize);
11571171
#endif
11581172

1173+
// We expect high mortality rate of Gen0 objects.
1174+
// If surviving set is large, then collection will be more expensive with diminishing results.
1175+
// We will not continue with collection if we see that too much of thread local objects are alive.
1176+
// The criteria does not need to be very precise. (anything in the order of 1/8 and 1/16 seems
1177+
// to yield similar results)
1178+
const size_t maxSurv = Satori::REGION_SIZE_GRANULARITY / 8;
1179+
1180+
// Temporarily use m_occupancy to estimate surviving size.
1181+
// If we proceed with collection, m_occupancy will be recomputed anyways.
1182+
size_t uncollectedOccupancy = m_occupancy;
1183+
m_occupancy = 0;
1184+
11591185
// mark roots for the current stack
11601186
ScanContext sc;
11611187
sc.promotion = TRUE;
@@ -1170,7 +1196,7 @@ void SatoriRegion::ThreadLocalMark()
11701196
SatoriObject* o = PopFromMarkStack();
11711197

11721198
propagateMarks:
1173-
while (o)
1199+
while (o && m_occupancy < maxSurv)
11741200
{
11751201
_ASSERTE(IsMarked(o));
11761202
_ASSERTE(!IsEscaped(o));
@@ -1182,6 +1208,7 @@ void SatoriRegion::ThreadLocalMark()
11821208
if (child->SameRegion(this) && !IsMarked(child))
11831209
{
11841210
SetMarked(child);
1211+
m_occupancy += child->Size();
11851212
PushToMarkStackIfHasPointers(child);
11861213
}
11871214
},
@@ -1190,6 +1217,14 @@ void SatoriRegion::ThreadLocalMark()
11901217
o = PopFromMarkStack();
11911218
}
11921219

1220+
if (m_occupancy >= maxSurv)
1221+
{
1222+
// surviving set is too large.
1223+
while (PopFromMarkStack()){};
1224+
m_occupancy = uncollectedOccupancy;
1225+
return false;
1226+
}
1227+
11931228
if (checkFinalizables)
11941229
{
11951230
// unreachable finalizables:
@@ -1217,6 +1252,7 @@ void SatoriRegion::ThreadLocalMark()
12171252
{
12181253
// keep alive
12191254
SetMarked(finalizable);
1255+
m_occupancy += finalizable->Size();
12201256
PushToMarkStackIfHasPointers(finalizable);
12211257
(size_t&)finalizable |= Satori::FINALIZATION_PENDING;
12221258
HasPendingFinalizables() = true;
@@ -1236,6 +1272,7 @@ void SatoriRegion::ThreadLocalMark()
12361272
}
12371273

12381274
Verify(/*allowMarked*/ true);
1275+
return true;
12391276
}
12401277

12411278
void SatoriRegion::ThreadLocalPlan()
@@ -1608,13 +1645,6 @@ void SatoriRegion::ThreadLocalCompact()
16081645
}
16091646
}
16101647

1611-
// schedule pending finalizables if we have them
1612-
// must be after compaction, since pend may escape objects.
1613-
if (HasPendingFinalizables())
1614-
{
1615-
ThreadLocalPendFinalizables();
1616-
}
1617-
16181648
Verify();
16191649

16201650
_ASSERTE((Satori::REGION_SIZE_GRANULARITY - offsetof(SatoriRegion, m_firstObject) - foundFree) == m_occupancy);

src/coreclr/gc/satori/SatoriRegion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ bool TryDemote();
322322

323323
static void EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion* region);
324324

325-
void ThreadLocalMark();
325+
bool ThreadLocalMark();
326326
void ThreadLocalPlan();
327327
void ThreadLocalUpdatePointers();
328328
void ThreadLocalCompact();

0 commit comments

Comments
 (0)