Skip to content

Commit 580a18d

Browse files
Cleanups.
1 parent 06c6404 commit 580a18d

12 files changed

+144
-166
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.Collections;
2828
import java.util.List;
2929

30-
import com.oracle.svm.core.sampler.SamplerStatistics;
3130
import org.graalvm.nativeimage.ImageSingletons;
3231
import org.graalvm.nativeimage.Platform;
3332
import org.graalvm.nativeimage.hosted.Feature;
@@ -43,6 +42,7 @@
4342
import com.oracle.svm.core.sampler.SamplerJfrStackTraceSerializer;
4443
import com.oracle.svm.core.sampler.SamplerStackTraceSerializer;
4544
import com.oracle.svm.core.sampler.SamplerStackWalkVisitor;
45+
import com.oracle.svm.core.sampler.SamplerStatistics;
4646
import com.oracle.svm.core.thread.ThreadListenerSupport;
4747
import com.oracle.svm.core.thread.ThreadListenerSupportFeature;
4848
import com.oracle.svm.core.util.UserError;
@@ -175,6 +175,7 @@ public void afterRegistration(AfterRegistrationAccess access) {
175175
if (VMInspectionOptions.hasNativeMemoryTrackingSupport()) {
176176
JfrSerializerSupport.get().register(new JfrNmtCategorySerializer());
177177
}
178+
178179
ThreadListenerSupport.get().register(SubstrateJVM.getThreadLocal());
179180

180181
RuntimeClassInitializationSupport rci = ImageSingletons.lookup(RuntimeClassInitializationSupport.class);

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@
2626

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

29-
import com.oracle.svm.core.nmt.NmtCategory;
3029
import org.graalvm.nativeimage.Platform;
3130
import org.graalvm.nativeimage.Platforms;
3231

32+
import com.oracle.svm.core.nmt.NmtCategory;
33+
3334
public class JfrNmtCategorySerializer implements JfrSerializer {
3435
@Platforms(Platform.HOSTED_ONLY.class)
3536
public JfrNmtCategorySerializer() {
@@ -41,9 +42,9 @@ public void write(JfrChunkWriter writer) {
4142

4243
NmtCategory[] nmtCategories = NmtCategory.values();
4344
writer.writeCompressedLong(nmtCategories.length);
44-
for (int i = 0; i < nmtCategories.length; i++) {
45-
writer.writeCompressedInt(i);
46-
writer.writeString(nmtCategories[i].getName());
45+
for (NmtCategory nmtCategory : nmtCategories) {
46+
writer.writeCompressedInt(nmtCategory.ordinal());
47+
writer.writeString(nmtCategory.getName());
4748
}
4849
}
4950
}

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

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.graalvm.nativeimage.StackValue;
3131

3232
import com.oracle.svm.core.Uninterruptible;
33+
import com.oracle.svm.core.VMInspectionOptions;
3334
import com.oracle.svm.core.heap.Heap;
3435
import com.oracle.svm.core.heap.PhysicalMemory;
3536
import com.oracle.svm.core.heap.VMOperationInfos;
@@ -39,11 +40,10 @@
3940
import com.oracle.svm.core.jfr.JfrNativeEventWriterData;
4041
import com.oracle.svm.core.jfr.JfrNativeEventWriterDataAccess;
4142
import com.oracle.svm.core.jfr.JfrTicks;
42-
import com.oracle.svm.core.nmt.NmtCategory;
4343
import com.oracle.svm.core.nmt.NativeMemoryTracking;
44+
import com.oracle.svm.core.nmt.NmtCategory;
4445
import com.oracle.svm.core.thread.JavaVMOperation;
4546
import com.oracle.svm.core.thread.VMThreads;
46-
import com.oracle.svm.core.VMInspectionOptions;
4747

4848
import jdk.jfr.Event;
4949
import jdk.jfr.Name;
@@ -120,7 +120,7 @@ private static void emitNativeMemoryTrackingEvents() {
120120
}
121121
}
122122

123-
/** These peak events are specific to SubstrateVM. */
123+
/** Emit Native Image-specific events that report the peak memory usage. */
124124
private static void emitNmtPeakEvents() {
125125
NativeMemoryUsageTotalPeakEvent nmtTotalPeakEvent = new NativeMemoryUsageTotalPeakEvent();
126126
nmtTotalPeakEvent.countAtPeak = NativeMemoryTracking.singleton().getCountAtTotalPeakUsage();
@@ -144,27 +144,26 @@ private static void emitJdkNmtEvents(NmtCategory[] nmtCategories) {
144144

145145
if (JfrEvent.NativeMemoryUsage.shouldEmit()) {
146146
for (NmtCategory nmtCategory : nmtCategories) {
147+
long usedMemory = NativeMemoryTracking.singleton().getUsedMemory(nmtCategory);
148+
147149
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.NativeMemoryUsage);
148150
JfrNativeEventWriter.putLong(data, timestamp);
149-
/* Category */
150151
JfrNativeEventWriter.putLong(data, nmtCategory.ordinal());
151-
/* Reserved usage */
152-
JfrNativeEventWriter.putLong(data, NativeMemoryTracking.singleton().getUsedMemory(nmtCategory));
153-
/* Committed usage */
154-
JfrNativeEventWriter.putLong(data, NativeMemoryTracking.singleton().getUsedMemory(nmtCategory));
152+
JfrNativeEventWriter.putLong(data, usedMemory); // reserved
153+
JfrNativeEventWriter.putLong(data, usedMemory); // committed
155154
JfrNativeEventWriter.endSmallEvent(data);
156155
}
157156
}
157+
158158
if (JfrEvent.NativeMemoryUsageTotal.shouldEmit()) {
159+
long totalUsedMemory = NativeMemoryTracking.singleton().getTotalUsedMemory();
160+
159161
JfrNativeEventWriter.beginSmallEvent(data, JfrEvent.NativeMemoryUsageTotal);
160162
JfrNativeEventWriter.putLong(data, timestamp);
161-
/* Reserved usage */
162-
JfrNativeEventWriter.putLong(data, NativeMemoryTracking.singleton().getTotalUsedMemory());
163-
/* Committed usage */
164-
JfrNativeEventWriter.putLong(data, NativeMemoryTracking.singleton().getTotalUsedMemory());
163+
JfrNativeEventWriter.putLong(data, totalUsedMemory); // reserved
164+
JfrNativeEventWriter.putLong(data, totalUsedMemory); // committed
165165
JfrNativeEventWriter.endSmallEvent(data);
166166
}
167-
168167
}
169168

170169
private static void emitPerThreadEvents() {
@@ -176,7 +175,7 @@ private static void emitPerThreadEvents() {
176175

177176
@Uninterruptible(reason = "Used to avoid the VM operation if it is not absolutely needed.")
178177
private static boolean needsVMOperation() {
179-
/* The returned value is racy. */
178+
/* The returned value is racy but this is fine because we recheck in the VM operation. */
180179
return JfrEvent.ThreadCPULoad.shouldEmit() || JfrEvent.ThreadAllocationStatistics.shouldEmit();
181180
}
182181

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@
2828
import jdk.jfr.Category;
2929
import jdk.jfr.Description;
3030
import jdk.jfr.Event;
31+
import jdk.jfr.Experimental;
3132
import jdk.jfr.Label;
3233
import jdk.jfr.Name;
3334
import jdk.jfr.StackTrace;
3435

35-
@Name("svm.NativeMemoryUsagePeak")
36+
/** Similar to the JFR event jdk.NativeMemoryUsage, except that it tracks the peak usage. */
37+
@Experimental
38+
@Name("jdk.NativeMemoryUsagePeak")
3639
@Label("Native Memory Usage Peak")
37-
@Description("Information about native memory peak usage of committed virtual memory and malloc.")
38-
@Category("Native Image")
40+
@Description("Native memory peak usage for a given memory type in the JVM.")
41+
@Category({"Java Virtual Machine", "Memory"})
3942
@StackTrace(false)
4043
public class NativeMemoryUsagePeakEvent extends Event {
4144
@Label("Memory Type") public String type;

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,17 @@
2828
import jdk.jfr.Category;
2929
import jdk.jfr.Description;
3030
import jdk.jfr.Event;
31+
import jdk.jfr.Experimental;
3132
import jdk.jfr.Label;
3233
import jdk.jfr.Name;
3334
import jdk.jfr.StackTrace;
3435

35-
@Name("svm.NativeMemoryUsageTotalPeak")
36+
/** Similar to the JFR event jdk.NativeMemoryUsageTotal, except that it tracks the peak usage. */
37+
@Experimental
38+
@Name("jdk.NativeMemoryUsageTotalPeak")
3639
@Label("Native Memory Usage Total Peak")
37-
@Description("Information about native memory peak usage of committed virtual memory and malloc.")
38-
@Category("Native Image")
40+
@Description("Total native memory peak usage for the JVM. Can be slightly smaller than the exact sum of the NativeMemoryUsagePeak events due to timing.")
41+
@Category({"Java Virtual Machine", "Memory"})
3942
@StackTrace(false)
4043
public class NativeMemoryUsageTotalPeakEvent extends Event {
4144
@Label("Peak Usage") public long peakUsage;

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nmt/NativeMemoryTracking.java

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,17 @@
5757
public class NativeMemoryTracking {
5858
private static final UnsignedWord ALIGNMENT = WordFactory.unsigned(16);
5959
private static final int MAGIC = 0xF0F1F2F3;
60-
private final NmtMallocMemorySnapshot mallocMemorySnapshot = new NmtMallocMemorySnapshot();
60+
61+
private final NmtMallocMemoryInfo[] categories;
62+
private final NmtMallocMemoryInfo total;
6163

6264
@Platforms(Platform.HOSTED_ONLY.class)
6365
public NativeMemoryTracking() {
66+
total = new NmtMallocMemoryInfo();
67+
categories = new NmtMallocMemoryInfo[NmtCategory.values().length];
68+
for (int i = 0; i < categories.length; i++) {
69+
categories[i] = new NmtMallocMemoryInfo();
70+
}
6471
}
6572

6673
@Fold
@@ -71,7 +78,7 @@ public static NativeMemoryTracking singleton() {
7178
@Fold
7279
public static UnsignedWord sizeOfNmtHeader() {
7380
/*
74-
* Align the header to 16 bytes to preserve platform-specific malloc alignments up to 16
81+
* Align the header to 16 bytes to preserve platform-specific malloc alignment up to 16
7582
* bytes (i.e., the allocation payload is aligned to 16 bytes if the platform-specific
7683
* malloc implementation returns a pointer that is aligned to at least 16 bytes).
7784
*/
@@ -109,9 +116,9 @@ public void track(PointerBase innerPtr) {
109116
UnsignedWord allocationSize = header.getAllocationSize();
110117
UnsignedWord totalSize = allocationSize.add(nmtHeaderSize);
111118

112-
mallocMemorySnapshot.getInfoByCategory(header.getCategory()).track(allocationSize);
113-
mallocMemorySnapshot.getInfoByCategory(NmtCategory.NMT).track(nmtHeaderSize);
114-
mallocMemorySnapshot.getTotalInfo().track(totalSize);
119+
getInfo(header.getCategory()).track(allocationSize);
120+
getInfo(NmtCategory.NMT).track(nmtHeaderSize);
121+
total.track(totalSize);
115122
}
116123

117124
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
@@ -127,9 +134,9 @@ public PointerBase untrack(PointerBase innerPtr) {
127134

128135
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
129136
public void untrack(UnsignedWord size, int category) {
130-
mallocMemorySnapshot.getInfoByCategory(category).untrack(size);
131-
mallocMemorySnapshot.getInfoByCategory(NmtCategory.NMT).untrack(sizeOfNmtHeader());
132-
mallocMemorySnapshot.getTotalInfo().untrack(size.add(sizeOfNmtHeader()));
137+
getInfo(category).untrack(size);
138+
getInfo(NmtCategory.NMT).untrack(sizeOfNmtHeader());
139+
total.untrack(size.add(sizeOfNmtHeader()));
133140
}
134141

135142
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
@@ -146,44 +153,55 @@ private static Pointer getInnerPointer(NmtMallocHeader mallocHeader) {
146153

147154
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
148155
public long getUsedMemory(NmtCategory category) {
149-
return mallocMemorySnapshot.getInfoByCategory(category).getUsed();
156+
return getInfo(category).getUsed();
150157
}
151158

152159
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
153160
public long getPeakUsedMemory(NmtCategory category) {
154-
return mallocMemorySnapshot.getInfoByCategory(category).getPeakUsed();
161+
return getInfo(category).getPeakUsed();
155162
}
156163

157164
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
158165
public long getCountAtPeakUsage(NmtCategory category) {
159-
return mallocMemorySnapshot.getInfoByCategory(category).getCountAtPeakUsage();
166+
return getInfo(category).getCountAtPeakUsage();
160167
}
161168

162169
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
163170
public long getTotalCount() {
164-
return mallocMemorySnapshot.getTotalInfo().getCount();
171+
return total.getCount();
165172
}
166173

167174
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
168175
public long getTotalUsedMemory() {
169-
return mallocMemorySnapshot.getTotalInfo().getUsed();
176+
return total.getUsed();
170177
}
171178

172179
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
173180
public long getPeakTotalUsedMemory() {
174-
return mallocMemorySnapshot.getTotalInfo().getPeakUsed();
181+
return total.getPeakUsed();
175182
}
176183

177184
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
178185
public long getCountAtTotalPeakUsage() {
179-
return mallocMemorySnapshot.getTotalInfo().getCountAtPeakUsage();
186+
return total.getCountAtPeakUsage();
187+
}
188+
189+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
190+
private NmtMallocMemoryInfo getInfo(NmtCategory category) {
191+
return getInfo(category.ordinal());
192+
}
193+
194+
@Uninterruptible(reason = "Called from uninterruptible code.", mayBeInlined = true)
195+
private NmtMallocMemoryInfo getInfo(int category) {
196+
assert category < categories.length;
197+
return categories[category];
180198
}
181199

182200
public static RuntimeSupport.Hook shutdownHook() {
183201
return isFirstIsolate -> NativeMemoryTracking.singleton().printStatistics();
184202
}
185203

186-
public void printStatistics() {
204+
private void printStatistics() {
187205
if (VMInspectionOptions.PrintNMTStatistics.getValue()) {
188206
System.out.println();
189207
System.out.println("Native memory tracking");
@@ -194,12 +212,12 @@ public void printStatistics() {
194212

195213
for (int i = 0; i < NmtCategory.values().length; i++) {
196214
String name = NmtCategory.values()[i].getName();
197-
NmtMallocMemoryInfo info = mallocMemorySnapshot.getInfoByCategory(i);
215+
NmtMallocMemoryInfo info = getInfo(i);
198216

199217
System.out.println(" " + name + " peak used memory: " + info.getPeakUsed() + " bytes");
200218
System.out.println(" " + name + " alive allocations at peak: " + info.getCountAtPeakUsage());
201-
System.out.println(" " + name + " used memory: " + info.getUsed() + " bytes");
202-
System.out.println(" " + name + " alive allocations: " + info.getCount());
219+
System.out.println(" " + name + " currently used memory: " + info.getUsed() + " bytes");
220+
System.out.println(" " + name + " currently alive allocations: " + info.getCount());
203221
}
204222
}
205223
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/nmt/NmtMallocMemoryInfo.java

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,38 +35,33 @@
3535
import com.oracle.svm.core.Uninterruptible;
3636
import com.oracle.svm.core.jdk.UninterruptibleUtils.AtomicLong;
3737

38-
import jdk.internal.misc.Unsafe;
39-
4038
class NmtMallocMemoryInfo {
41-
private static final Unsafe U = Unsafe.getUnsafe();
42-
protected static final long PEAK_USAGE_OFFSET = U.objectFieldOffset(NmtMallocMemoryInfo.class, "peakUsage");
4339
private final AtomicLong count = new AtomicLong(0);
4440
private final AtomicLong used = new AtomicLong(0);
45-
private volatile long peakUsage;
46-
private volatile long peakCount;
41+
private final AtomicLong countAtPeakUsage = new AtomicLong(0);
42+
private final AtomicLong peakUsed = new AtomicLong(0);
4743

4844
@Platforms(Platform.HOSTED_ONLY.class)
4945
NmtMallocMemoryInfo() {
5046
}
5147

5248
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
5349
void track(UnsignedWord allocationSize) {
54-
/*
55-
* Similar to Hotspot, we only make a best effort to record the count at the time of the
56-
* peak. Observing the memory used and count is not together atomic.
57-
*/
58-
updatePeak(used.addAndGet(allocationSize.rawValue()), count.incrementAndGet());
50+
long newUsed = used.addAndGet(allocationSize.rawValue());
51+
long newCount = count.incrementAndGet();
52+
updatePeak(newUsed, newCount);
5953
}
6054

6155
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
6256
private void updatePeak(long newUsed, long newCount) {
63-
long expectedPeakUsage = peakUsage;
64-
while (expectedPeakUsage < newUsed) {
65-
if (U.compareAndSetLong(this, PEAK_USAGE_OFFSET, expectedPeakUsage, newUsed)) {
66-
peakCount = newCount;
57+
long oldUsed = peakUsed.get();
58+
while (oldUsed < newUsed) {
59+
if (peakUsed.compareAndSet(oldUsed, newUsed)) {
60+
/* Recording the count at peak usage is racy (similar to Hotspot). */
61+
countAtPeakUsage.set(newCount);
6762
return;
6863
}
69-
expectedPeakUsage = peakUsage;
64+
oldUsed = peakUsed.get();
7065
}
7166
}
7267

@@ -89,11 +84,11 @@ long getCount() {
8984

9085
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
9186
long getPeakUsed() {
92-
return peakUsage;
87+
return peakUsed.get();
9388
}
9489

9590
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
9691
long getCountAtPeakUsage() {
97-
return peakCount;
92+
return countAtPeakUsage.get();
9893
}
9994
}

0 commit comments

Comments
 (0)