27
27
package com .oracle .svm .core .jfr .events ;
28
28
29
29
import com .oracle .svm .core .Uninterruptible ;
30
- import com .oracle .svm .core .UnmanagedMemoryUtil ;
31
30
import com .oracle .svm .core .heap .Heap ;
32
31
import com .oracle .svm .core .heap .ObjectVisitor ;
33
- import com .oracle .svm .core .heap .VMOperationInfos ;
34
32
import com .oracle .svm .core .hub .DynamicHub ;
35
33
import com .oracle .svm .core .hub .DynamicHubSupport ;
36
34
import com .oracle .svm .core .hub .LayoutEncoding ;
37
35
import com .oracle .svm .core .jfr .HasJfrSupport ;
38
36
import com .oracle .svm .core .jfr .JfrEvent ;
39
37
import com .oracle .svm .core .jfr .SubstrateJVM ;
40
- import com .oracle .svm .core .jfr .events .ObjectCountEvents ;
41
38
import com .oracle .svm .core .jfr .utils .PointerArray ;
42
39
import com .oracle .svm .core .jfr .utils .PointerArrayAccess ;
43
- import com .oracle .svm .core .thread .NativeVMOperation ;
44
- import com .oracle .svm .core .thread .NativeVMOperationData ;
45
- import com .oracle .svm .core .thread .VMOperation .SystemEffect ;
46
40
import com .oracle .svm .core .thread .VMOperation ;
47
41
import com .oracle .svm .core .util .VMError ;
48
42
55
49
import org .graalvm .nativeimage .c .struct .SizeOf ;
56
50
import org .graalvm .nativeimage .impl .UnmanagedMemorySupport ;
57
51
58
- import org .graalvm .word .Pointer ;
59
52
import org .graalvm .word .PointerBase ;
60
- import org .graalvm .word .WordFactory ;
61
53
62
54
public class ObjectCountEventSupport {
63
- private final static ObjectCountVisitor objectCountVisitor = new ObjectCountVisitor ();
64
- // private static final ObjectCountOperation objectCountOperation = new ObjectCountOperation();
65
- private static double cutoffPercentage = 0.005 ; // *** don't need user input for this. Hotspot simply hardcodes this
66
- private static long totalSize ;
67
-
68
- // *** should be volatile because periodic thread writes it and VM op thread reads it
55
+ private static final double CUTOFF_PERCENTAGE = 0.005 ;
56
+ private static final ObjectCountVisitor objectCountVisitor = new ObjectCountVisitor ();
69
57
private static volatile boolean shouldSendRequestableEvent = false ;
70
58
71
59
@ Platforms (HOSTED_ONLY .class )
72
60
ObjectCountEventSupport () {
73
61
}
74
62
75
63
@ Uninterruptible (reason = "Set and unset should be atomic with invoked GC." , callerMustBe = true )
76
- public static void setShouldSendRequestableEvent (boolean value ){
64
+ public static void setShouldSendRequestableEvent (boolean value ) {
77
65
shouldSendRequestableEvent = value ;
78
66
}
79
67
80
- public static void emitEvents (int gcId , long startTicks ){
68
+ public static void emitEvents (int gcId , long startTicks ) {
81
69
if (HasJfrSupport .get () && shouldEmitEvents ()) {
82
- emitEvents0 (gcId , startTicks );
83
- // if (shouldSendRequestableEvent){
84
- // shouldSendRequestableEvent = false;
85
- // }
70
+ emitEvents0 (gcId , startTicks );
86
71
}
87
72
}
88
73
89
- /** ShouldEmit will be checked again later. This is merely an optimization.*/
74
+ /** ShouldEmit will be checked again later. This is merely an optimization. */
90
75
@ Uninterruptible (reason = "Caller of JfrEvent#shouldEmit must be uninterruptible." )
91
- private static boolean shouldEmitEvents (){
76
+ private static boolean shouldEmitEvents () {
92
77
return shouldSendRequestableEvent || JfrEvent .ObjectCountAfterGC .shouldEmit ();
93
78
}
79
+
94
80
private static void emitEvents0 (int gcId , long startTicks ) {
95
81
PointerArray objectCounts = StackValue .get (PointerArray .class );
96
82
try {
@@ -99,79 +85,34 @@ private static void emitEvents0(int gcId, long startTicks) {
99
85
return ;
100
86
}
101
87
102
- // Throw an error, otherwise we'll probably get a segfault later
103
- VMError .guarantee (objectCounts .getSize () == initialCapacity , "init not done properly" );
104
- countObjects (objectCounts );
88
+ long totalSize = visitObjects (objectCounts );
105
89
106
90
for (int i = 0 ; i < objectCounts .getSize (); i ++) {
107
- emitForTypeId (i , objectCounts , gcId , startTicks );
91
+ emitForTypeId (i , objectCounts , gcId , startTicks , totalSize );
108
92
}
109
93
} finally {
110
94
PointerArrayAccess .freeData (objectCounts );
111
95
}
112
96
}
113
97
114
- private static void emitForTypeId (int typeId , PointerArray objectCounts , int gcId , long startTicks ) {
98
+ private static void emitForTypeId (int typeId , PointerArray objectCounts , int gcId , long startTicks , long totalSize ) {
115
99
ObjectCountData objectCountData = (ObjectCountData ) PointerArrayAccess .get (objectCounts , typeId );
116
- if (objectCountData .isNonNull () && objectCountData .getSize () / (double ) totalSize > cutoffPercentage ) {
117
- VMError .guarantee (objectCountData .getSize () > 0 && objectCountData .getTraceId () >0 && objectCountData .getSize ()> 0 , "size should be > 0 if count is > 0" );
100
+ if (objectCountData .isNonNull () && objectCountData .getSize () / (double ) totalSize > CUTOFF_PERCENTAGE ) {
101
+ VMError .guarantee (objectCountData .getSize () > 0 && objectCountData .getTraceId () > 0 && objectCountData .getSize () > 0 , "size should be > 0 if count is > 0" );
118
102
if (shouldSendRequestableEvent ) {
119
103
ObjectCountEvents .emit (JfrEvent .ObjectCount , startTicks , objectCountData .getTraceId (), objectCountData .getCount (), objectCountData .getSize (), gcId );
120
104
}
121
105
ObjectCountEvents .emit (JfrEvent .ObjectCountAfterGC , startTicks , objectCountData .getTraceId (), objectCountData .getCount (), objectCountData .getSize (), gcId );
122
106
}
123
107
}
124
108
125
- private static void countObjects (PointerArray objectCounts ) {
109
+ private static long visitObjects (PointerArray objectCounts ) {
126
110
assert VMOperation .isGCInProgress ();
127
- // int size = SizeOf.get(ObjectCountVMOperationData.class);
128
- // ObjectCountVMOperationData vmOpData = StackValue.get(size);
129
- // UnmanagedMemoryUtil.fill((Pointer) vmOpData, WordFactory.unsigned(size), (byte) 0);
130
-
131
- // vmOpData.setObjectCounts(objectCounts);
132
- // objectCountOperation.enqueue(vmOpData);
133
- // objectCountVisitor.initialize(vmOpData.getObjectCounts());
134
111
objectCountVisitor .initialize (objectCounts );
135
- totalSize = 0 ; // compute anew each time we operate
136
112
Heap .getHeap ().walkImageHeapObjects (objectCountVisitor );
137
-
138
- int sizeSum = 0 ;
139
- int countSum = 0 ;
140
- for (int i = 0 ; i < objectCounts .getSize (); i ++) {
141
- ObjectCountData objectCountData = (ObjectCountData ) PointerArrayAccess .get (objectCounts , i );
142
- if (objectCountData .isNull ()) {
143
- continue ;
144
- }
145
- countSum += objectCountData .getCount ();
146
- sizeSum += objectCountData .getSize ();
147
- VMError .guarantee (objectCountData .getSize () > 0 , "size should be > 0 if count is > 0" );
148
- }
149
-
150
- VMError .guarantee (countSum > 0 , "countSum should be >0" );
151
- VMError .guarantee (sizeSum > 0 , "sizeSum should be >0" );
152
-
153
- int typeId = DynamicHub .fromClass (String .class ).getTypeID ();
154
- ObjectCountData stringOcd = objectCounts .getData ().addressOf (typeId ).read ();
155
- VMError .guarantee (stringOcd .getCount () > 0 , "should have more than 1 String in heap" );
156
- VMError .guarantee (stringOcd .getSize () > 0 , "string size should be positive" );
113
+ return objectCountVisitor .getTotalSize ();
157
114
}
158
115
159
- // private static class ObjectCountOperation extends NativeVMOperation {
160
- // @Platforms(HOSTED_ONLY.class)
161
- // ObjectCountOperation() {
162
- // super(VMOperationInfos.get(ObjectCountOperation.class, "JFR count objects", SystemEffect.SAFEPOINT));
163
- // }
164
- //
165
- // @Override
166
- // protected void operate(NativeVMOperationData data) {
167
- // ObjectCountVMOperationData objectCountVMOperationData = (ObjectCountVMOperationData) data;
168
- // objectCountVisitor.initialize(objectCountVMOperationData.getObjectCounts());
169
- // totalSize = 0; // compute anew each time we operate
170
- // Heap.getHeap().walkImageHeapObjects(objectCountVisitor);
171
- // }
172
- // }
173
-
174
-
175
116
private static boolean initializeObjectCountData (PointerArray pointerArray , int idx , Object obj ) {
176
117
ObjectCountData objectCountData = ImageSingletons .lookup (UnmanagedMemorySupport .class ).malloc (SizeOf .unsigned (ObjectCountData .class ));
177
118
if (objectCountData .isNull ()) {
@@ -184,33 +125,37 @@ private static boolean initializeObjectCountData(PointerArray pointerArray, int
184
125
return true ;
185
126
}
186
127
187
- /** JFR epoch will not change before associated ObjectCount event is committed because this code runs within a
188
- * GC safepoint.*/ //*** epoch cannot change bc we already are in a safepoint // TODO revisit this logic
128
+ /**
129
+ * It's ok to ge the trace ID here because JFR epoch will not change before jdk.ObjectCount
130
+ * events are committed.
131
+ */
189
132
@ Uninterruptible (reason = "Caller of SubstrateJVM#getClassId must be uninterruptible." )
190
- private static long getTraceId (Class <?> c ){
133
+ private static long getTraceId (Class <?> c ) {
191
134
assert VMOperation .isGCInProgress ();
192
135
return SubstrateJVM .get ().getClassId (c );
193
136
}
194
137
195
138
private static class ObjectCountVisitor implements ObjectVisitor {
196
- PointerArray objectCounts ;
139
+ private PointerArray objectCounts ;
140
+ private long totalSize ;
197
141
198
142
@ Platforms (HOSTED_ONLY .class )
199
143
ObjectCountVisitor () {
200
144
}
201
145
202
146
public void initialize (PointerArray objectCounts ) {
203
147
this .objectCounts = objectCounts ;
148
+ this .totalSize = 0 ;
204
149
}
205
150
206
151
@ Override
207
- public boolean visitObject (Object obj ) { // *** Can't allocate in here no matter what.
152
+ public boolean visitObject (Object obj ) {
208
153
assert VMOperation .isGCInProgress ();
209
154
DynamicHub hub = DynamicHub .fromClass (obj .getClass ());
210
155
int typeId = hub .getTypeID ();
211
- VMError . guarantee ( typeId < objectCounts .getSize (), "Should not encounter a typeId out of scope of the array" );
156
+ assert typeId < objectCounts .getSize ();
212
157
213
- // create an ObjectCountData for this typeID if one doesn't already exist
158
+ // Create an ObjectCountData for this typeID if one doesn't already exist
214
159
ObjectCountData objectCountData = objectCounts .getData ().addressOf (typeId ).read ();
215
160
if (objectCountData .isNull ()) {
216
161
if (!initializeObjectCountData (objectCounts , typeId , obj )) {
@@ -231,23 +176,20 @@ public boolean visitObject(Object obj) { // *** Can't allocate in here no matter
231
176
return true ;
232
177
}
233
178
234
- /** Safe to call from interruptible code because GC should not touch this object again before we
235
- * are done with it.*/ // *** no allocation and already in a GC safepoint // TODO revisit this logic
179
+ /**
180
+ * Caller can be interruptible code because GC should not touch this object again before we
181
+ * are done with it.
182
+ */
236
183
@ Uninterruptible (reason = "Caller of LayoutEncoding#getSizeFromObject must be uninterruptible." )
237
184
private long uninterruptibleGetSize (Object obj ) {
238
185
assert VMOperation .isGCInProgress ();
239
186
return LayoutEncoding .getSizeFromObject (obj ).rawValue ();
240
187
}
241
- }
242
188
243
- // @RawStructure
244
- // private interface ObjectCountVMOperationData extends NativeVMOperationData {
245
- // @RawField
246
- // PointerArray getObjectCounts();
247
- //
248
- // @RawField
249
- // void setObjectCounts(PointerArray value);
250
- // }
189
+ public long getTotalSize () {
190
+ return totalSize ;
191
+ }
192
+ }
251
193
252
194
@ RawStructure
253
195
public interface ObjectCountData extends PointerBase {
0 commit comments