11
11
12
12
import java .lang .management .GarbageCollectorMXBean ;
13
13
import java .lang .management .ManagementFactory ;
14
+ import java .lang .management .MemoryPoolMXBean ;
15
+ import java .lang .management .MemoryUsage ;
14
16
import java .time .Duration ;
17
+ import java .util .Arrays ;
15
18
19
+ import com .oracle .truffle .api .dsl .Cached ;
20
+ import org .jcodings .specific .UTF8Encoding ;
16
21
import org .truffleruby .SuppressFBWarnings ;
17
22
import org .truffleruby .builtins .CoreMethod ;
18
23
import org .truffleruby .builtins .CoreMethodArrayArgumentsNode ;
23
28
import org .truffleruby .builtins .Primitive ;
24
29
import org .truffleruby .builtins .PrimitiveArrayArgumentsNode ;
25
30
import org .truffleruby .collections .WeakValueCache ;
31
+ import org .truffleruby .core .array .RubyArray ;
32
+ import org .truffleruby .core .rope .CodeRange ;
33
+ import org .truffleruby .core .string .StringNodes ;
26
34
import org .truffleruby .language .SafepointManager ;
27
35
import org .truffleruby .language .control .RaiseException ;
28
36
@@ -103,10 +111,6 @@ public abstract static class CountNode extends CoreMethodArrayArgumentsNode {
103
111
@ TruffleBoundary
104
112
@ Specialization
105
113
protected int count () {
106
- return getCollectionCount ();
107
- }
108
-
109
- public static int getCollectionCount () {
110
114
int count = 0 ;
111
115
for (GarbageCollectorMXBean bean : ManagementFactory .getGarbageCollectorMXBeans ()) {
112
116
count += bean .getCollectionCount ();
@@ -122,15 +126,115 @@ public abstract static class TimeNode extends CoreMethodArrayArgumentsNode {
122
126
@ TruffleBoundary
123
127
@ Specialization
124
128
protected long time () {
125
- return getCollectionTime ();
129
+ long time = 0 ;
130
+ for (GarbageCollectorMXBean bean : ManagementFactory .getGarbageCollectorMXBeans ()) {
131
+ time += bean .getCollectionTime ();
132
+ }
133
+ return time ;
126
134
}
127
135
128
- public static long getCollectionTime () {
136
+ }
137
+
138
+ @ Primitive (name = "gc_stat" )
139
+ public static abstract class GCStatPrimitiveNode extends PrimitiveArrayArgumentsNode {
140
+
141
+ @ TruffleBoundary
142
+ @ Specialization
143
+ protected RubyArray stat (
144
+ @ Cached StringNodes .MakeStringNode makeStringNode ) {
129
145
long time = 0 ;
146
+ int count = 0 ;
147
+ int minorCount = 0 ;
148
+ int majorCount = 0 ;
149
+ int unknownCount = 0 ;
150
+ String [] memoryPoolNames = new String [0 ];
151
+ Object [] memoryPools ;
152
+
153
+ // Get GC time and counts from GarbageCollectorMXBean
130
154
for (GarbageCollectorMXBean bean : ManagementFactory .getGarbageCollectorMXBeans ()) {
155
+ // Get MemoryPoolName relevant to GC
156
+ if (bean .getMemoryPoolNames ().length > memoryPoolNames .length ) {
157
+ // Since old generation memory pools are a superset of young generation memory pools,
158
+ // it suffices to check that we have the longer list of memory pools
159
+ memoryPoolNames = bean .getMemoryPoolNames ();
160
+ }
131
161
time += bean .getCollectionTime ();
162
+ count += bean .getCollectionCount ();
163
+ switch (bean .getName ()) {
164
+ case "G1 Young Generation" : // during 'jvm' and 'jvm-ce'
165
+ case "PS Scavenge" : // during 'jvm --vm.XX:+UseParallelGC'
166
+ case "young generation scavenger" : // during 'native'
167
+ minorCount += bean .getCollectionCount ();
168
+ break ;
169
+ case "G1 Old Generation" : // during 'jvm' and 'jvm-ce'
170
+ case "PS MarkSweep" : // during 'jvm --vm.XX:+UseParallelGC'
171
+ case "complete scavenger" : // during 'native'
172
+ majorCount += bean .getCollectionCount ();
173
+ break ;
174
+ default :
175
+ unknownCount += bean .getCollectionCount ();
176
+ break ;
177
+ }
132
178
}
133
- return time ;
179
+
180
+ // Get memory usage values from relevant memory pools (2-3 / ~8 are relevant)
181
+ memoryPools = new Object [memoryPoolNames .length ];
182
+ // On Native Image, ManagementFactory.getMemoryPoolMXBeans() is empty
183
+ Arrays .fill (memoryPools , nil );
184
+ for (int i = 0 ; i < memoryPoolNames .length ; i ++) {
185
+ String memoryPoolName = memoryPoolNames [i ];
186
+ for (MemoryPoolMXBean bean : ManagementFactory .getMemoryPoolMXBeans ()) {
187
+ if (bean .getName ().equals (memoryPoolName )) {
188
+ memoryPools [i ] = beanToArray (bean );
189
+ }
190
+ }
191
+ }
192
+
193
+ MemoryUsage total = ManagementFactory .getMemoryMXBean ().getHeapMemoryUsage ();
194
+
195
+ Object [] memoryPoolNamesCast = new Object [memoryPoolNames .length ];
196
+ for (int i = 0 ; i < memoryPoolNames .length ; i ++) {
197
+ memoryPoolNamesCast [i ] = makeStringNode
198
+ .executeMake (memoryPoolNames [i ], UTF8Encoding .INSTANCE , CodeRange .CR_UNKNOWN );
199
+ }
200
+
201
+
202
+ return createArray (
203
+ new Object []{
204
+ time ,
205
+ count ,
206
+ minorCount ,
207
+ majorCount ,
208
+ unknownCount ,
209
+ createArray (new long []{
210
+ total .getUsed (),
211
+ total .getCommitted (),
212
+ total .getInit (),
213
+ total .getMax (),
214
+ }),
215
+ createArray (memoryPoolNamesCast ),
216
+ createArray (memoryPools ) });
217
+ }
218
+
219
+ protected RubyArray beanToArray (MemoryPoolMXBean bean ) {
220
+ MemoryUsage usage = bean .getUsage ();
221
+ MemoryUsage peak = bean .getPeakUsage ();
222
+ MemoryUsage last = bean .getCollectionUsage ();
223
+ return createArray (
224
+ new long []{
225
+ usage .getUsed (),
226
+ usage .getCommitted (),
227
+ usage .getInit (),
228
+ usage .getMax (),
229
+ peak .getUsed (),
230
+ peak .getCommitted (),
231
+ peak .getInit (),
232
+ peak .getMax (),
233
+ last .getUsed (),
234
+ last .getCommitted (),
235
+ last .getInit (),
236
+ last .getMax (),
237
+ });
134
238
}
135
239
136
240
}
0 commit comments