Skip to content

Commit 6db271c

Browse files
JFR and Sampler code improvements and bug fixes.
1 parent 45a1400 commit 6db271c

File tree

13 files changed

+129
-71
lines changed

13 files changed

+129
-71
lines changed

substratevm/src/com.oracle.svm.core.posix/src/com/oracle/svm/core/posix/PosixSubstrateSigprofHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ private static void registerSigprofSignal() {
7878
LibC.memset(structSigAction, WordFactory.signed(0), WordFactory.unsigned(structSigActionSize));
7979

8080
/* Register sa_sigaction signal handler */
81-
structSigAction.sa_flags(Signal.SA_SIGINFO() | Signal.SA_NODEFER());
81+
structSigAction.sa_flags(Signal.SA_SIGINFO() | Signal.SA_NODEFER() | Signal.SA_RESTART());
8282
structSigAction.sa_sigaction(advancedSignalDispatcher.getFunctionPointer());
8383
Signal.sigaction(Signal.SignalEnum.SIGPROF.getCValue(), structSigAction, WordFactory.nullPointer());
8484
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ private static int runCore0() {
183183
*/
184184
return 1;
185185
} finally {
186-
PlatformThreads.exit(Thread.currentThread());
186+
PlatformThreads.exitMain(Thread.currentThread());
187187
}
188188
}
189189

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/CodeInfoAccess.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import com.oracle.svm.core.deopt.SubstrateInstalledCode;
4242
import com.oracle.svm.core.graal.stackvalue.UnsafeStackValue;
4343
import com.oracle.svm.core.heap.Heap;
44-
import com.oracle.svm.core.heap.RestrictHeapAccess;
4544
import com.oracle.svm.core.log.Log;
4645
import com.oracle.svm.core.thread.VMOperation;
4746
import com.oracle.svm.core.util.VMError;
@@ -485,8 +484,8 @@ public SingleShotFrameInfoQueryResultAllocator reload() {
485484
return this;
486485
}
487486

