2323
2424package gc .metaspace ;
2525
26- import java .lang .management . GarbageCollectorMXBean ;
26+ import java .lang .invoke . VarHandle ;
2727import java .util .List ;
2828import java .util .ArrayList ;
2929
183183 * @run main/othervm -XX:+UsePerfData -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC gc.metaspace.TestMetaspacePerfCounters
184184 */
185185
186+ class PerfCounterSnapshot {
187+ private static long getMinCapacity (String ns ) throws Exception {
188+ return PerfCounters .findByName (ns + ".minCapacity" ).longValue ();
189+ }
190+
191+ private static long getCapacity (String ns ) throws Exception {
192+ return PerfCounters .findByName (ns + ".capacity" ).longValue ();
193+ }
194+
195+ private static long getMaxCapacity (String ns ) throws Exception {
196+ return PerfCounters .findByName (ns + ".maxCapacity" ).longValue ();
197+ }
198+
199+ private static long getUsed (String ns ) throws Exception {
200+ return PerfCounters .findByName (ns + ".used" ).longValue ();
201+ }
202+
203+ public long minCapacity ;
204+ public long maxCapacity ;
205+ public long capacity ;
206+ public long used ;
207+
208+ public void get (String ns ) throws Exception {
209+ minCapacity = getMinCapacity (ns );
210+ maxCapacity = getMaxCapacity (ns );
211+ used = getUsed (ns );
212+ capacity = getCapacity (ns );
213+ }
214+
215+ public boolean consistentWith (PerfCounterSnapshot other ) {
216+ return (minCapacity == other .minCapacity ) && (maxCapacity == other .maxCapacity ) &&
217+ (used == other .used ) && (capacity == other .capacity );
218+ }
219+ }
220+
186221public class TestMetaspacePerfCounters {
187222 public static Class <?> fooClass = null ;
188223 private static final String [] counterNames = {"minCapacity" , "maxCapacity" , "capacity" , "used" };
189- private static final List <GarbageCollectorMXBean > gcBeans = ManagementFactoryHelper .getGarbageCollectorMXBeans ();
190224
191225 public static void main (String [] args ) throws Exception {
192226 String metaspace = "sun.gc.metaspace" ;
@@ -204,32 +238,28 @@ public static void main(String[] args) throws Exception {
204238 }
205239
206240 private static void checkPerfCounters (String ns ) throws Exception {
207- long gcCountBefore ;
208- long gcCountAfter ;
209- long minCapacity ;
210- long maxCapacity ;
211- long capacity ;
212- long used ;
213-
214- // The perf counter values are updated during GC and to be able to
215- // do the assertions below we need to ensure that the values are from
216- // the same GC cycle.
217- do {
218- gcCountBefore = currentGCCount ();
219-
220- minCapacity = getMinCapacity (ns );
221- maxCapacity = getMaxCapacity (ns );
222- capacity = getCapacity (ns );
223- used = getUsed (ns );
224-
225- gcCountAfter = currentGCCount ();
226- assertGTE (gcCountAfter , gcCountBefore );
227- } while (gcCountAfter > gcCountBefore );
228-
229- assertGTE (minCapacity , 0L );
230- assertGTE (used , minCapacity );
231- assertGTE (capacity , used );
232- assertGTE (maxCapacity , capacity );
241+ PerfCounterSnapshot snap1 = new PerfCounterSnapshot ();
242+ PerfCounterSnapshot snap2 = new PerfCounterSnapshot ();
243+
244+ final int MaxAttempts = 10 ;
245+
246+ for (int attempts = 0 ; ; attempts ++) {
247+ snap1 .get (ns );
248+ VarHandle .fullFence ();
249+ snap2 .get (ns );
250+
251+ if (snap1 .consistentWith (snap2 )) {
252+ // Got a consistent snapshot for examination.
253+ break ;
254+ } else if (attempts == MaxAttempts ) {
255+ throw new Exception ("Failed to get stable reading of metaspace performance counters after " + attempts + " tries" );
256+ }
257+ }
258+
259+ assertGTE (snap1 .minCapacity , 0L );
260+ assertGTE (snap1 .used , snap1 .minCapacity );
261+ assertGTE (snap1 .capacity , snap1 .used );
262+ assertGTE (snap1 .maxCapacity , snap1 .capacity );
233263 }
234264
235265 private static void checkEmptyPerfCounters (String ns ) throws Exception {
@@ -243,12 +273,14 @@ private static void checkUsedIncreasesWhenLoadingClass(String ns) throws Excepti
243273 // Need to ensure that used is up to date and that all unreachable
244274 // classes are unloaded before doing this check.
245275 System .gc ();
246- long before = getUsed (ns );
276+ PerfCounterSnapshot before = new PerfCounterSnapshot ();
277+ before .get (ns );
247278 fooClass = compileAndLoad ("Foo" , "public class Foo { }" );
248279 System .gc ();
249- long after = getUsed (ns );
280+ PerfCounterSnapshot after = new PerfCounterSnapshot ();
281+ after .get (ns );
250282
251- assertGT (after , before );
283+ assertGT (after . used , before . used );
252284 }
253285
254286 private static List <PerfCounter > countersInNamespace (String ns ) throws Exception {
@@ -267,28 +299,4 @@ private static Class<?> compileAndLoad(String name, String source) throws Except
267299 private static boolean isUsingCompressedClassPointers () {
268300 return Platform .is64bit () && InputArguments .contains ("-XX:+UseCompressedClassPointers" );
269301 }
270-
271- private static long getMinCapacity (String ns ) throws Exception {
272- return PerfCounters .findByName (ns + ".minCapacity" ).longValue ();
273- }
274-
275- private static long getCapacity (String ns ) throws Exception {
276- return PerfCounters .findByName (ns + ".capacity" ).longValue ();
277- }
278-
279- private static long getMaxCapacity (String ns ) throws Exception {
280- return PerfCounters .findByName (ns + ".maxCapacity" ).longValue ();
281- }
282-
283- private static long getUsed (String ns ) throws Exception {
284- return PerfCounters .findByName (ns + ".used" ).longValue ();
285- }
286-
287- private static long currentGCCount () {
288- long gcCount = 0 ;
289- for (GarbageCollectorMXBean bean : gcBeans ) {
290- gcCount += bean .getCollectionCount ();
291- }
292- return gcCount ;
293- }
294302}
0 commit comments