Skip to content

Commit d04b0eb

Browse files
committed
VGC improvements for CS
Verbose GC improvements for Concurrent Scavenger. Now reporting gc-op for each of 3 phases of CS (2xSTW and one concurrent). Also introducing a wrapper stanza (concurrent-end) for concurrent scavenge gc-op: <concurrent-end id="12169" type="scavenge" contextid="12159" timestamp="2017-08-18T14:28:44.329"> <gc-op id="12170" type="scavenge" timems="19.722" contextid="12159" timestamp="2017-08-18T14:28:44.329"> <memory-copied type="nursery" objects="9888" bytes="450472" bytesdiscarded="7816" /> <memory-copied type="tenure" objects="64" bytes="2256" bytesdiscarded="4112" /> </gc-op> </concurrent-end> In future, this wrapper may report some concurrent specific data of scavenge (that gc-op does not report), like read barrier counts. Signed-off-by: Aleksandar Micic <amicic@ca.ibm.com>
1 parent e8c5419 commit d04b0eb

10 files changed

+276
-73
lines changed

gc/base/Collector.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
class MM_AllocateDescription;
3131
class MM_AllocationContext;
3232
class MM_CollectorLanguageInterface;
33-
class MM_ConcurrentGMPStats;
33+
class MM_ConcurrentPhaseStatsBase;
3434
class MM_MemoryPool;
3535
class MM_ObjectAllocationInterface;
3636
class MM_MemorySubSpace;
@@ -275,11 +275,15 @@ class MM_Collector : public MM_BaseVirtual
275275
virtual void preMasterGCThreadInitialize(MM_EnvironmentBase *env) {}
276276
virtual void masterThreadGarbageCollect(MM_EnvironmentBase *env, MM_AllocateDescription *allocDescription, bool initMarkMap = false, bool rebuildMarkBits = false) {}
277277
virtual bool isConcurrentWorkAvailable(MM_EnvironmentBase *env) { return false; }
278-
virtual void preConcurrentInitializeStatsAndReport(MM_EnvironmentBase *env, MM_ConcurrentGMPStats *stats) {}
278+
virtual void preConcurrentInitializeStatsAndReport(MM_EnvironmentBase *env, MM_ConcurrentPhaseStatsBase *stats) {}
279279
virtual uintptr_t masterThreadConcurrentCollect(MM_EnvironmentBase *env) { return 0; }
280-
virtual void postConcurrentUpdateStatsAndReport(MM_EnvironmentBase *env, MM_ConcurrentGMPStats *stats, UDATA bytesConcurrentlyScanned) {}
280+
virtual void postConcurrentUpdateStatsAndReport(MM_EnvironmentBase *env, MM_ConcurrentPhaseStatsBase *stats, UDATA bytesConcurrentlyScanned) {}
281281
virtual void forceConcurrentFinish() {}
282282
virtual void completeExternalConcurrentCycle(MM_EnvironmentBase *env) {}
283+
/**
284+
* @return pointer to collector/phase specific concurrent stats structure
285+
*/
286+
virtual MM_ConcurrentPhaseStatsBase *getConcurrentPhaseStats() { return NULL; }
283287

284288
MM_Collector(MM_CollectorLanguageInterface *cli)
285289
: MM_BaseVirtual()

gc/base/MasterGCThread.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ MM_MasterGCThread::masterThreadEntryPoint()
181181

182182
_collector->preMasterGCThreadInitialize(env);
183183