488-
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Provide allocation-free StackFrameVisitor")
489487
@Override
488+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
490489
public FrameInfoQueryResult newFrameInfoQueryResult() {
491490
if (fired) {
492491
return null;
@@ -498,26 +497,26 @@ public FrameInfoQueryResult newFrameInfoQueryResult() {
498497
}
499498

500499
public static class DummyValueInfoAllocator implements ValueInfoAllocator {
501-
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Provide allocation-free StackFrameVisitor")
502500
@Override
501+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
503502
public FrameInfoQueryResult.ValueInfo newValueInfo() {
504503
return null;
505504
}
506505

507-
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Provide allocation-free StackFrameVisitor")
508506
@Override
507+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
509508
public FrameInfoQueryResult.ValueInfo[] newValueInfoArray(int len) {
510509
return null;
511510
}
512511

513-
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Provide allocation-free StackFrameVisitor")
514512
@Override
513+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
515514
public FrameInfoQueryResult.ValueInfo[][] newValueInfoArrayArray(int len) {
516515
return null;
517516
}
518517

519-
@RestrictHeapAccess(access = RestrictHeapAccess.Access.NO_ALLOCATION, reason = "Provide allocation-free StackFrameVisitor")
520518
@Override
519+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
521520
public void decodeConstant(FrameInfoQueryResult.ValueInfo valueInfo, NonmovableObjectArray<?> frameInfoObjectConstants) {
522521
}
523522
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FrameInfoQueryResult.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ public FrameInfoQueryResult() {
179179
init();
180180
}
181181

182+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
182183
public void init() {
183184
caller = null;
184185
deoptMethod = null;

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

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
*/
2525
package com.oracle.svm.core.jfr;
2626

27+
import org.graalvm.nativeimage.ImageSingletons;
2728
import org.graalvm.nativeimage.Platform;
2829
import org.graalvm.nativeimage.Platforms;
2930
import org.graalvm.nativeimage.StackValue;
@@ -32,6 +33,7 @@
3233
import org.graalvm.nativeimage.c.struct.RawStructure;
3334
import org.graalvm.nativeimage.c.struct.SizeOf;
3435
import org.graalvm.nativeimage.c.type.CIntPointer;
36+
import org.graalvm.nativeimage.impl.UnmanagedMemorySupport;
3537
import org.graalvm.word.Pointer;
3638
import org.graalvm.word.UnsignedWord;
3739
import org.graalvm.word.WordFactory;
@@ -48,8 +50,6 @@
4850
import com.oracle.svm.core.jfr.traceid.JfrTraceIdEpoch;
4951
import com.oracle.svm.core.jfr.utils.JfrVisited;
5052
import com.oracle.svm.core.locks.VMMutex;
51-
import com.oracle.svm.core.sampler.SamplerBuffer;
52-
import com.oracle.svm.core.sampler.SamplerBufferAccess;
5353
import com.oracle.svm.core.sampler.SamplerSampleWriter;
5454
import com.oracle.svm.core.sampler.SamplerSampleWriterData;
5555
import com.oracle.svm.core.sampler.SamplerSampleWriterDataAccess;
@@ -119,7 +119,7 @@ public long getStackTraceId(int skipCount) {
119119
Pointer start = data.getStartPos().add(SamplerSampleWriter.getHeaderSize());
120120
stackTraceId = getStackTraceId(start, data.getCurrentPos(), data.getHashCode(), status, false);
121121
if (JfrStackTraceTableEntryStatus.get(status, JfrStackTraceTableEntryStatus.NEW)) {
122-
SamplerSampleWriter.end(data);
122+
SamplerSampleWriter.end(data, SamplerSampleWriter.JFR_STACK_TRACE_END);
123123
}
124124
} finally {
125125
releaseLock();
@@ -138,6 +138,7 @@ public long getStackTraceId(Pointer start, Pointer end, int hashCode, CIntPointe
138138
UnsignedWord size = end.subtract(start);
139139
entry.setHash(hashCode);
140140
entry.setSize((int) size.rawValue());
141+
entry.setSerialized(false);
141142
/* Do not copy stacktrace into new entry unless it is necessary. */
142143
entry.setStackTrace(start);
143144

@@ -147,15 +148,20 @@ public long getStackTraceId(Pointer start, Pointer end, int hashCode, CIntPointe
147148
return result.getId();
148149
} else {
149150
/* Replace the previous pointer with new one (entry size and hash remains the same). */
150-
SamplerBuffer buffer = SamplerBufferAccess.allocate(size);
151-
Pointer to = SamplerBufferAccess.getDataStart(buffer);
152-
entry.setStackTrace(to);
153-
/* Copy the stacktrace into separate native memory entry in hashtable. */
154-
UnmanagedMemoryUtil.copy(start, to, size);
155-
156-
JfrStackTraceTableEntry newEntry = (JfrStackTraceTableEntry) epochData.visitedStackTraces.getOrPut(entry);
157-
JfrStackTraceTableEntryStatus.update(newEntry, status, true, false, isSerializationInProgress);
158-
return newEntry.getId();
151+
Pointer to = ImageSingletons.lookup(UnmanagedMemorySupport.class).malloc(size);
152+
if (to.isNull()) {
153+
/* There is not enough space to allocate a new buffer. */
154+
JfrStackTraceTableEntryStatus.failStatus(status);
155+
return 0;
156+
} else {
157+
entry.setStackTrace(to);
158+
/* Copy the stacktrace into separate native memory entry in hashtable. */
159+
UnmanagedMemoryUtil.copy(start, to, size);
160+
161+
JfrStackTraceTableEntry newEntry = (JfrStackTraceTableEntry) epochData.visitedStackTraces.getOrPut(entry);
162+
JfrStackTraceTableEntryStatus.update(newEntry, status, true, false, isSerializationInProgress);
163+
return newEntry.getId();
164+
}
159165
}
160166
}
161167

@@ -294,20 +300,35 @@ protected UninterruptibleEntry copyToHeap(UninterruptibleEntry valueOnStack) {
294300
result.setId(++nextId);
295301
return result;
296302
}
303+
304+
@Override
305+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
306+
protected void free(UninterruptibleEntry entry) {
307+
JfrStackTraceTableEntry stackTraceEntry = (JfrStackTraceTableEntry) entry;
308+
/* The base method will free only the entry itself, not the pointer with stacktrace. */
309+
ImageSingletons.lookup(UnmanagedMemorySupport.class).free(stackTraceEntry.getStackTrace());
310+
super.free(entry);
311+
}
297312
}
298313

299314
public static class JfrStackTraceTableEntryStatus {
300315
public static final int NEW = 1;
301316
public static final int SHOULD_SERIALIZE = NEW << 1;
302317
public static final int SERIALIZED = SHOULD_SERIALIZE << 1;
318+
public static final int FAILED = SERIALIZED << 1;
319+
320+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
321+
public static void failStatus(CIntPointer status) {
322+
status.write(FAILED);
323+
}
303324

304325
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
305326
public static void update(JfrStackTraceTableEntry entry, CIntPointer status, boolean setNew, boolean isAlreadySerialized, boolean isSerializationInProgress) {
306-
int isRecorded = setNew ? NEW : 0;
327+
int isNew = setNew ? NEW : 0;
307328
int shouldSerialize = !isAlreadySerialized ? SHOULD_SERIALIZE : 0;
308329
int isSerialized = isAlreadySerialized ? SERIALIZED : 0;
309-
status.write(isRecorded | shouldSerialize | isSerialized);
310-
if (!entry.getSerialized() && isSerializationInProgress) {
330+
status.write(isNew | shouldSerialize | isSerialized);
331+
if (!isAlreadySerialized && isSerializationInProgress) {
311332
entry.setSerialized(true);
312333
}
313334
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,8 @@ public void setMethodSamplingInterval(long type, long intervalMillis) {
385385

386386
if (millis > 0) {
387387
SubstrateJVM.get().setEnabled(type, true);
388+
/* Stacktrace walk is disabled by default for ExecutionSample. */
389+
SubstrateJVM.get().setStackTraceEnabled(type, true);
388390
} else {
389391
millis = 0;
390392
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public final class ExecutionSampleEvent {
5050

5151
@Uninterruptible(reason = "Called from uninterruptible code.", calleeMustBe = false)
5252
public static void tryToRegisterExecutionSampleEventCallback() {
53-
if (SubstrateJVM.get().isEnabled(JfrEvent.ExecutionSample) && intervalMillis > 0) {
53+
if (intervalMillis > 0) {
5454
ImageSingletons.lookup(ThreadingSupport.class).registerRecurringCallback(intervalMillis, TimeUnit.MILLISECONDS, CALLBACK);
5555
}
5656
}
@@ -83,7 +83,7 @@ public void run(Threading.RecurringCallbackAccess access) {
8383
ExecutionSampleEvent.writeExecutionSample(
8484
JfrTicks.elapsedTicks(),
8585
SubstrateJVM.getThreadId(isolateThread),
86-
SubstrateJVM.get().getStackTraceId(JfrEvent.ExecutionSample.getId(), 0),
86+
SubstrateJVM.get().getStackTraceId(JfrEvent.ExecutionSample, 0),
8787
JfrThreadState.getId(javaThread.getState()));
8888
}
8989
}

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525

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

28+
import static com.oracle.svm.core.jfr.JfrStackTraceRepository.JfrStackTraceTableEntryStatus.FAILED;
29+
import static com.oracle.svm.core.jfr.JfrStackTraceRepository.JfrStackTraceTableEntryStatus.SERIALIZED;
30+
import static com.oracle.svm.core.jfr.JfrStackTraceRepository.JfrStackTraceTableEntryStatus.SHOULD_SERIALIZE;
31+
2832
import org.graalvm.nativeimage.StackValue;
2933
import org.graalvm.nativeimage.c.function.CodePointer;
3034
import org.graalvm.nativeimage.c.type.CIntPointer;
@@ -119,18 +123,30 @@ public static void processSamplerBuffer(SamplerBuffer buffer) {
119123
stackTraceRepo.acquireLock();
120124
try {
121125
long stackTraceId = stackTraceRepo.getStackTraceId(current, current.add(sampleSize), sampleHash, status, true);
122-
if (JfrStackTraceRepository.JfrStackTraceTableEntryStatus.get(status, JfrStackTraceRepository.JfrStackTraceTableEntryStatus.SERIALIZED)) {
123-
ExecutionSampleEvent.writeExecutionSample(sampleTick, buffer.getOwner(), stackTraceId, threadState);
124-
/* Sample is already there, skip the rest of sample plus END_MARK symbol. */
125-
current = current.add(sampleSize).add(SamplerSampleWriter.END_MARKER_SIZE);
126+
boolean serialized = JfrStackTraceRepository.JfrStackTraceTableEntryStatus.get(status, SERIALIZED);
127+
boolean failed = JfrStackTraceRepository.JfrStackTraceTableEntryStatus.get(status, FAILED);
128+
if (serialized || failed) {
129+
/*
130+
* Sample/Stack is already there or there is not enough memory to operate, skip
131+
* the rest of the data.
132+
*/
133+
current = current.add(sampleSize);
134+
long endMarker = current.readLong(0);
135+
if (endMarker == SamplerSampleWriter.SAMPLE_EVENT_DATA_END && serialized) {
136+
ExecutionSampleEvent.writeExecutionSample(sampleTick, buffer.getOwner(), stackTraceId, threadState);
137+
}
138+
current = current.add(SamplerSampleWriter.END_MARKER_SIZE);
126139
} else {
127-
assert JfrStackTraceRepository.JfrStackTraceTableEntryStatus.get(status, JfrStackTraceRepository.JfrStackTraceTableEntryStatus.SHOULD_SERIALIZE);
140+
assert JfrStackTraceRepository.JfrStackTraceTableEntryStatus.get(status, SHOULD_SERIALIZE);
128141
/* Sample is not there. Start walking a stacktrace. */
129142
stackTraceRepo.serializeStackTraceHeader(stackTraceId, isTruncated, sampleSize / SamplerSampleWriter.IP_SIZE);
130143
while (current.belowThan(end)) {
131144
long ip = current.readLong(0);
132-
if (ip == SamplerSampleWriter.END_MARKER) {
133-
ExecutionSampleEvent.writeExecutionSample(sampleTick, buffer.getOwner(), stackTraceId, threadState);
145+
/* Check if we hit any of the end markers. */
146+
if (ip == SamplerSampleWriter.JFR_STACK_TRACE_END || ip == SamplerSampleWriter.SAMPLE_EVENT_DATA_END) {
147+
if (ip == SamplerSampleWriter.SAMPLE_EVENT_DATA_END) {
148+
ExecutionSampleEvent.writeExecutionSample(sampleTick, buffer.getOwner(), stackTraceId, threadState);
149+
}
134150
current = current.add(SamplerSampleWriter.END_MARKER_SIZE);
135151
break;
136152
} else {
@@ -143,6 +159,7 @@ public static void processSamplerBuffer(SamplerBuffer buffer) {
143159
stackTraceRepo.releaseLock();
144160
}
145161
}
162+
SamplerBufferAccess.reinitialize(buffer);
146163
}
147164

148165
@Uninterruptible(reason = "The handle should only be accessed from uninterruptible code to prevent that the GC frees the CodeInfo.", callerMustBe = true)

0 commit comments

Comments
 (0)