Skip to content

Commit 23192ad

Browse files
author
Zhengyu Gu
committed
Implementation of GC phase pause events
1 parent b39631a commit 23192ad

File tree

3 files changed

+142
-3
lines changed

3 files changed

+142
-3
lines changed

substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/GCImpl.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -207,6 +207,8 @@ private boolean collectImpl(GCCause cause, long requestingNanoTime, boolean forc
207207
precondition();
208208

209209
NoAllocationVerifier nav = noAllocationVerifier.open();
210+
211+
long startTicks = JfrGCEventSupport.startGCPhasePause();
210212
try {
211213
outOfMemory = doCollectImpl(cause, requestingNanoTime, forceFullGC, false);
212214
if (outOfMemory) {
@@ -219,6 +221,7 @@ private boolean collectImpl(GCCause cause, long requestingNanoTime, boolean forc
219221
}
220222
}
221223
} finally {
224+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), cause.getName(), startTicks);
222225
nav.close();
223226
}
224227

@@ -231,14 +234,19 @@ private boolean doCollectImpl(GCCause cause, long requestingNanoTime, boolean fo
231234

232235
boolean incremental = !forceNoIncremental && !policy.shouldCollectCompletely(false);
233236
boolean outOfMemory = false;
237+
234238
if (incremental) {
239+
long startTicks = JfrGCEventSupport.startGCPhasePause();
235240
outOfMemory = doCollectOnce(cause, requestingNanoTime, false, false);
241+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), "Incremental GC", startTicks);
236242
}
237243
if (!incremental || outOfMemory || forceFullGC || policy.shouldCollectCompletely(incremental)) {
238244
if (incremental) { // uncommit unaligned chunks
239245
CommittedMemoryProvider.get().afterGarbageCollection();
240246
}
247+
long startTicks = JfrGCEventSupport.startGCPhasePause();
241248
outOfMemory = doCollectOnce(cause, requestingNanoTime, true, incremental);
249+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), "Full GC", startTicks);
242250
}
243251

244252
HeapImpl.getChunkProvider().freeExcessAlignedChunks();
@@ -495,15 +503,18 @@ public boolean isCompleteCollection() {
495503
/** Scavenge, either from dirty roots or from all roots, and process discovered references. */
496504
private void scavenge(boolean incremental) {
497505
GreyToBlackObjRefVisitor.Counters counters = greyToBlackObjRefVisitor.openCounters();
506+
long startTicks;
498507
try {
499508
Timer rootScanTimer = timers.rootScan.open();
509+
startTicks = JfrGCEventSupport.startGCPhasePause();
500510
try {
501511
if (incremental) {
502512
cheneyScanFromDirtyRoots();
503513
} else {
504514
cheneyScanFromRoots();
505515
}
506516
} finally {
517+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), incremental ? "Incremental Scan Roots" : "Scan Roots", startTicks);
507518
rootScanTimer.close();
508519
}
509520

@@ -515,23 +526,28 @@ private void scavenge(boolean incremental) {
515526
* operation. To avoid side-effects between the code cache cleaning and the GC
516527
* core, it is crucial that all the GC core work finished before.
517528
*/
529+
startTicks = JfrGCEventSupport.startGCPhasePause();
518530
cleanRuntimeCodeCache();
519531
} finally {
532+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), "Clean Runtime CodeCache", startTicks);
520533
cleanCodeCacheTimer.close();
521534
}
522535
}
523536

524537
Timer referenceObjectsTimer = timers.referenceObjects.open();
525538
try {
539+
startTicks = JfrGCEventSupport.startGCPhasePause();
526540
Reference<?> newlyPendingList = ReferenceObjectProcessing.processRememberedReferences();
527541
HeapImpl.getHeapImpl().addToReferencePendingList(newlyPendingList);
528542
} finally {
543+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), "Process Remembered References", startTicks);
529544
referenceObjectsTimer.close();
530545
}
531546