184+
MM_ConcurrentPhaseStatsBase *stats = _collector->getConcurrentPhaseStats();
185+
184186
/* first, notify the thread that started us that we are ready to enter the waiting state */
185187
_masterThreadState = STATE_WAITING;
186188
_masterGCThread = omrthread_self();
@@ -222,13 +224,12 @@ MM_MasterGCThread::masterThreadEntryPoint()
222224
if (_collector->isConcurrentWorkAvailable(env)) {
223225
_masterThreadState = STATE_RUNNING_CONCURRENT;
224226
// todo: remove this VLHGC specific structure
225-
MM_ConcurrentGMPStats stats;
226-
_collector->preConcurrentInitializeStatsAndReport(env, &stats);
227+
_collector->preConcurrentInitializeStatsAndReport(env, stats);
227228
/* ensure that we get out of this monitor so that the mutator can wake up */
228229
omrthread_monitor_exit(_collectorControlMutex);
229230
uintptr_t bytesConcurrentlyScanned = _collector->masterThreadConcurrentCollect(env);
230231
omrthread_monitor_enter(_collectorControlMutex);
231-
_collector->postConcurrentUpdateStatsAndReport(env, &stats, bytesConcurrentlyScanned);
232+
_collector->postConcurrentUpdateStatsAndReport(env, stats, bytesConcurrentlyScanned);
232233
if (STATE_RUNNING_CONCURRENT == _masterThreadState) {
233234
/* we are still in the concurrent state (might have changed if a GC was requested) so set it back to waiting */
234235
_masterThreadState = STATE_WAITING;

gc/base/omrmmprivate.hdf

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
<data type="uint64_t" name="timestamp" description="time of event" />
157157
<data type="uintptr_t" name="eventid" description="unique identifier for event" />
158158
<data type="void*" name="subSpace" description="the subspace which was collected" />
159+
<data type="bool" name="cycleEnd" description="true, if last GC increment in a cycle" />
159160
</event>
160161

161162
<event>
@@ -974,29 +975,29 @@
974975
</event>
975976

976977
<event>
977-
<name>J9HOOK_MM_PRIVATE_CONCURRENT_GMP_START</name>
978+
<name>J9HOOK_MM_PRIVATE_CONCURRENT_PHASE_START</name>
978979
<description>
979-
Triggered when concurrent GMP work begins.
980+
Triggered when concurrent phase work begins.
980981
NOTE: Only expected to be used by verbose GC output.
981982
</description>
982-
<struct>MM_ConcurrentGMPStartEvent</struct>
983+
<struct>MM_ConcurrentPhaseStartEvent</struct>
983984
<data type="struct OMR_VMThread*" name="currentThread" description="current thread" />
984985
<data type="uint64_t" name="timestamp" description="time of event" />
985986
<data type="uintptr_t" name="eventid" description="unique identifier for event" />
986-
<data type="void *" name="concurrentGMPStats" description="internal statistics for concurrent GMP" />
987+
<data type="void *" name="concurrentStats" description="internal statistics for concurrent phase" />
987988
</event>
988989

989-
<event>
990-
<name>J9HOOK_MM_PRIVATE_CONCURRENT_GMP_END</name>
990+
<event>
991+
<name>J9HOOK_MM_PRIVATE_CONCURRENT_PHASE_END</name>
991992
<description>
992-
Triggered when concurrent GMP work ends.
993+
Triggered when concurrent phase work ends.
993994
NOTE: Only expected to be used by verbose GC output.
994995
</description>
995-
<struct>MM_ConcurrentGMPEndEvent</struct>
996+
<struct>MM_ConcurrentPhaseEndEvent</struct>
996997
<data type="struct OMR_VMThread*" name="currentThread" description="current thread" />
997998
<data type="uint64_t" name="timestamp" description="time of event" />
998999
<data type="uintptr_t" name="eventid" description="unique identifier for event" />
999-
<data type="void *" name="concurrentGMPStats" description="internal statistics for concurrent GMP" />
1000+
<data type="void *" name="concurrentStats" description="internal statistics for concurrent phase" />
10001001
</event>
10011002

10021003
<event>

gc/base/standard/Scavenger.cpp

Lines changed: 83 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ void
407407
MM_Scavenger::workerSetupForGC(MM_EnvironmentStandard *env)
408408
{
409409
/* Clear local stats */
410-
memset((void *)&(env->_scavengerStats), 0, sizeof(MM_ScavengerStats));
410+
env->_scavengerStats.clear();
411411

412412
/* Clear the worker hot field statistics */
413413
clearHotFieldStats(env);
@@ -469,7 +469,7 @@ MM_Scavenger::reportScavengeStart(MM_EnvironmentStandard *env)
469469
}
470470

471471
void
472-
MM_Scavenger::reportScavengeEnd(MM_EnvironmentStandard *env)
472+
MM_Scavenger::reportScavengeEnd(MM_EnvironmentStandard *env, bool lastIncrement)
473473
{
474474
OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());
475475

@@ -485,7 +485,8 @@ MM_Scavenger::reportScavengeEnd(MM_EnvironmentStandard *env)
485485
env->getOmrVMThread(),
486486
omrtime_hires_clock(),
487487
J9HOOK_MM_PRIVATE_SCAVENGE_END,
488-
env->_cycleState->_activeSubSpace
488+
env->_cycleState->_activeSubSpace,
489+
lastIncrement
489490
);
490491
}
491492

