Skip to content

Commit ecc2da1

Browse files
Clean up. Group allocation events. Add testing back door static class.
1 parent dc8f2d0 commit ecc2da1

File tree

8 files changed

+181
-344
lines changed

8 files changed

+181
-344
lines changed

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
import com.oracle.svm.core.hub.DynamicHub;
6363
import com.oracle.svm.core.hub.LayoutEncoding;
6464
import com.oracle.svm.core.jfr.JfrTicks;
65-
import com.oracle.svm.core.jfr.events.ObjectAllocationInNewTLABEvent;
65+
import com.oracle.svm.core.jfr.events.JfrAllocationEvents;
6666
import com.oracle.svm.core.log.Log;
6767
import com.oracle.svm.core.snippets.KnownIntrinsics;
6868
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
@@ -75,7 +75,6 @@
7575
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
7676
import com.oracle.svm.core.threadlocal.FastThreadLocalWord;
7777
import com.oracle.svm.core.util.VMError;
78-
import com.oracle.svm.core.jfr.events.ObjectAllocationSampleEvent;
7978

8079
/**
8180
* Bump-pointer allocation from thread-local top and end Pointers. Many of these methods are called
@@ -238,8 +237,7 @@ private static Object slowPathNewInstanceWithoutAllocating(DynamicHub hub) {
238237
AlignedHeader newTlab = HeapImpl.getChunkProvider().produceAlignedChunk();
239238
return allocateInstanceInNewTlab(hub, newTlab);
240239
} finally {
241-
ObjectAllocationInNewTLABEvent.emit(startTicks, hub, LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding()), HeapParameters.getAlignedHeapChunkSize());
242-
ObjectAllocationSampleEvent.emit(startTicks, DynamicHub.toClass(hub));
240+
JfrAllocationEvents.emit(startTicks, DynamicHub.toClass(hub), LayoutEncoding.getPureInstanceAllocationSize(hub.getLayoutEncoding()), HeapParameters.getAlignedHeapChunkSize());
243241
DeoptTester.enableDeoptTesting();
244242
}
245243
}
@@ -318,8 +316,7 @@ private static Object slowPathNewArrayLikeObject0(DynamicHub hub, int length, Un
318316
}
319317
return array;
320318
} finally {
321-
ObjectAllocationInNewTLABEvent.emit(startTicks, hub, size, tlabSize);
322-
ObjectAllocationSampleEvent.emit(startTicks, DynamicHub.toClass(hub));
319+
JfrAllocationEvents.emit(startTicks, DynamicHub.toClass(hub), size, tlabSize);
323320
DeoptTester.enableDeoptTesting();
324321
}
325322
}

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

Lines changed: 84 additions & 167 deletions
Large diffs are not rendered by default.

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@
3333

3434
/**
3535
* Each event that supports throttling has its own throttler that can be accessed through this class.
36-
* TODO: Consider making this a proper singleton later
37-
* When more events support throttling, some sort of allocation free hashmap should be used.
3836
*/
3937
public class JfrThrottlerSupport {
4038
JfrThrottler objectAllocationSampleThrottler;
4139
@Platforms(Platform.HOSTED_ONLY.class)
4240
JfrThrottlerSupport() {
43-
objectAllocationSampleThrottler = new JfrThrottler(new VMMutex("jfrThrottler"));
41+
if (HasJfrSupport.get()) {
42+
objectAllocationSampleThrottler = new JfrThrottler(new VMMutex("jfrThrottler"));
43+
}
4444
}
4545

4646
private JfrThrottler getThrottler(long eventId) {
@@ -53,7 +53,7 @@ private JfrThrottler getThrottler(long eventId) {
5353
public boolean setThrottle(long eventTypeId, long eventSampleSize, long periodMs) {
5454
JfrThrottler throttler = getThrottler(eventTypeId);
5555
if (throttler == null) {
56-
//event doesn't support throttling
56+
// This event doesn't support throttling
5757
return false;
5858
}
5959
throttler.setThrottle(eventSampleSize, periodMs);
@@ -63,7 +63,7 @@ public boolean setThrottle(long eventTypeId, long eventSampleSize, long periodMs
6363
public boolean shouldCommit(long eventTypeId) {
6464
JfrThrottler throttler = getThrottler(eventTypeId);
6565
if (throttler == null) {
66-
//event doesn't support throttling
66+
// This event doesn't support throttling
6767
return true;
6868
}
6969
return throttler.sample();

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

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,22 @@
3131

3232
public class JfrThrottlerWindow {
3333
// reset every rotation
34-
public UninterruptibleUtils.AtomicLong measuredPopSize; // already volatile
35-
public UninterruptibleUtils.AtomicLong endTicks; // already volatile
34+
public UninterruptibleUtils.AtomicLong measuredPopSize;
35+
public UninterruptibleUtils.AtomicLong endTicks;
3636

3737
// Calculated every rotation based on params set by user and results from previous windows
3838
public volatile long samplingInterval;
39-
public volatile double activeWindowSampleLimit;
39+
public volatile double maxSampleablePopulation;
4040

41-
// params set by user
41+
// Set by user
4242
public volatile long samplesPerWindow;
4343
public volatile long windowDurationNs;
4444
public volatile long debt;
4545

4646
public JfrThrottlerWindow() {
4747
windowDurationNs = 0;
4848
samplesPerWindow = 0;
49-
activeWindowSampleLimit = 0;
49+
maxSampleablePopulation = 0;
5050
measuredPopSize = new UninterruptibleUtils.AtomicLong(0);
5151
endTicks = new UninterruptibleUtils.AtomicLong(JfrTicks.currentTimeNanos() + windowDurationNs);
5252
samplingInterval = 1;
@@ -63,17 +63,17 @@ public boolean sample() {
6363
// Guarantees only one thread can record the last event of the window
6464
long prevMeasuredPopSize = measuredPopSize.getAndIncrement();
6565

66-
// Stop sampling if we're already over the projected population size, and we're over the
67-
// samples per window
66+
// Stop sampling if we're already over maxSampleablePopulation and we're over the expected
67+
// samples per window.
6868
if (prevMeasuredPopSize % samplingInterval == 0 &&
69-
(prevMeasuredPopSize < activeWindowSampleLimit)) {
69+
(prevMeasuredPopSize < maxSampleablePopulation)) {
7070
return true;
7171
}
7272
return false;
7373
}
7474

7575
public long samplesTaken() {
76-
if (measuredPopSize.get() > activeWindowSampleLimit) {
76+
if (measuredPopSize.get() > maxSampleablePopulation) {
7777
return samplesExpected();
7878
}
7979
return measuredPopSize.get() / samplingInterval;
@@ -88,15 +88,13 @@ public void configure(long debt, double projectedPopSize) {
8888
if (projectedPopSize <= samplesExpected()) {
8989
samplingInterval = 1;
9090
} else {
91-
// It's important to round *up* otherwise we risk violating the upper bound
92-
// TODO geometric
93-
// samplingInterval = (long) Math.ceil(projectedPopSize / (double) samplesExpected());
91+
9492
double projectedProbability = (double) samplesExpected() / projectedPopSize;
9593
samplingInterval = nextGeometric(projectedProbability, Math.random());
9694
}
97-
// activeWindowSampleLimit is either projectedPopSize or samplesExpected() (if
98-
// projectedPopSize < samplesPerWindow)
99-
this.activeWindowSampleLimit = samplesExpected() * samplingInterval;
95+
96+
this.maxSampleablePopulation = samplesExpected() * samplingInterval;
97+
10098
// reset
10199
measuredPopSize.set(0);
102100

@@ -106,11 +104,13 @@ public void configure(long debt, double projectedPopSize) {
106104
} else {
107105
endTicks.set(JfrTicks.currentTimeNanos() + windowDurationNs);
108106
}
109-
110107
}
111108

112-
long nextGeometric(double p, double u) { // *** is P is larger, then its more likely sampling
113-
// interval is smaller
109+
/**
110+
* This method is essentially the same as jfrAdaptiveSampler::next_geometric(double, double) in
111+
* the OpenJDK.
112+
*/
113+
private long nextGeometric(double p, double u) {
114114
if (u == 0.0) {
115115
u = 0.01;
116116
}

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -645,17 +645,12 @@ public boolean isEnabled(JfrEvent event) {
645645
}
646646

647647
public boolean shouldCommit(JfrEvent event) {
648-
// find the right throttler for the event (each event should have its own)like in hotspot
649-
// if none found, return true.
650-
// call into throttler code
651648
return jfrThrottlerSupport.shouldCommit(event.getId());
652649
}
653650

654651
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
655652
public boolean setThrottle(long eventTypeId, long eventSampleSize, long periodMs) {
656-
// find the right throttler for the event and set the new params there
657653
return jfrThrottlerSupport.setThrottle(eventTypeId, eventSampleSize, periodMs);
658-
// TODO: why would it ever return false? Maybe if the throttler doesn't exist?
659654
}
660655

661656
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,62 @@
2626

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

29+
import org.graalvm.nativeimage.StackValue;
30+
import org.graalvm.word.UnsignedWord;
31+
2932
import com.oracle.svm.core.Uninterruptible;
33+
import com.oracle.svm.core.jfr.HasJfrSupport;
3034
import com.oracle.svm.core.jfr.JfrEvent;
3135
import com.oracle.svm.core.jfr.JfrNativeEventWriter;
3236
import com.oracle.svm.core.jfr.JfrNativeEventWriterData;
3337
import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess;
3438
import com.oracle.svm.core.jfr.SubstrateJVM;
35-
import com.oracle.svm.core.jfr.HasJfrSupport;
36-
import org.graalvm.nativeimage.StackValue;
3739
import com.oracle.svm.core.threadlocal.FastThreadLocalFactory;
3840
import com.oracle.svm.core.threadlocal.FastThreadLocalLong;
3941
import com.oracle.svm.core.thread.PlatformThreads;
4042
import com.oracle.svm.core.thread.JavaThreads;
4143

42-
public class ObjectAllocationSampleEvent {
44+
public class JfrAllocationEvents {
4345
private static final FastThreadLocalLong lastAllocationSize = FastThreadLocalFactory.createLong("ObjectAllocationSampleEvent.lastAllocationSize");
44-
public static void emit(long startTicks, Class<?> clazz) {
46+
47+
public static void emit(long startTicks, Class<?> clazz, UnsignedWord allocationSize, UnsignedWord tlabSize) {
4548
if (HasJfrSupport.get()) {
46-
// TODO: consider moving this to after the isRecording check in emit0 to avoid duplicate checks. Might be a pain to deal with uninterruptibility though. Also we want to minimize uninterruptible code usage.
47-
// Doesn't hurt to check twice, might save us some time doing the sampling
48-
if (SubstrateJVM.get().shouldCommit(JfrEvent.ObjectAllocationSample)) {
49-
emit0(startTicks, clazz);
49+
emitObjectAllocationInNewTLAB(startTicks, clazz, allocationSize, tlabSize);
50+
51+
if (shouldEmitObjectAllocationSample() && SubstrateJVM.get().shouldCommit(JfrEvent.ObjectAllocationSample)) {
52+
emitObjectAllocationSample(startTicks, clazz);
5053
}
5154
}
5255
}
5356

57+
/**
58+
* This method exists as a slight optimization to avoid entering the sampler code if
59+
* unnecessary. We'll have to check {@link JfrEvent.shouldEmit()} again if a sample ends up
60+
* being taken.
61+
*/
62+
@Uninterruptible(reason = "Needed for JfrEvent.shouldEmit().")
63+
private static boolean shouldEmitObjectAllocationSample() {
64+
return JfrEvent.ObjectAllocationSample.shouldEmit();
65+
}
66+
67+
@Uninterruptible(reason = "Accesses a JFR buffer.")
68+
private static void emitObjectAllocationInNewTLAB(long startTicks, Class<?> clazz, UnsignedWord allocationSize, UnsignedWord tlabSize) {
69+
if (JfrEvent.ObjectAllocationInNewTLAB.shouldEmit()) {
70+
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class);
71+
JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data);
72+
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.ObjectAllocationInNewTLAB);
73+
JfrNativeEventWriter.putLong(data, startTicks);
74+
JfrNativeEventWriter.putEventThread(data);
75+
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ObjectAllocationInNewTLAB, 0));
76+
JfrNativeEventWriter.putClass(data, clazz);
77+
JfrNativeEventWriter.putLong(data, allocationSize.rawValue());
78+
JfrNativeEventWriter.putLong(data, tlabSize.rawValue());
79+
JfrNativeEventWriter.endSmallEvent(data);
80+
}
81+
}
82+
5483
@Uninterruptible(reason = "Accesses a JFR buffer.")
55-
private static void emit0(long startTicks, Class<?> clazz) {
84+
private static void emitObjectAllocationSample(long startTicks, Class<?> clazz) {
5685
if (JfrEvent.ObjectAllocationSample.shouldEmit()) {
5786
long currentAllocationSize = PlatformThreads.getThreadAllocatedBytes(JavaThreads.getCurrentThreadId());
5887

@@ -61,7 +90,7 @@ private static void emit0(long startTicks, Class<?> clazz) {
6190
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.ObjectAllocationSample);
6291
JfrNativeEventWriter.putLong(data, startTicks);
6392
JfrNativeEventWriter.putEventThread(data);
64-
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ObjectAllocationSample, 0)); //This causes problems during JFR shutdown
93+
JfrNativeEventWriter.putLong(data, SubstrateJVM.get().getStackTraceId(JfrEvent.ObjectAllocationSample, 0));
6594
JfrNativeEventWriter.putClass(data, clazz);
6695
JfrNativeEventWriter.putLong(data, currentAllocationSize - lastAllocationSize.get());
6796
JfrNativeEventWriter.endSmallEvent(data);

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

Lines changed: 0 additions & 63 deletions
This file was deleted.

0 commit comments

Comments
 (0)