Skip to content

Commit 71c6ad2

Browse files
Remove internal frames from the top of JFR event stacktraces.
1 parent 32ce531 commit 71c6ad2

20 files changed

+193
-160
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/VMInspectionOptions.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,6 @@ public final class VMInspectionOptions {
8585
AccumulatingLocatableMultiOptionValue.Strings.buildWithCommaDelimiter(),
8686
VMInspectionOptions::validateEnableMonitoringFeatures);
8787

88-
@Option(help = "Determine whether to trim internal frames from JFR stacktraces (defaults to true).")//
89-
public static final HostedOptionKey<Boolean> JfrTrimInternalStackTraces = new HostedOptionKey<>(true, VMInspectionOptions::notSupportedOnWindows);
90-
9188
@Option(help = "Dumps all runtime compiled methods on SIGUSR2.", type = OptionType.User) //
9289
public static final HostedOptionKey<Boolean> DumpRuntimeCompilationOnSignal = new HostedOptionKey<>(false, VMInspectionOptions::notSupportedOnWindows);
9390

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

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,13 @@
3232
import com.oracle.svm.core.Uninterruptible;
3333
import com.oracle.svm.core.collections.EnumBitmask;
3434
import com.oracle.svm.core.thread.JavaThreads;
35-
import com.oracle.svm.core.VMInspectionOptions;
3635