@@ -647,7 +648,7 @@ MM_Scavenger::mergeHotFieldStats(MM_EnvironmentStandard *env)
647648
* Clear any global stats associated to the scavenger.
648649
*/
649650
void
650-
MM_Scavenger::clearGCStats(MM_EnvironmentStandard *env)
651+
MM_Scavenger::clearGCStats(MM_EnvironmentBase *env)
651652
{
652653
_extensions->scavengerStats.clear();
653654
}
@@ -656,7 +657,7 @@ MM_Scavenger::clearGCStats(MM_EnvironmentStandard *env)
656657
* Merge the current threads scavenge stats into the global scavenge stats.
657658
*/
658659
void
659-
MM_Scavenger::mergeGCStats(MM_EnvironmentStandard *env)
660+
MM_Scavenger::mergeGCStats(MM_EnvironmentBase *env)
660661
{
661662
OMRPORT_ACCESS_FROM_OMRVM(_omrVM);
662663

@@ -3477,19 +3478,12 @@ MM_Scavenger::masterThreadGarbageCollect(MM_EnvironmentBase *envBase, MM_Allocat
34773478
}
34783479

34793480
reportGCCycleStart(env);
3481+
masterSetupForGC(env);
34803482
}
34813483
reportGCStart(env);
34823484
reportGCIncrementStart(env);
3483-
#if defined(OMR_GC_CONCURRENT_SCAVENGER)
3484-
if (!isConcurrentInProgress())
3485-
#endif
3486-
{
3487-
reportScavengeStart(env);
3488-
3489-
_extensions->scavengerStats._startTime = omrtime_hires_clock();
3490-
3491-
masterSetupForGC(env);
3492-
}
3485+
reportScavengeStart(env);
3486+
_extensions->scavengerStats._startTime = omrtime_hires_clock();
34933487

