Skip to content

Commit 1923bf4

Browse files
GC notifications
1 parent a8efbf7 commit 1923bf4

21 files changed

+1002
-69
lines changed

substratevm/mx.substratevm/suite.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,9 @@
356356
"java.management": [
357357
"sun.management",
358358
],
359+
"jdk.management": [
360+
"com.sun.management.internal"
361+
],
359362
"jdk.internal.vm.ci" : [
360363
"jdk.vm.ci.code",
361364
],
@@ -994,6 +997,9 @@
994997
"jdk.internal.misc",
995998
"sun.security.jca",
996999
],
1000+
"java.management": [
1001+
"sun.management",
1002+
],
9971003
},
9981004
"checkstyle": "com.oracle.svm.test",
9991005
"checkstyleVersion" : "10.7.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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.genscavenge;
27+
28+
import com.oracle.svm.core.util.BasedOnJDKFile;
29+
30+
import com.oracle.svm.core.SubstrateUtil;
31+
import com.oracle.svm.core.genscavenge.service.GcNotificationRequest;
32+
import com.oracle.svm.core.genscavenge.service.PoolMemoryUsage;
33+
import com.oracle.svm.core.genscavenge.service.Target_com_sun_management_GcInfo;
34+
import com.oracle.svm.core.genscavenge.service.Target_com_sun_management_internal_GcInfoBuilder;
35+
36+
import com.sun.management.GarbageCollectionNotificationInfo;
37+
import com.sun.management.GcInfo;
38+
import com.sun.management.internal.GarbageCollectionNotifInfoCompositeData;
39+
import com.sun.management.internal.GcInfoBuilder;
40+
import sun.management.NotificationEmitterSupport;
41+
42+
import javax.management.MBeanNotificationInfo;
43+
import javax.management.Notification;
44+
import javax.management.NotificationEmitter;
45+
import javax.management.openmbean.CompositeData;
46+
import java.lang.management.MemoryUsage;
47+
48+
public abstract class AbstractGarbageCollectorMXBean extends NotificationEmitterSupport
49+
implements com.sun.management.GarbageCollectorMXBean, NotificationEmitter {
50+
51+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+14/src/hotspot/share/gc/serial/serialHeap.cpp#L451") //
52+
private static final String ACTION_MINOR = "end of minor GC";
53+
54+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/jdk-24+14/src/hotspot/share/gc/serial/serialHeap.cpp#L718") //
55+
private static final String ACTION_MAJOR = "end of major GC";
56+
57+
private GcInfoBuilder gcInfoBuilder;
58+
private volatile GcInfo gcInfo;
59+
private long seqNumber = 0;
60+
61+
private synchronized GcInfoBuilder getGcInfoBuilder() {
62+
if (gcInfoBuilder == null) {
63+
Target_com_sun_management_internal_GcInfoBuilder gib = new Target_com_sun_management_internal_GcInfoBuilder(this, getMemoryPoolNames());
64+
gcInfoBuilder = SubstrateUtil.cast(gib, GcInfoBuilder.class);
65+
}
66+
return gcInfoBuilder;
67+
}
68+
69+
/**
70+
* Use the data taken from the request queue to populate MemoryUsage. The service thread calls
71+
* this method.
72+
*/
73+
public void createNotification(GcNotificationRequest request) {
74+
AbstractMemoryPoolMXBean[] beans = GenScavengeMemoryPoolMXBeans.singleton().getMXBeans();
75+
76+
String[] poolNames = getMemoryPoolNames();
77+
MemoryUsage[] before = new MemoryUsage[poolNames.length];
78+
MemoryUsage[] after = new MemoryUsage[poolNames.length];
79+
80+
// Pools must be in the order of getMemoryPoolNames() to match GcInfoBuilder
81+
for (int i = 0; i < poolNames.length; i++) {
82+
for (int j = 0; j < beans.length; j++) {
83+
PoolMemoryUsage pmu = request.getPoolBefore(j);
84+
if (pmu.name != null && pmu.name.equals(poolNames[i])) {
85+
before[i] = beans[j].memoryUsage(pmu.used, pmu.committed);
86+
pmu = request.getPoolAfter(j);
87+
after[i] = beans[j].memoryUsage(pmu.used, pmu.committed);
88+
}
89+
}
90+
}
91+
92+
// Number of GC threads.
93+
Object[] extAttribute = new Object[]{Integer.valueOf(1)};
94+
95+
Target_com_sun_management_GcInfo targetGcInfo = new Target_com_sun_management_GcInfo(getGcInfoBuilder(), request.epoch, request.startTime, request.endTime, before, after, extAttribute);
96+
gcInfo = SubstrateUtil.cast(targetGcInfo, GcInfo.class);
97+
98+
GarbageCollectionNotificationInfo info = new GarbageCollectionNotificationInfo(
99+
getName(),
100+
request.isIncremental ? ACTION_MINOR : ACTION_MAJOR,
101+
request.cause.getName(),
102+
gcInfo);
103+
104+
CompositeData cd = GarbageCollectionNotifInfoCompositeData.toCompositeData(info);
105+
106+
Notification notif = new Notification(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION,
107+
getObjectName(),
108+
getNextSeqNumber(),
109+
request.timestamp,
110+
getName());
111+
notif.setUserData(cd);
112+
113+
sendNotification(notif);
114+
}
115+
116+
private long getNextSeqNumber() {
117+
return ++seqNumber;
118+
}
119+
120+
@Override
121+
public MBeanNotificationInfo[] getNotificationInfo() {
122+
return new MBeanNotificationInfo[]{
123+
new MBeanNotificationInfo(
124+
new String[]{GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION},
125+
"javax.management.Notification",
126+
"GC Notification")
127+
};
128+
}
129+
130+
@Override
131+
public GcInfo getLastGcInfo() {
132+
return gcInfo;
133+
}
134+
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,28 @@ UnsignedWord getInitialValue() {
6666
return initialValue;
6767
}
6868

69+
public abstract UnsignedWord getUsedBytes();
70+
71+
public UnsignedWord getCommittedBytes() {
72+
return getUsedBytes();
73+
}
74+
6975
abstract UnsignedWord computeInitialValue();
7076

7177
abstract void beforeCollection();
7278

7379
abstract void afterCollection();
7480

7581
MemoryUsage memoryUsage(UnsignedWord usedAndCommitted) {
76-
return new MemoryUsage(getInitialValue().rawValue(), usedAndCommitted.rawValue(), usedAndCommitted.rawValue(), getMaximumValue().rawValue());
82+
return memoryUsage(usedAndCommitted, usedAndCommitted);
7783
}
7884

7985
MemoryUsage memoryUsage(UnsignedWord used, UnsignedWord committed) {
80-
return new MemoryUsage(getInitialValue().rawValue(), used.rawValue(), committed.rawValue(), getMaximumValue().rawValue());
86+
return memoryUsage(used.rawValue(), committed.rawValue());
87+
}
88+
89+
public MemoryUsage memoryUsage(long used, long committed) {
90+
return new MemoryUsage(getInitialValue().rawValue(), used, committed, getMaximumValue().rawValue());
8191
}
8292

8393
@Override

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

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,16 @@
2626

2727
import java.lang.management.ManagementFactory;
2828

29-
import javax.management.MBeanNotificationInfo;
30-
import javax.management.NotificationEmitter;
31-
import javax.management.NotificationFilter;
32-
import javax.management.NotificationListener;
3329
import javax.management.ObjectName;
3430

3531
import org.graalvm.nativeimage.Platform;
3632
import org.graalvm.nativeimage.Platforms;
3733

3834
import com.oracle.svm.core.util.TimeUtils;
39-
import com.sun.management.GcInfo;
4035

4136
import sun.management.Util;
4237

43-
public final class CompleteGarbageCollectorMXBean implements com.sun.management.GarbageCollectorMXBean, NotificationEmitter {
38+
public final class CompleteGarbageCollectorMXBean extends AbstractGarbageCollectorMXBean {
4439

4540
@Platforms(Platform.HOSTED_ONLY.class)
4641
public CompleteGarbageCollectorMXBean() {
@@ -81,26 +76,4 @@ public boolean isValid() {
8176
public ObjectName getObjectName() {
8277
return Util.newObjectName(ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE, getName());
8378
}
84-
85-
@Override
86-
public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) {
87-
}
88-
89-
@Override
90-
public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) {
91-
}
92-
93-
@Override
94-
public void removeNotificationListener(NotificationListener listener) {
95-
}
96-
97-
@Override
98-
public MBeanNotificationInfo[] getNotificationInfo() {
99-
return new MBeanNotificationInfo[0];
100-
}
101-
102-
@Override
103-
public GcInfo getLastGcInfo() {
104-
return null;
105-
}
10679
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import com.oracle.svm.core.genscavenge.HeapChunk.Header;
6767
import com.oracle.svm.core.genscavenge.UnalignedHeapChunk.UnalignedHeader;
6868
import com.oracle.svm.core.genscavenge.remset.RememberedSet;
69+
import com.oracle.svm.core.genscavenge.service.ServiceSupport;
6970
import com.oracle.svm.core.graal.RuntimeCompilation;
7071
import com.oracle.svm.core.heap.CodeReferenceMapDecoder;
7172
import com.oracle.svm.core.heap.GC;
@@ -103,6 +104,7 @@
103104
import com.oracle.svm.core.threadlocal.VMThreadLocalSupport;
104105
import com.oracle.svm.core.util.TimeUtils;
105106
import com.oracle.svm.core.util.VMError;
107+
import com.oracle.svm.core.VMInspectionOptions;
106108

107109
import jdk.graal.compiler.api.replacements.Fold;
108110

@@ -240,6 +242,9 @@ assert getCollectionEpoch().equal(data.getRequestingEpoch()) ||
240242
try {
241243
ThreadLocalAllocation.disableAndFlushForAllThreads();
242244
GenScavengeMemoryPoolMXBeans.singleton().notifyBeforeCollection();
245+
if (VMInspectionOptions.hasGcNotificationSupport()) {
246+
ServiceSupport.singleton().beforeCollection(Isolates.getCurrentUptimeMillis());
247+
}
243248
HeapImpl.getAccounting().notifyBeforeCollection();
244249

245250
verifyHeap(Before);
@@ -257,6 +262,10 @@ assert getCollectionEpoch().equal(data.getRequestingEpoch()) ||
257262
GenScavengeMemoryPoolMXBeans.singleton().notifyAfterCollection();
258263
ChunkBasedCommittedMemoryProvider.get().afterGarbageCollection();
259264

265+
if (VMInspectionOptions.hasGcNotificationSupport()) {
266+
ServiceSupport.singleton().afterCollection(!isCompleteCollection(), cause, getCollectionEpoch(), Isolates.getCurrentUptimeMillis());
267+
}
268+
260269
printGCAfter(cause);
261270
JfrGCHeapSummaryEvent.emit(JfrGCWhen.AFTER_GC);
262271

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

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@
3939
import jdk.graal.compiler.api.replacements.Fold;
4040

4141
public class GenScavengeMemoryPoolMXBeans {
42-
static final String YOUNG_GEN_SCAVENGER = "young generation scavenger";
43-
static final String COMPLETE_SCAVENGER = "complete scavenger";
42+
public static final String YOUNG_GEN_SCAVENGER = "young generation scavenger";
43+
public static final String COMPLETE_SCAVENGER = "complete scavenger";
4444
static final String EPSILON_SCAVENGER = "epsilon scavenger";
4545

4646
static final String EDEN_SPACE = "eden space";
4747
static final String SURVIVOR_SPACE = "survivor space";
48-
static final String OLD_GEN_SPACE = "old generation space";
48+
public static final String OLD_GEN_SPACE = "old generation space";
4949
static final String EPSILON_HEAP = "epsilon heap";
5050

5151
private final AbstractMemoryPoolMXBean[] mxBeans;
@@ -111,12 +111,12 @@ UnsignedWord computeInitialValue() {
111111

112112
@Override
113113
public MemoryUsage getUsage() {
114-
return memoryUsage(getCurrentUsage());
114+
return memoryUsage(getUsedBytes());
115115
}
116116

117117
@Override
118118
public MemoryUsage getPeakUsage() {
119-
updatePeakUsage(getCurrentUsage());
119+
updatePeakUsage(getUsedBytes());
120120
return memoryUsage(peakUsage.get());
121121
}
122122

@@ -125,7 +125,8 @@ public MemoryUsage getCollectionUsage() {
125125
return memoryUsage(WordFactory.zero());
126126
}
127127

128-
private static UnsignedWord getCurrentUsage() {
128+
@Override
129+
public UnsignedWord getUsedBytes() {
129130
return HeapImpl.getAccounting().getEdenUsedBytes();
130131
}
131132
}
@@ -166,6 +167,11 @@ public MemoryUsage getPeakUsage() {
166167
public MemoryUsage getCollectionUsage() {
167168
return memoryUsage(HeapImpl.getAccounting().getSurvivorUsedBytes());
168169
}
170+
171+
@Override
172+
public UnsignedWord getUsedBytes() {
173+
return HeapImpl.getAccounting().getSurvivorUsedBytes();
174+
}
169175
}
170176

171177
static final class OldGenerationMemoryPoolMXBean extends AbstractMemoryPoolMXBean {
@@ -204,6 +210,11 @@ public MemoryUsage getPeakUsage() {
204210
public MemoryUsage getCollectionUsage() {
205211
return memoryUsage(HeapImpl.getAccounting().getOldUsedBytes());
206212
}
213+
214+
@Override
215+
public UnsignedWord getUsedBytes() {
216+
return HeapImpl.getAccounting().getOldUsedBytes();
217+
}
207218
}
208219

209220
static final class EpsilonMemoryPoolMXBean extends AbstractMemoryPoolMXBean {
@@ -243,5 +254,15 @@ public MemoryUsage getPeakUsage() {
243254
public MemoryUsage getCollectionUsage() {
244255
return memoryUsage(WordFactory.zero());
245256
}
257+
258+
@Override
259+
public UnsignedWord getUsedBytes() {
260+
return HeapImpl.getAccounting().getUsedBytes();
261+
}
262+
263+
@Override
264+
public UnsignedWord getCommittedBytes() {
265+
return HeapImpl.getAccounting().getCommittedBytes();
266+
}
246267
}
247268
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void notifyAfterCollection() {
7979
invalidData = false;
8080
}
8181

82-
HeapSizes getHeapSizesBeforeGc() {
82+
public HeapSizes getHeapSizesBeforeGc() {
8383
return beforeGc;
8484
}
8585

0 commit comments

Comments
 (0)