3736
/**
3837
* This file contains the VM-level events that Native Image supports on all JDK versions. The event
3938
* IDs depend on the JDK version (see metadata.xml file) and are computed at image build time.
4039
*/
4140
public final class JfrEvent {
42-
private static final int defaultInternalSkipCount = VMInspectionOptions.JfrTrimInternalStackTraces.getValue() ? 5 : 0;
43-
public static final JfrEvent ThreadStart = create("jdk.ThreadStart", defaultInternalSkipCount - 1);
41+
public static final JfrEvent ThreadStart = create("jdk.ThreadStart", 4);
4442
public static final JfrEvent ThreadEnd = create("jdk.ThreadEnd");
4543
public static final JfrEvent ThreadCPULoad = create("jdk.ThreadCPULoad");
4644
public static final JfrEvent DataLoss = create("jdk.DataLoss");
@@ -62,17 +60,17 @@ public final class JfrEvent {
6260
public static final JfrEvent SafepointBegin = create("jdk.SafepointBegin", JfrEventFlags.HasDuration);
6361
public static final JfrEvent SafepointEnd = create("jdk.SafepointEnd", JfrEventFlags.HasDuration);
6462
public static final JfrEvent ExecuteVMOperation = create("jdk.ExecuteVMOperation", JfrEventFlags.HasDuration);
65-
public static final JfrEvent JavaMonitorEnter = create("jdk.JavaMonitorEnter", JfrEventFlags.HasDuration);
66-
public static final JfrEvent ThreadPark = create("jdk.ThreadPark", JfrEventFlags.HasDuration);
67-
public static final JfrEvent JavaMonitorWait = create("jdk.JavaMonitorWait", JfrEventFlags.HasDuration);
68-
public static final JfrEvent JavaMonitorInflate = create("jdk.JavaMonitorInflate", JfrEventFlags.HasDuration);
69-
public static final JfrEvent ObjectAllocationInNewTLAB = create("jdk.ObjectAllocationInNewTLAB");
63+
public static final JfrEvent JavaMonitorEnter = create("jdk.JavaMonitorEnter", 5, JfrEventFlags.HasDuration);
64+
public static final JfrEvent ThreadPark = create("jdk.ThreadPark", 5, JfrEventFlags.HasDuration);
65+
public static final JfrEvent JavaMonitorWait = create("jdk.JavaMonitorWait", 5, JfrEventFlags.HasDuration);
66+
public static final JfrEvent JavaMonitorInflate = create("jdk.JavaMonitorInflate", 5, JfrEventFlags.HasDuration);
67+
public static final JfrEvent ObjectAllocationInNewTLAB = create("jdk.ObjectAllocationInNewTLAB", 5);
7068
public static final JfrEvent GCHeapSummary = create("jdk.GCHeapSummary");
7169
public static final JfrEvent ThreadAllocationStatistics = create("jdk.ThreadAllocationStatistics");
72-
public static final JfrEvent SystemGC = create("jdk.SystemGC", JfrEventFlags.HasDuration);
73-
public static final JfrEvent AllocationRequiringGC = create("jdk.AllocationRequiringGC");
70+
public static final JfrEvent SystemGC = create("jdk.SystemGC", 5, JfrEventFlags.HasDuration);
71+
public static final JfrEvent AllocationRequiringGC = create("jdk.AllocationRequiringGC", 5);
7472
public static final JfrEvent OldObjectSample = create("jdk.OldObjectSample", 7);
75-
public static final JfrEvent ObjectAllocationSample = create("jdk.ObjectAllocationSample", JfrEventFlags.SupportsThrottling);
73+
public static final JfrEvent ObjectAllocationSample = create("jdk.ObjectAllocationSample", 5, JfrEventFlags.SupportsThrottling);
7674
public static final JfrEvent NativeMemoryUsage = create("jdk.NativeMemoryUsage");
7775
public static final JfrEvent NativeMemoryUsageTotal = create("jdk.NativeMemoryUsageTotal");
7876

@@ -82,12 +80,12 @@ public final class JfrEvent {
8280
private final int skipCount;
8381

8482
@Platforms(Platform.HOSTED_ONLY.class)
85-
public static JfrEvent create(String name, JfrEventFlags... flags) {
86-
return new JfrEvent(name, defaultInternalSkipCount, flags);
83+
private static JfrEvent create(String name, JfrEventFlags... flags) {
84+
return new JfrEvent(name, -1, flags);
8785
}
8886

8987
@Platforms(Platform.HOSTED_ONLY.class)
90-
public static JfrEvent create(String name, int skipCount, JfrEventFlags... flags) {
88+
private static JfrEvent create(String name, int skipCount, JfrEventFlags... flags) {
9189
return new JfrEvent(name, skipCount, flags);
9290
}
9391

@@ -106,6 +104,7 @@ public long getId() {
106104

107105
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
108106
public int getSkipCount() {
107+
assert skipCount >= 0 : "method may only be called for events that need a stack trace";
109108
return skipCount;
110109
}
111110

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jfr/events/JavaMonitorInflateEvent.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
package com.oracle.svm.core.jfr.events;
2828

29-
import jdk.graal.compiler.word.Word;
3029
import org.graalvm.nativeimage.StackValue;
3130

3231
import com.oracle.svm.core.Uninterruptible;
@@ -39,6 +38,8 @@
3938
import com.oracle.svm.core.jfr.SubstrateJVM;
4039
import com.oracle.svm.core.monitor.MonitorInflationCause;
4140

41+
import jdk.graal.compiler.word.Word;
42+
4243
public class JavaMonitorInflateEvent {
4344
public static void emit(Object obj, long startTicks, MonitorInflationCause cause) {
4445
if (HasJfrSupport.get()) {
@@ -47,7 +48,7 @@ public static void emit(Object obj, long startTicks, MonitorInflationCause cause
4748
}
4849

4950
@Uninterruptible(reason = "Accesses a JFR buffer.")
50-
public static void emit0(Object obj, long startTicks, MonitorInflationCause cause) {
51+
private static void emit0(Object obj, long startTicks, MonitorInflationCause cause) {
5152
long duration = JfrTicks.duration(startTicks);
5253
if (JfrEvent.JavaMonitorInflate.shouldEmit(duration)) {
5354
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerBuffersAccess.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ private static void serializeStackTraces(SamplerBuffer rawStackTraceBuffer) {
115115
int sampleSize = current.readInt(0);
116116
current = current.add(Integer.BYTES);
117117

118-
/* Sample size, excluding the header and the end marker. */
118+
/* Number of vframes that should be skipped at the top of the stack trace. */
119119
int skipCount = current.readInt(0);
120120
current = current.add(Integer.BYTES);
121121

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerJfrStackTraceSerializer.java

Lines changed: 54 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525

2626
package com.oracle.svm.core.sampler;
2727

28-
import jdk.graal.compiler.word.Word;
28+
import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
29+
2930
import org.graalvm.nativeimage.StackValue;
3031
import org.graalvm.nativeimage.c.function.CodePointer;
3132
import org.graalvm.nativeimage.c.type.CIntPointer;
@@ -49,19 +50,18 @@
4950
import com.oracle.svm.core.jfr.events.ExecutionSampleEvent;
5051
import com.oracle.svm.core.util.VMError;
5152

53+
import jdk.graal.compiler.word.Word;
54+
5255
/**
5356
* A concrete implementation of {@link SamplerStackTraceSerializer} designed for JFR stack trace
5457
* serialization.
58+
*
59+
* All static mutable state in this class is preallocated and reused by multiple threads. This is
60+
* safe because only one thread at a time may serialize stack traces.
5561
*/
5662
public final class SamplerJfrStackTraceSerializer implements SamplerStackTraceSerializer {
57-
/** This value is used by multiple threads but only by a single thread at a time. */
5863
private static final CodeInfoDecoder.FrameInfoCursor FRAME_INFO_CURSOR = new CodeInfoDecoder.FrameInfoCursor();
59-
60-
/*
61-
* This is static so that a single instance can be preallocated and reused. Only one thread ever
62-
* serializes at a given time.
63-
*/
64-
private static final FrameCountData FRAME_COUNT_DATA = new FrameCountData();
64+
private static final StackTraceVisitorData VISITOR_DATA = new StackTraceVisitorData();
6565

6666
@Override
6767
@Uninterruptible(reason = "Prevent JFR recording and epoch change.")
@@ -117,20 +117,19 @@ private static boolean serializeStackTrace(Pointer rawStackTrace, int sampleSize
117117
/*
118118
* One IP may correspond to multiple Java-level stack frames. We need to precompute the
119119
* number of stack trace elements because the count can't be patched later on
120-
* (JfrNativeEventWriter.putInt() would not necessarily reserve enough bytes).
121-
*
122-
* The first pass-through also sets FRAME_COUNT_DATA.isTruncated().
120+
* (JfrNativeEventWriter.putInt() would not necessarily reserve enough bytes). We also
121+
* precompute if the stack trace was truncated.
123122
*/
124-
int numStackTraceElements = visitRawStackTrace(rawStackTrace, sampleSize, Word.nullPointer(), skipCount);
125-
if (numStackTraceElements == 0) {
123+
visitRawStackTrace(rawStackTrace, sampleSize, Word.nullPointer(), skipCount);
124+
if (VISITOR_DATA.getUsedFrames() == 0) {
126125
return false;
127126
}
128127

129128
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class);
130129
JfrNativeEventWriterDataAccess.initialize(data, targetBuffer);
131130
JfrNativeEventWriter.putLong(data, stackTraceId);
132-
JfrNativeEventWriter.putBoolean(data, isTruncated || FRAME_COUNT_DATA.isTruncated());
133-
JfrNativeEventWriter.putInt(data, numStackTraceElements);
131+
JfrNativeEventWriter.putBoolean(data, isTruncated || VISITOR_DATA.isTruncated());
132+
JfrNativeEventWriter.putInt(data, VISITOR_DATA.getUsedFrames());
134133
visitRawStackTrace(rawStackTrace, sampleSize, data, skipCount);
135134
boolean success = JfrNativeEventWriter.commit(data);
136135

@@ -140,24 +139,20 @@ private static boolean serializeStackTrace(Pointer rawStackTrace, int sampleSize
140139
}
141140

142141
@Uninterruptible(reason = "Prevent JFR recording and epoch change.")
143-
private static int visitRawStackTrace(Pointer rawStackTrace, int sampleSize, JfrNativeEventWriterData data, int skipCount) {
144-
int numStackTraceElements = 0;
145-
Pointer rawStackTraceEnd = rawStackTrace.add(sampleSize);
146-
Pointer ipPtr = rawStackTrace;
147-
148-
// Reset FrameCountData before every serialization of a new stacktrace.
149-
FRAME_COUNT_DATA.reset(skipCount);
142+
private static void visitRawStackTrace(Pointer rawStackTrace, int sampleSize, JfrNativeEventWriterData data, int skipCount) {
143+
VISITOR_DATA.reset(skipCount);
150144

145+
Pointer ipPtr = rawStackTrace;
146+
Pointer rawStackTraceEnd = rawStackTrace.add(sampleSize);
151147
while (ipPtr.belowThan(rawStackTraceEnd)) {
152148
long ip = ipPtr.readLong(0);
153-
numStackTraceElements += visitFrame(data, ip);
149+
visitFrame(data, ip);
154150
ipPtr = ipPtr.add(Long.BYTES);
155151
}
156-
return numStackTraceElements;
157152
}
158153

159154
@Uninterruptible(reason = "Prevent JFR recording, epoch change, and that the GC frees the CodeInfo.")
160-
private static int visitFrame(JfrNativeEventWriterData data, long address) {
155+
private static void visitFrame(JfrNativeEventWriterData data, long address) {
161156
CodePointer ip = Word.pointer(address);
162157
UntetheredCodeInfo untetheredInfo = CodeInfoTable.lookupCodeInfo(ip);
163158
if (untetheredInfo.isNull()) {
@@ -168,32 +163,30 @@ private static int visitFrame(JfrNativeEventWriterData data, long address) {
168163
Object tether = CodeInfoAccess.acquireTether(untetheredInfo);
169164
try {
170165
CodeInfo tetheredCodeInfo = CodeInfoAccess.convert(untetheredInfo, tether);
171-
return visitFrame(data, tetheredCodeInfo, ip);
166+
visitFrame(data, tetheredCodeInfo, ip);
172167
} finally {
173168
CodeInfoAccess.releaseTether(untetheredInfo, tether);
174169
}
175170
}
176171

177172
@Uninterruptible(reason = "Prevent JFR recording and epoch change.")
178-
private static int visitFrame(JfrNativeEventWriterData data, CodeInfo codeInfo, CodePointer ip) {
179-
int numStackTraceElements = 0;
173+
private static void visitFrame(JfrNativeEventWriterData data, CodeInfo codeInfo, CodePointer ip) {
180174
FRAME_INFO_CURSOR.initialize(codeInfo, ip, false);
181175
while (FRAME_INFO_CURSOR.advance()) {
182-
if (FRAME_COUNT_DATA.shouldSkip()) {
183-
FRAME_COUNT_DATA.incrementSkipped();
176+
if (VISITOR_DATA.shouldSkipFrame()) {
177+
VISITOR_DATA.incrementSkippedFrames();
184178
continue;
185-
} else if (FRAME_COUNT_DATA.shouldTruncate()) {
186-
FRAME_COUNT_DATA.setTruncated();
179+
} else if (VISITOR_DATA.shouldTruncate()) {
180+
VISITOR_DATA.setTruncated();
187181
break;
188182
}
183+
184+
VISITOR_DATA.incrementUsedFrames();
189185
if (data.isNonNull()) {
190186
FrameInfoQueryResult frame = FRAME_INFO_CURSOR.get();
191187
serializeStackTraceElement(data, frame);
192188
}
193-
FRAME_COUNT_DATA.incrementTotal();
194-
numStackTraceElements++;
195189
}
196-
return numStackTraceElements;
197190
}
198191

199192
@Uninterruptible(reason = "Prevent JFR recording and epoch change.")
@@ -206,48 +199,53 @@ private static void serializeStackTraceElement(JfrNativeEventWriterData data, Fr
206199
JfrNativeEventWriter.putLong(data, JfrFrameType.FRAME_AOT_COMPILED.getId());
207200
}
208201

209-
private static final class FrameCountData {
210-
private int skipcount;
211-
private int totalCount;
212-
private int skippedCount;
202+
private static final class StackTraceVisitorData {
203+
private int framesToSkip;
204+
private int skippedFrames;
205+
private int usedFrames;
213206
private boolean truncated;
214207

215-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
208+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
216209
public void reset(int skipCount) {
217-
this.skipcount = skipCount;
218-
totalCount = 0;
219-
skippedCount = 0;
210+
framesToSkip = skipCount;
211+
skippedFrames = 0;
212+
usedFrames = 0;
220213
truncated = false;
221214
}
222215

223-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) //
224-
public boolean shouldSkip() {
225-
return skippedCount < skipcount;
216+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) //
217+
public boolean shouldSkipFrame() {
218+
return skippedFrames < framesToSkip;
219+
}
220+
221+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
222+
public void incrementSkippedFrames() {
223+
skippedFrames++;
226224
}
227225

228-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) //
226+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true) //
229227
public boolean shouldTruncate() {
230-
return totalCount > SubstrateJVM.getStackTraceRepo().getStackTraceDepth();
228+
return usedFrames >= SubstrateJVM.getStackTraceRepo().getStackTraceDepth();
231229
}
232230

233-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
231+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
234232
public void setTruncated() {
235233
truncated = true;
236234
}
237235

238-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
236+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
239237
public boolean isTruncated() {
240238
return truncated;
241239
}
242240

243-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
244-
public void incrementSkipped() {
245-
skippedCount++;
241+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
242+
public void incrementUsedFrames() {
243+
usedFrames++;
246244
}
247245

248-
@Uninterruptible(reason = Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
249-
public void incrementTotal() {
250-
totalCount++;
246+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
247+
public int getUsedFrames() {
248+
return usedFrames;
251249
}
252250
}
253251
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/sampler/SamplerSampleWriter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525

2626
package com.oracle.svm.core.sampler;
2727

28-
import jdk.graal.compiler.api.replacements.Fold;
29-
import jdk.graal.compiler.word.Word;
3028
import org.graalvm.word.Pointer;
3129
import org.graalvm.word.UnsignedWord;
3230

@@ -37,6 +35,9 @@
3735
import com.oracle.svm.core.jfr.JfrTicks;
3836
import com.oracle.svm.core.jfr.SubstrateJVM;
3937

38+
import jdk.graal.compiler.api.replacements.Fold;
39+
import jdk.graal.compiler.word.Word;
40+
4041
public final class SamplerSampleWriter {
4142
public static final long JFR_STACK_TRACE_END = -1;
4243
public static final long EXECUTION_SAMPLE_END = -2;
@@ -62,9 +63,8 @@ public static void begin(SamplerSampleWriterData data) {
6263
SamplerSampleWriter.putInt(data, 0);
6364
/* Sample size. (will be patched later) */
6465
SamplerSampleWriter.putInt(data, 0);
65-
/* Skipcount will be used later during serialization. */
66-
SamplerSampleWriter.putInt(data, data.getSkipCount());
6766

67+
SamplerSampleWriter.putInt(data, data.getSkipCount());
6868
SamplerSampleWriter.putLong(data, JfrTicks.elapsedTicks());
6969
SamplerSampleWriter.putLong(data, SubstrateJVM.getCurrentThreadId());
7070
SamplerSampleWriter.putLong(data, JfrThreadState.getId(Thread.State.RUNNABLE));

0 commit comments

Comments
 (0)