34943488
#if defined(OMR_GC_CONCURRENT_SCAVENGER)
34953489
if (_extensions->concurrentScavenger) {
@@ -3500,18 +3494,18 @@ MM_Scavenger::masterThreadGarbageCollect(MM_EnvironmentBase *envBase, MM_Allocat
35003494
scavenge(env);
35013495
}
35023496

3497+
_extensions->scavengerStats._endTime = omrtime_hires_clock();
35033498
#if defined(OMR_GC_CONCURRENT_SCAVENGER)
3504-
if (!isConcurrentInProgress())
3499+
if (isConcurrentInProgress()) {
3500+
reportScavengeEnd(env, false);
3501+
} else
35053502
#endif
35063503
{
3504+
reportScavengeEnd(env, true);
3505+
35073506
/* defer to collector language interface */
35083507
_cli->scavenger_masterThreadGarbageCollect_scavengeComplete(env);
35093508

3510-
/* Record the completion time of the scavenge */
3511-
_extensions->scavengerStats._endTime = omrtime_hires_clock();
3512-
3513-
reportScavengeEnd(env);
3514-
35153509
/* Reset the resizable flag of the semi space.
35163510
* NOTE: Must be done before we attempt to resize the new space.
35173511
*/
@@ -3786,19 +3780,28 @@ MM_Scavenger::getCollectorExpandSize(MM_EnvironmentBase *env)
37863780
void
37873781
MM_Scavenger::internalPreCollect(MM_EnvironmentBase *env, MM_MemorySubSpace *subSpace, MM_AllocateDescription *allocDescription, uint32_t gcCode)
37883782
{
3789-
_cycleState = MM_CycleState();
37903783
env->_cycleState = &_cycleState;
3791-
env->_cycleState->_gcCode = MM_GCCode(gcCode);
3792-
env->_cycleState->_type = _cycleType;
3793-
env->_cycleState->_collectionStatistics = &_collectionStatistics;
37943784

3795-
/* If we are in an excessiveGC level beyond normal then an aggressive GC is
3796-
* conducted to free up as much space as possible
3785+
#if defined(OMR_GC_CONCURRENT_SCAVENGER)
3786+
/* Cycle state is initialized only once at the beginning of a cycle. We do not want, in mid-end cycle phases, to reset some members
3787+
* that are initialized at the beginning (such as verboseContextID).
37973788
*/
3798-
if (!env->_cycleState->_gcCode.isExplicitGC()) {
3799-
if(excessive_gc_normal != _extensions->excessiveGCLevel) {
3800-
/* convert the current mode to excessive GC mode */
3801-
env->_cycleState->_gcCode = MM_GCCode(J9MMCONSTANT_IMPLICIT_GC_EXCESSIVE);
3789+
if (!isConcurrentInProgress())
3790+
#endif
3791+
{
3792+
_cycleState = MM_CycleState();
3793+
_cycleState._gcCode = MM_GCCode(gcCode);
3794+
_cycleState._type = _cycleType;
3795+
_cycleState._collectionStatistics = &_collectionStatistics;
3796+
3797+
/* If we are in an excessiveGC level beyond normal then an aggressive GC is
3798+
* conducted to free up as much space as possible
3799+
*/
3800+
if (!_cycleState._gcCode.isExplicitGC()) {
3801+
if(excessive_gc_normal != _extensions->excessiveGCLevel) {
3802+
/* convert the current mode to excessive GC mode */
3803+
_cycleState._gcCode = MM_GCCode(J9MMCONSTANT_IMPLICIT_GC_EXCESSIVE);
3804+
}
38023805
}
38033806
}
38043807

@@ -3814,7 +3817,7 @@ MM_Scavenger::internalPostCollect(MM_EnvironmentBase *env, MM_MemorySubSpace *su
38143817
{
38153818
calcGCStats((MM_EnvironmentStandard*)env);
38163819

3817-
return ;
3820+
Assert_MM_true(env->_cycleState == &_cycleState);
38183821
}
38193822

38203823
/**
@@ -4535,6 +4538,8 @@ MM_Scavenger::scavengeComplete(MM_EnvironmentBase *envBase)
45354538

45364539
Assert_MM_true(concurrent_state_complete == _concurrentState);
45374540

4541+
clearGCStats(env);
4542+
45384543
GC_OMRVMThreadListIterator threadIterator(_extensions->getOmrVM());
45394544
OMR_VMThread *walkThread = NULL;
45404545

@@ -4597,7 +4602,7 @@ MM_Scavenger::scavengeIncremental(MM_EnvironmentBase *env)
45974602
case concurrent_state_scan:
45984603
{
45994604
/* This is just for corner cases that must be run in STW mode.
4600-
* Default main scan phase is done by scavengeConcurrent. */
4605+
* Default main scan phase is done within masterThreadConcurrentCollect. */
46014606

46024607
timeout = scavengeScan(env);
46034608

@@ -4639,24 +4644,34 @@ MM_Scavenger::workThreadProcessRoots(MM_EnvironmentStandard *env)
46394644
rootScanner.scavengeRememberedSet(env);
46404645

46414646
rootScanner.scanRoots(env);
4647+
4648+
mergeGCStats(env);
46424649
}
46434650

46444651
void
46454652
MM_Scavenger::workThreadScan(MM_EnvironmentStandard *env)
46464653
{
4654+
/* Clear thread local stats */
4655+
env->_scavengerStats.clear();
4656+
46474657
completeScan(env);
46484658
// todo: are these two steps really necessary?
46494659
// we probably have to clear all things for master since it'll be doing final release/clear on behalf of mutator threads
46504660
// but is it really needed for slaves as well?
46514661
addCopyCachesToFreeList(env);
46524662
abandonTLHRemainders(env);
4663+
4664+
mergeGCStats(env);
46534665
}
46544666

46554667
void
46564668
MM_Scavenger::workThreadComplete(MM_EnvironmentStandard *env)
46574669
{
46584670
Assert_MM_true(_extensions->concurrentScavenger);
46594671

4672+
/* Clear thread local stats */
4673+
env->_scavengerStats.clear();
4674+
46604675
MM_ScavengerRootScanner rootScanner(env, this);
46614676

46624677
/* Complete scan loop regardless if we already aborted. If so, the scan operation will just fix up pointers that still point to forwarded objects.
@@ -4703,46 +4718,62 @@ MM_Scavenger::workThreadComplete(MM_EnvironmentStandard *env)
47034718
}
47044719

47054720
uintptr_t
4706-
MM_Scavenger::scavengeConcurrent(MM_EnvironmentBase *env, UDATA totalBytesToScavenge, volatile bool *forceExit)
4721+
MM_Scavenger::masterThreadConcurrentCollect(MM_EnvironmentBase *env)
47074722
{
47084723
Assert_MM_true(concurrent_state_scan == _concurrentState);
47094724

4710-
MM_ConcurrentScavengeTask scavengeTask(env, _dispatcher, this, MM_ConcurrentScavengeTask::SCAVENGE_SCAN, totalBytesToScavenge, forceExit, env->_cycleState);
4725+
clearGCStats(env);
4726+
4727+
MM_ConcurrentScavengeTask scavengeTask(env, _dispatcher, this, MM_ConcurrentScavengeTask::SCAVENGE_SCAN, UDATA_MAX, &_forceConcurrentTermination, env->_cycleState);
47114728
/* Concurrent background task will run with different (typically lower) number of threads. */
47124729
_dispatcher->run(env, &scavengeTask, _extensions->concurrentScavengerBackgroundThreads);
47134730

4714-
uintptr_t bytesScanned = scavengeTask.getBytesScanned();
47154731
/* we can't assert the work queue is empty. some mutator threads could have just flushed their copy caches, after the task terminated */
47164732
_concurrentState = concurrent_state_complete;
47174733
/* make allocate space non-allocatable to trigger the final GC phase */
47184734
_activeSubSpace->flip(env, MM_MemorySubSpaceSemiSpace::disable_allocation);
47194735

4720-
return bytesScanned;
4736+
/* return the number of bytes scanned since the caller needs to pass it into postConcurrentUpdateStatsAndReport for stats reporting */
4737+
return scavengeTask.getBytesScanned();
47214738
}
47224739

4723-
uintptr_t
4724-
MM_Scavenger::masterThreadConcurrentCollect(MM_EnvironmentBase *env)
4740+
void MM_Scavenger::preConcurrentInitializeStatsAndReport(MM_EnvironmentBase *env, MM_ConcurrentPhaseStatsBase *stats)
47254741
{
4726-
/* note that we can't check isConcurrentWorkAvailable at this point since another thread could have set _forceConcurrentTermination since the
4727-
* master thread calls this outside of the control monitor
4728-
*/
4742+
OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());
47294743
Assert_MM_true(NULL == env->_cycleState);
4730-
Assert_MM_true(concurrent_state_scan == _concurrentState);
4731-
47324744
env->_cycleState = &_cycleState;
47334745

4734-
/* We pass a pointer to _forceConcurrentTermination so that we can cause the concurrent to terminate early by setting the
4735-
* flag to true if we want to interrupt it so that the master thread returns to the control mutex in order to receive a
4736-
* new GC request.
4737-
*/
4738-
uintptr_t bytesConcurrentlyScanned = scavengeConcurrent(env, 100000, &_forceConcurrentTermination);
4746+
stats->_cycleID = _cycleState._verboseContextID;
47394747

4740-
env->_cycleState = NULL;
4748+
TRIGGER_J9HOOK_MM_PRIVATE_CONCURRENT_PHASE_START(
4749+
_extensions->privateHookInterface,
4750+
env->getOmrVMThread(),
4751+
omrtime_hires_clock(),
4752+
J9HOOK_MM_PRIVATE_CONCURRENT_PHASE_START,
4753+
stats);
47414754

4742-
/* return the number of bytes scanned since the caller needs to pass it into postConcurrentUpdateStatsAndReport for stats reporting */
4743-
return bytesConcurrentlyScanned;
4755+
_extensions->scavengerStats._startTime = omrtime_hires_clock();
47444756
}
47454757

4758+
void MM_Scavenger::postConcurrentUpdateStatsAndReport(MM_EnvironmentBase *env, MM_ConcurrentPhaseStatsBase *stats, UDATA bytesConcurrentlyScanned)
4759+
{
4760+
OMRPORT_ACCESS_FROM_OMRPORT(env->getPortLibrary());
4761+
4762+
stats->_terminationWasRequested = _forceConcurrentTermination;
4763+
4764+
_extensions->scavengerStats._endTime = omrtime_hires_clock();
4765+
4766+
TRIGGER_J9HOOK_MM_PRIVATE_CONCURRENT_PHASE_END(
4767+
_extensions->privateHookInterface,
4768+
env->getOmrVMThread(),
4769+
omrtime_hires_clock(),
4770+
J9HOOK_MM_PRIVATE_CONCURRENT_PHASE_END,
4771+
stats);
4772+
4773+
env->_cycleState = NULL;
4774+
}
4775+
4776+
47464777
void
47474778
MM_Scavenger::switchConcurrentForThread(MM_EnvironmentBase *env)
47484779
{

0 commit comments

Comments
 (0)