532547
Timer releaseSpacesTimer = timers.releaseSpaces.open();
533548
try {
534549
assert chunkReleaser.isEmpty();
550+
startTicks = JfrGCEventSupport.startGCPhasePause();
535551
releaseSpaces();
536552

537553
/*
@@ -542,10 +558,13 @@ private void scavenge(boolean incremental) {
542558
boolean keepAllAlignedChunks = incremental;
543559
chunkReleaser.release(keepAllAlignedChunks);
544560
} finally {
561+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), "Release Spaces", startTicks);
545562
releaseSpacesTimer.close();
546563
}
547564

565+
startTicks = JfrGCEventSupport.startGCPhasePause();
548566
swapSpaces();
567+
JfrGCEventSupport.emitGCPhasePauseEvent(getCollectionEpoch(), "Swap Spaces", startTicks);
549568
} finally {
550569
counters.close();
551570
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2022, 2022, Red Hat Inc. All rights reserved.
4+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
*
6+
* This code is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 only, as
8+
* published by the Free Software Foundation. Oracle designates this
9+
* particular file as subject to the "Classpath" exception as provided
10+
* by Oracle in the LICENSE file that accompanied this code.
11+
*
12+
* This code is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15+
* version 2 for more details (a copy is included in the LICENSE file that
16+
* accompanied this code).
17+
*
18+
* You should have received a copy of the GNU General Public License version
19+
* 2 along with this work; if not, write to the Free Software Foundation,
20+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21+
*
22+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23+
* or visit www.oracle.com if you need additional information or have any
24+
* questions.
25+
*/
26+
package com.oracle.svm.core.genscavenge;
27+
28+
import org.graalvm.nativeimage.Platform;
29+
import org.graalvm.nativeimage.Platforms;
30+
import org.graalvm.nativeimage.StackValue;
31+
import org.graalvm.word.UnsignedWord;
32+
33+
import com.oracle.svm.core.annotate.Uninterruptible;
34+
import com.oracle.svm.core.jfr.JfrBuffer;
35+
import com.oracle.svm.core.jfr.JfrEnabled;
36+
import com.oracle.svm.core.jfr.JfrEvents;
37+
import com.oracle.svm.core.jfr.JfrNativeEventWriter;
38+
import com.oracle.svm.core.jfr.JfrNativeEventWriterData;
39+
import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess;
40+
import com.oracle.svm.core.jfr.JfrThreadLocal;
41+
import com.oracle.svm.core.jfr.JfrTicks;
42+
import com.oracle.svm.core.jfr.SubstrateJVM;
43+
import com.oracle.svm.core.util.VMError;
44+
45+
class JfrGCEventSupport {
46+
public static final int MAX_PHASE_LEVEL = 4;
47+
private static int currentPhase;
48+
49+
@Platforms(Platform.HOSTED_ONLY.class)
50+
JfrGCEventSupport() {
51+
}
52+
53+
public static long startGCPhasePause() {
54+
if (!JfrEnabled.get()) {
55+
return 0;
56+
}
57+
pushPausePhaseLevel();
58+
return JfrTicks.elapsedTicks();
59+
}
60+
61+
@Uninterruptible(reason = "Accesses a JFR buffer.")
62+
public static void emitGCPhasePauseEvent(UnsignedWord gcEpoch, String name, long startTicks) {
63+
if (!JfrEnabled.get()) {
64+
return;
65+
}
66+
67+
int level = popPausePhaseLevel();
68+
JfrEvents event = getGCPhasePauseEvent(level);
69+
if (SubstrateJVM.isRecording() && SubstrateJVM.get().isEnabled(event)) {
70+
long end = JfrTicks.elapsedTicks();
71+
JfrBuffer buffer = ((JfrThreadLocal) SubstrateJVM.getThreadLocal()).getNativeBuffer();
72+
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class);
73+
JfrNativeEventWriterDataAccess.initialize(data, buffer);
74+
75+
JfrNativeEventWriter.beginEventWrite(data, false);
76+
JfrNativeEventWriter.putLong(data, event.getId());
77+
JfrNativeEventWriter.putLong(data, startTicks);
78+
JfrNativeEventWriter.putLong(data, end - startTicks);
79+
JfrNativeEventWriter.putEventThread(data);
80+
JfrNativeEventWriter.putLong(data, gcEpoch.rawValue());
81+
JfrNativeEventWriter.putString(data, name);
82+
JfrNativeEventWriter.endEventWrite(data, false);
83+
}
84+
}
85+
86+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
87+
private static JfrEvents getGCPhasePauseEvent(int level) {
88+
switch (level) {
89+
case 0:
90+
return JfrEvents.GCPhasePauseEvent;
91+
case 1:
92+
return JfrEvents.GCPhasePauseLevel1Event;
93+
case 2:
94+
return JfrEvents.GCPhasePauseLevel2Event;
95+
case 3:
96+
return JfrEvents.GCPhasePauseLevel3Event;
97+
case 4:
98+
return JfrEvents.GCPhasePauseLevel4Event;
99+
default:
100+
throw VMError.shouldNotReachHere("At most " + MAX_PHASE_LEVEL + " levels");
101+
}
102+
}
103+
104+
private static void pushPausePhaseLevel() {
105+
assert currentPhase < MAX_PHASE_LEVEL;
106+
currentPhase++;
107+
}
108+
109+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
110+
private static int popPausePhaseLevel() {
111+
assert currentPhase > 0;
112+
currentPhase--;
113+
return currentPhase;
114+
}
115+
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/JfrEvents.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,12 @@ public enum JfrEvents {
5151
OSInformation("jdk.OSInformation"),
5252
PhysicalMemory("jdk.PhysicalMemory"),
5353
ExecutionSample("jdk.ExecutionSample"),
54-
NativeMethodSample("jdk.NativeMethodSample");
54+
NativeMethodSample("jdk.NativeMethodSample"),
55+
GCPhasePauseEvent("jdk.GCPhasePause"),
56+
GCPhasePauseLevel1Event("jdk.GCPhasePauseLevel1"),
57+
GCPhasePauseLevel2Event("jdk.GCPhasePauseLevel2"),
58+
GCPhasePauseLevel3Event("jdk.GCPhasePauseLevel3"),
59+
GCPhasePauseLevel4Event("jdk.GCPhasePauseLevel4");
5560

5661
private final long id;
5762

0 commit comments

Comments
 (0)