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 ;
15
17
16
18
import org .truffleruby .SuppressFBWarnings ;
23
25
import org .truffleruby .builtins .Primitive ;
24
26
import org .truffleruby .builtins .PrimitiveArrayArgumentsNode ;
25
27
import org .truffleruby .collections .WeakValueCache ;
28
+ import org .truffleruby .core .array .RubyArray ;
26
29
import org .truffleruby .language .SafepointManager ;
27
30
import org .truffleruby .language .control .RaiseException ;
28
31
@@ -103,10 +106,6 @@ public abstract static class CountNode extends CoreMethodArrayArgumentsNode {
103
106
@ TruffleBoundary
104
107
@ Specialization
105
108
protected int count () {
106
- return getCollectionCount ();
107
- }
108
-
109
- public static int getCollectionCount () {
110
109
int count = 0 ;
111
110
for (GarbageCollectorMXBean bean : ManagementFactory .getGarbageCollectorMXBeans ()) {
112
111
count += bean .getCollectionCount ();
@@ -122,15 +121,100 @@ public abstract static class TimeNode extends CoreMethodArrayArgumentsNode {
122
121
@ TruffleBoundary
123
122
@ Specialization
124
123
protected long time () {
125
- return getCollectionTime ();
124
+ long time = 0 ;
125
+ for (GarbageCollectorMXBean bean : ManagementFactory .getGarbageCollectorMXBeans ()) {
126
+ time += bean .getCollectionTime ();
127
+ }
128
+ return time ;
126
129
}
127
130
128
- public static long getCollectionTime () {
131
+ }
132
+
133
+ @ Primitive (name = "gc_stat" )
134
+ public static abstract class GCStatPrimitiveNode extends PrimitiveArrayArgumentsNode {
135
+
136
+ @ TruffleBoundary
137
+ @ Specialization
138
+ protected RubyArray stat () {
129
139
long time = 0 ;
140
+ int count = 0 ;
141
+ int minorCount = 0 ;
142
+ int majorCount = 0 ;
143
+ int unknownCount = 0 ;
144
+ String [] memoryPoolNames = new String [0 ];
145
+ Object [] memoryPools ;
146
+
147
+ // Get GC time and counts from GarbageCollectorMXBean
130
148
for (GarbageCollectorMXBean bean : ManagementFactory .getGarbageCollectorMXBeans ()) {
149
+ // Get MemoryPoolName relevant to GC
150
+ if (bean .getMemoryPoolNames ().length > memoryPoolNames .length ) {
151
+ // Since old generation memory pools are a superset of young generation memory pools,
152
+ // it suffices to check that we have the longer list of memory pools
153
+ memoryPoolNames = bean .getMemoryPoolNames ();
154
+ }
131
155
time += bean .getCollectionTime ();
156
+ count += bean .getCollectionCount ();
157
+ switch (bean .getName ()) {
158
+ case "G1 Young Generation" : // during 'jvm' and 'jvm-ce'
159
+ case "PS Scavenge" : // during 'jvm --vm.XX:+UseParallelGC'
160
+ case "young generation scavenger" : // during 'native'
161
+ minorCount += bean .getCollectionCount ();
162
+ break ;
163
+ case "G1 Old Generation" : // during 'jvm' and 'jvm-ce'
164
+ case "PS MarkSweep" : // during 'jvm --vm.XX:+UseParallelGC'
165
+ case "complete scavenger" : // during 'native'
166
+ majorCount += bean .getCollectionCount ();
167
+ break ;
168
+ default :
169
+ unknownCount += bean .getCollectionCount ();
170
+ break ;
171
+ }
132
172
}
133
- return time ;
173
+
174
+ // Get memory usage values from relevant memory pools (2-3 / ~8 are relevant)
175
+ memoryPools = new Object [memoryPoolNames .length ];
176
+ for (MemoryPoolMXBean bean : ManagementFactory .getMemoryPoolMXBeans ()) {
177
+ if (bean .getName ().equals (memoryPoolNames [0 ])) {
178
+ memoryPools [0 ] = beanToArray (bean );
179
+ } else if (bean .getName ().equals (memoryPoolNames [1 ])) {
180
+ memoryPools [1 ] = beanToArray (bean );
181
+ } else if (memoryPoolNames .length == 3 && bean .getName ().equals (memoryPoolNames [2 ])) {
182
+ memoryPools [2 ] = beanToArray (bean );
183
+ }
184
+ }
185
+
186
+ MemoryUsage usage = ManagementFactory .getMemoryMXBean ().getHeapMemoryUsage ();
187
+
188
+ // Use an object array instead because otherwise ArrayHelpers.java line 51 complains
189
+ Object [] memoryPoolNamesCast = new Object [memoryPoolNames .length ];
190
+ for (int i = 0 ; i < memoryPoolNames .length ; i ++) {
191
+ memoryPoolNamesCast [i ] = memoryPoolNames [i ];
192
+ }
193
+
194
+
195
+ return createArray (
196
+ new Object []{
197
+ time ,
198
+ count ,
199
+ minorCount ,
200
+ majorCount ,
201
+ unknownCount ,
202
+ usage .getCommitted (),
203
+ usage .getUsed (),
204
+ createArray (memoryPoolNamesCast ),
205
+ createArray (memoryPools ) });
206
+ }
207
+
208
+ protected RubyArray usageToArray (MemoryUsage usage ) {
209
+ return createArray (new Object []{ usage .getCommitted (), usage .getInit (), usage .getMax (), usage .getUsed () });
210
+ }
211
+
212
+ protected RubyArray beanToArray (MemoryPoolMXBean bean ) {
213
+ return createArray (
214
+ new Object []{
215
+ usageToArray (bean .getUsage ()),
216
+ usageToArray (bean .getPeakUsage ()),
217
+ usageToArray (bean .getCollectionUsage ()) });
134
218
}
135
219
136
220
}
0 commit comments