Skip to content

Commit 2bc5cdf

Browse files
add NMT peak events
1 parent 8ef5550 commit 2bc5cdf

File tree

5 files changed

+161
-19
lines changed

5 files changed

+161
-19
lines changed

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

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,24 +107,37 @@ private static void emitClassLoadingStatistics() {
107107
}
108108
}
109109

110-
private static void emitNativeMemoryTrackingEvents() {
111-
if (VMInspectionOptions.hasNativeMemoryTrackingSupport()) {
112-
emitNativeMemoryTrackingEvents0(NmtCategory.values());
113-
}
114-
}
115-
116110
/**
117111
* Emit events for NativeMemoryUsage and NativeMemoryUsageTotal. We do not guarantee consistent
118112
* measurements across NMT categories and the total. Each individual NMT category uses atomic
119113
* counters which may change while we are in this method. Similar to OpenJDK, it is only a
120114
* best-effort approach.
121115
*/
116+
private static void emitNativeMemoryTrackingEvents() {
117+
if (VMInspectionOptions.hasNativeMemoryTrackingSupport()) {
118+
/* All NMT events should have a consistent timestamp. */
119+
long timestamp = JfrTicks.elapsedTicks();
120+
emitNativeMemoryTrackingEvents0(NmtCategory.values(), timestamp);
121+
122+
NativeMemoryUsageTotalPeakEvent nmtTotalPeakEvent = new NativeMemoryUsageTotalPeakEvent();
123+
nmtTotalPeakEvent.countAtPeak = NativeMemoryTracking.singleton().getCountAtTotalPeakUsage();
124+
nmtTotalPeakEvent.peakUsage = NativeMemoryTracking.singleton().getPeakTotalUsedMemory();
125+
nmtTotalPeakEvent.commit();
126+
127+
for (NmtCategory nmtCategory : NmtCategory.values()) {
128+
NativeMemoryUsagePeakEvent nmtPeakEvent = new NativeMemoryUsagePeakEvent();
129+
nmtPeakEvent.type = nmtCategory.getName();
130+
nmtPeakEvent.countAtPeak = NativeMemoryTracking.singleton().getCountAtPeakUsage(nmtCategory);
131+
nmtPeakEvent.peakUsage = NativeMemoryTracking.singleton().getPeakUsedMemory(nmtCategory);
132+
nmtPeakEvent.commit();
133+
}
134+
}
135+
}
136+
122137
@Uninterruptible(reason = "Accesses a JFR buffer.")
123-
private static void emitNativeMemoryTrackingEvents0(NmtCategory[] nmtCategories) {
138+
private static void emitNativeMemoryTrackingEvents0(NmtCategory[] nmtCategories, long timestamp) {
124139
JfrNativeEventWriterData data = StackValue.get(JfrNativeEventWriterData.class);
125140
JfrNativeEventWriterDataAccess.initializeThreadLocalNativeBuffer(data);
126-
/* All NMT events should have a consistent timestamp. */
127-
long timestamp = JfrTicks.elapsedTicks();
128141

129142
if (JfrEvent.NativeMemoryUsage.shouldEmit()) {
130143
for (NmtCategory nmtCategory : nmtCategories) {
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, 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.jfr.events;
27+
28+
import jdk.jfr.Category;
29+
import jdk.jfr.Description;
30+
import jdk.jfr.Event;
31+
import jdk.jfr.Label;
32+
import jdk.jfr.Name;
33+
import jdk.jfr.StackTrace;
34+
35+
@Name("svm.NativeMemoryUsagePeak")
36+
@Label("Native Memory Usage Peak")
37+
@Description("Information about native memory peak usage of committed virtual memory and malloc.")
38+
@Category("Native Image")
39+
@StackTrace(false)
40+
public class NativeMemoryUsagePeakEvent extends Event {
41+
@Label("Memory Type") public String type;
42+
@Label("Peak Usage") public long peakUsage;
43+
@Label("CountAtPeak") public long countAtPeak;
44+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved.
3+
* Copyright (c) 2024, 2024, 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.jfr.events;
27+
28+
import jdk.jfr.Category;
29+
import jdk.jfr.Description;
30+
import jdk.jfr.Event;
31+
import jdk.jfr.Label;
32+
import jdk.jfr.Name;
33+
import jdk.jfr.StackTrace;
34+
35+
@Name("svm.NativeMemoryUsageTotalPeak")
36+
@Label("Native Memory Usage Total Peak")
37+
@Description("Information about native memory peak usage")
38+
@Category("Native Image")
39+
@StackTrace(false)
40+
public class NativeMemoryUsageTotalPeakEvent extends Event {
41+
@Label("PeakUsage") public long peakUsage;
42+
@Label("CountAtPeak") public long countAtPeak;
43+
}

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,36 @@ public long getUsedMemory(NmtCategory category) {
149149
return mallocMemorySnapshot.getInfoByCategory(category).getUsed();
150150
}
151151

152+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
153+
public long getPeakUsedMemory(NmtCategory category) {
154+
return mallocMemorySnapshot.getInfoByCategory(category).getPeakUsed();
155+
}
156+
157+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
158+
public long getCountAtPeakUsage(NmtCategory category) {
159+
return mallocMemorySnapshot.getInfoByCategory(category).getCountAtPeakUsage();
160+
}
161+
162+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
163+
public long getTotalCount() {
164+
return mallocMemorySnapshot.getTotalInfo().getCount();
165+
}
166+
152167
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
153168
public long getTotalUsedMemory() {
154169
return mallocMemorySnapshot.getTotalInfo().getUsed();
155170
}
156171

172+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
173+
public long getPeakTotalUsedMemory() {
174+
return mallocMemorySnapshot.getTotalInfo().getPeakUsed();
175+
}
176+
177+
@Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
178+
public long getCountAtTotalPeakUsage() {
179+
return mallocMemorySnapshot.getTotalInfo().getCountAtPeakUsage();
180+
}
181+
157182
public static RuntimeSupport.Hook shutdownHook() {
158183
return isFirstIsolate -> NativeMemoryTracking.singleton().printStatistics();
159184
}
@@ -162,10 +187,10 @@ public void printStatistics() {
162187
if (VMInspectionOptions.PrintNMTStatistics.getValue()) {
163188
System.out.println();
164189
System.out.println("Native memory tracking");
165-
System.out.println(" Peak total used memory: " + mallocMemorySnapshot.getTotalInfo().getPeakUsed() + " bytes");
166-
System.out.println(" Total alive allocations at peak usage: " + mallocMemorySnapshot.getTotalInfo().getCountAtPeakUsage());
167-
System.out.println(" Total used memory: " + mallocMemorySnapshot.getTotalInfo().getUsed() + " bytes");
168-
System.out.println(" Total alive allocations: " + mallocMemorySnapshot.getTotalInfo().getCount());
190+
System.out.println(" Peak total used memory: " + getPeakTotalUsedMemory() + " bytes");
191+
System.out.println(" Total alive allocations at peak usage: " + getCountAtTotalPeakUsage());
192+
System.out.println(" Total used memory: " + getTotalUsedMemory() + " bytes");
193+
System.out.println(" Total alive allocations: " + getTotalCount());
169194

170195
for (int i = 0; i < NmtCategory.values().length; i++) {
171196
String name = NmtCategory.values()[i].getName();

substratevm/src/com.oracle.svm.test/src/com/oracle/svm/test/jfr/TestNmtEvents.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ public class TestNmtEvents extends JfrRecordingTest {
4646

4747
@Test
4848
public void test() throws Throwable {
49-
String[] events = new String[]{JfrEvent.NativeMemoryUsage.getName(), JfrEvent.NativeMemoryUsageTotal.getName()};
49+
String[] events = new String[]{
50+
JfrEvent.NativeMemoryUsage.getName(),
51+
JfrEvent.NativeMemoryUsageTotal.getName(),
52+
"svm.NativeMemoryUsageTotalPeak",
53+
"svm.NativeMemoryUsagePeak"
54+
};
55+
5056
Recording recording = startRecording(events);
5157

5258
Pointer ptr = NativeMemory.malloc(WordFactory.unsigned(ALLOCATION_SIZE), NmtCategory.Code);
@@ -62,18 +68,29 @@ public void test() throws Throwable {
6268
private static void validateEvents(List<RecordedEvent> events) {
6369
boolean foundNativeMemoryUsage = false;
6470
boolean foundNativeMemoryUsageTotal = false;
71+
boolean foundNativeMemoryUsageTotalPeak = false;
72+
boolean foundNativeMemoryUsagePeak = false;
6573

66-
assertTrue(events.size() >= 2);
74+
assertTrue(events.size() >= 4);
6775
for (RecordedEvent e : events) {
68-
if (e.getEventType().getName().equals(JfrEvent.NativeMemoryUsage.getName())) {
69-
if (e.getString("type").equals(NmtCategory.Code.getName())) {
70-
foundNativeMemoryUsage = true;
71-
}
76+
if (e.getEventType().getName().equals(JfrEvent.NativeMemoryUsage.getName()) &&
77+
e.getString("type").equals(NmtCategory.Code.getName())) {
78+
foundNativeMemoryUsage = true;
79+
80+
}
81+
if (e.getEventType().getName().equals("svm.NativeMemoryUsageTotalPeak")) {
82+
foundNativeMemoryUsageTotalPeak = true;
83+
}
84+
if (e.getEventType().getName().equals("svm.NativeMemoryUsagePeak") &&
85+
e.getString("type").equals(NmtCategory.Code.getName())) {
86+
foundNativeMemoryUsagePeak = true;
7287
} else if (e.getEventType().getName().equals(JfrEvent.NativeMemoryUsageTotal.getName())) {
7388
foundNativeMemoryUsageTotal = true;
7489
}
7590
}
7691
assertTrue(foundNativeMemoryUsage);
7792
assertTrue(foundNativeMemoryUsageTotal);
93+
assertTrue(foundNativeMemoryUsagePeak);
94+
assertTrue(foundNativeMemoryUsageTotalPeak);
7895
}
7996
}

0 commit comments

Comments
 (0)