com/oracle/jfr/gc/GCEventAll.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File closed Sdiff com/oracle/jfr/gc

com/oracle/jfr/gc/GCEventAll.java

Print this page
rev 1475 : 8010090: GC ID has the wrong type
Summary: GC ID changed from ulong to uint
Reviewed-by: mattias.tobiasson@oracle.com


  43  *   Batch contains expected events depending on garbage_collection.name
  44  *
  45  *   garbage_collection_start.timestamp == garbage_collection.startTime.
  46  *
  47  *   garbage_collection.timestamp >= timestamp for all other events in batch.
  48  *
  49  *   The start_garbage_collection and garbage_collection events must be synchronized.
  50  *     This means that there may be multiple start_garbage_collection before a garbage_collection,
  51  *     but garbage_collection.gcId must be equal to latest start_garbage_collection.gcId.
  52  *
  53  *   start_garbage_collection must be the first event in the batch,
  54  *     that means no event with same gcId before garbage_collection_start event.
  55  *
  56  *   garbage_collection.name matches what is expected by the collectors specified in initial_configuration.
  57  *
  58  *   Duration for event "vm/gc/phases/pause" >= 1. Duration for phase level events >= 0.
  59  *
  60  *
  61  */
  62 public class GCEventAll {
  63     private static Set<Long> gcIds = new HashSet<Long>();
  64     private static int systemGcCount = 0;
  65     private boolean isIncompleteBatchRemoved = false;
  66 
  67     private String youngCollector = null;
  68     private String oldCollector = null;
  69 
  70     /**
  71      * Runs the test once with given worker threads.
  72      * @param workerThreads Threads that generates GCs.
  73      * @param gcIds Set of all used gcIds
  74      * @throws Exception
  75      */
  76     public void doSingleTest(Thread[] workerThreads) throws Throwable {
  77         TestRecording r = new TestRecording();
  78         final String gcEventRoot = "vm/gc/*";
  79         List<FLREvent> events = null;
  80         try {
  81             r.createJVMSetting(gcEventRoot, true, false, 0, 0);
  82 
  83             // Start with a full GC to minimize risk of getting extra GC between


 205         }
 206     }
 207 
 208     /**
 209      * When using collector ConcurrentMarkSweep with -XX:+ExplicitGCInvokesConcurrent, the JFR recording may
 210      * stop before we have received the last garbage_collection event.
 211      *
 212      * This function does 3 things:
 213      * 1. Check if the last batch is incomplete.
 214      * 2. If it is incomplete, then asserts that incomplete batches are allowed for this configuration.
 215      * 3. If incomplete batches are allowed, then the incomplete batch is removed.
 216      *
 217      * @param events All events
 218      * @return All events with any incomplete batch removed.
 219      * @throws Throwable
 220      */
 221     private List<FLREvent> filterIncompleteGcBatch(List<FLREvent> events) throws Throwable {
 222         List<FLREvent> returnEvents = new ArrayList<FLREvent>();
 223         returnEvents.addAll(events);
 224 
 225         long lastGcId = getLastGcId(events);
 226         List<FLREvent> lastBatchEvents = getEventsWithGcId(events, lastGcId);
 227         String[] endEvents = {GCHelper.event_garbage_collection, GCHelper.event_old_garbage_collection, GCHelper.event_young_garbage_collection};
 228         boolean isComplete = containsAnyPath(lastBatchEvents, endEvents);
 229         if (!isComplete) {
 230             // The last GC batch does not contain an end event. The batch is incomplete.
 231             // This is only allowed if we are using old_collector="ConcurrentMarkSweep" and "-XX:+ExplicitGCInvokesConcurrent"
 232             boolean isExplicitGCInvokesConcurrent = hasInputArgument("-XX:+ExplicitGCInvokesConcurrent");
 233             boolean isConcurrentMarkSweep = GCHelper.gcConcurrentMarkSweep.equals(oldCollector);
 234             String msg = String.format(
 235                     "Incomplete batch only allowed for '%s' with -XX:+ExplicitGCInvokesConcurrent",
 236                     GCHelper.gcConcurrentMarkSweep);
 237             Asserts.assertTrue(isConcurrentMarkSweep && isExplicitGCInvokesConcurrent, msg);
 238 
 239             // This batch is incomplete, but that is allowed with the current settings.
 240             // Remove the incomplete batch.
 241             returnEvents.removeAll(lastBatchEvents);
 242         }
 243         return returnEvents;
 244     }
 245 


 248      * @param arg The argument to search for
 249      * @return true if the argument is on the command line.
 250      */
 251     private boolean hasInputArgument(String arg) {
 252         RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
 253         List<String> arguments = runtimeMxBean.getInputArguments();
 254         for (String currArg : arguments) {
 255             if (currArg.equals(arg)) {
 256                 return true;
 257             }
 258         }
 259         return false;
 260     }
 261 
 262     /**
 263      * Get all events that has the specified gcId.
 264      * @param events All events.
 265      * @param gcId The specified gcId.
 266      * @return A list of the events with the specified gcId.
 267      */
 268     private List<FLREvent> getEventsWithGcId(List<FLREvent> events, long gcId) {
 269         List<FLREvent> batchEvents = new ArrayList<FLREvent>();
 270         for (FLREvent event : events) {
 271             if (GCHelper.isGcEvent(event) && GCHelper.getGcId(event) == gcId) {
 272                 batchEvents.add(event);
 273             }
 274         }
 275         return batchEvents;
 276     }
 277 
 278     /**
 279      * Checks if at least one event in the list has one of the specified paths.
 280      * @param events All events.
 281      * @param paths The paths to search for.
 282      * @return true if at least one of the events has one of the specified paths.
 283      */
 284     private boolean containsAnyPath(List<FLREvent> events, String[] paths) {
 285         Set<String> pathSet = new HashSet<String>(Arrays.asList(paths));
 286         for (FLREvent event : events) {
 287             if (pathSet.contains(event.getPath())) {
 288                 return true;
 289             }
 290         }
 291         return false;
 292     }
 293 
 294     /**
 295      * Return the highest gcId in the list.
 296      * @param events All events.
 297      * @return the highest gcId found in the list or -1 if no event had a gcId.
 298      */
 299     private long getLastGcId(List<FLREvent> events) {
 300         long lastGcId = -1;
 301         for (FLREvent event : events) {
 302             if (GCHelper.isGcEvent(event)) {
 303                 long gcId = GCHelper.getGcId(event);
 304                 if (gcId > lastGcId) {
 305                     lastGcId = gcId;
 306                 }
 307             }
 308         }
 309         Asserts.assertTrue(lastGcId != -1, "No gcId found");
 310         return lastGcId;
 311     }
 312 
 313     /**
 314      * Verifies collection count reported by flight recorder events against the values
 315      * reported by GarbageCollectionMXBean.
 316      * Number of collections should match exactly.
 317      * Sum pause time are allowed some margin of error because of rounding errors in measurements.
 318      */
 319     private void verifyCollectionCount(GCHelper.CollectionSummary eventCounts, GCHelper.CollectionSummary beanCounts) {
 320         verifyCollectionCount(youngCollector, eventCounts.collectionCountYoung, beanCounts.collectionCountYoung);
 321         verifyCollectionCount(oldCollector, eventCounts.collectionCountOld, beanCounts.collectionCountOld);
 322     }
 323 


 383                             countAfterGc++;
 384                         } else {
 385                             Asserts.assertTrue(false, "Unknown value for heap_summary.when: '" + when + "'");
 386                         }
 387                     }
 388                 }
 389                 if (!GCHelper.gcConcurrentMarkSweep.equals(batch.getName())) {
 390                     // We do not get heap_summary events for ConcurrentMarkSweep
 391                     Asserts.assertEquals(1, countBeforeGc, "Unexpected number of heap_summary.before_gc");
 392                     Asserts.assertEquals(1, countAfterGc, "Unexpected number of heap_summary.after_gc");
 393                 }
 394             } catch (Throwable e) {
 395                 throw e;
 396             }
 397         }
 398     }
 399 
 400     /**
 401      * Verify that all gcId are unique.
 402      */
 403     private void verifyUniqueIds(List<GCHelper.GcBatch> batches, Set<Long> gcIds) {
 404         for (GCHelper.GcBatch batch : batches) {
 405             Long gcId = new Long(batch.getGcId());
 406             Asserts.assertFalse(gcIds.contains(gcId), "Duplicate gcId: " + gcId);
 407             gcIds.add(gcId);
 408         }
 409     }
 410 
 411     /**
 412      * Verify phase events.
 413      */
 414     private void verifyPhaseEvents(List<GCHelper.GcBatch> batches) {
 415         for (GCHelper.GcBatch batch : batches) {
 416             for(FLREvent event : batch.getEvents()) {
 417                 // Only check events that start with "vm/gc/phases/"
 418                 if (event.getPath().startsWith(GCHelper.event_phases_group)) {
 419                     long batchStartTime = batch.getEndEvent().getStartTime();
 420                     Asserts.assertGreaterOrEqualThan(event.getStartTime(), batchStartTime, "Phase startTime >= batch startTime");
 421                     long minDuration = 0;
 422                     long duration = event.getTimestamp() - event.getStartTime();
 423                     Asserts.assertGreaterOrEqualThan(duration, minDuration, "Phase event duration >= " + minDuration);
 424                 }
 425             }




  43  *   Batch contains expected events depending on garbage_collection.name
  44  *
  45  *   garbage_collection_start.timestamp == garbage_collection.startTime.
  46  *
  47  *   garbage_collection.timestamp >= timestamp for all other events in batch.
  48  *
  49  *   The start_garbage_collection and garbage_collection events must be synchronized.
  50  *     This means that there may be multiple start_garbage_collection before a garbage_collection,
  51  *     but garbage_collection.gcId must be equal to latest start_garbage_collection.gcId.
  52  *
  53  *   start_garbage_collection must be the first event in the batch,
  54  *     that means no event with same gcId before garbage_collection_start event.
  55  *
  56  *   garbage_collection.name matches what is expected by the collectors specified in initial_configuration.
  57  *
  58  *   Duration for event "vm/gc/phases/pause" >= 1. Duration for phase level events >= 0.
  59  *
  60  *
  61  */
  62 public class GCEventAll {
  63     private static Set<Integer> gcIds = new HashSet<Integer>();
  64     private static int systemGcCount = 0;
  65     private boolean isIncompleteBatchRemoved = false;
  66 
  67     private String youngCollector = null;
  68     private String oldCollector = null;
  69 
  70     /**
  71      * Runs the test once with given worker threads.
  72      * @param workerThreads Threads that generates GCs.
  73      * @param gcIds Set of all used gcIds
  74      * @throws Exception
  75      */
  76     public void doSingleTest(Thread[] workerThreads) throws Throwable {
  77         TestRecording r = new TestRecording();
  78         final String gcEventRoot = "vm/gc/*";
  79         List<FLREvent> events = null;
  80         try {
  81             r.createJVMSetting(gcEventRoot, true, false, 0, 0);
  82 
  83             // Start with a full GC to minimize risk of getting extra GC between


 205         }
 206     }
 207 
 208     /**
 209      * When using collector ConcurrentMarkSweep with -XX:+ExplicitGCInvokesConcurrent, the JFR recording may
 210      * stop before we have received the last garbage_collection event.
 211      *
 212      * This function does 3 things:
 213      * 1. Check if the last batch is incomplete.
 214      * 2. If it is incomplete, then asserts that incomplete batches are allowed for this configuration.
 215      * 3. If incomplete batches are allowed, then the incomplete batch is removed.
 216      *
 217      * @param events All events
 218      * @return All events with any incomplete batch removed.
 219      * @throws Throwable
 220      */
 221     private List<FLREvent> filterIncompleteGcBatch(List<FLREvent> events) throws Throwable {
 222         List<FLREvent> returnEvents = new ArrayList<FLREvent>();
 223         returnEvents.addAll(events);
 224 
 225         int lastGcId = getLastGcId(events);
 226         List<FLREvent> lastBatchEvents = getEventsWithGcId(events, lastGcId);
 227         String[] endEvents = {GCHelper.event_garbage_collection, GCHelper.event_old_garbage_collection, GCHelper.event_young_garbage_collection};
 228         boolean isComplete = containsAnyPath(lastBatchEvents, endEvents);
 229         if (!isComplete) {
 230             // The last GC batch does not contain an end event. The batch is incomplete.
 231             // This is only allowed if we are using old_collector="ConcurrentMarkSweep" and "-XX:+ExplicitGCInvokesConcurrent"
 232             boolean isExplicitGCInvokesConcurrent = hasInputArgument("-XX:+ExplicitGCInvokesConcurrent");
 233             boolean isConcurrentMarkSweep = GCHelper.gcConcurrentMarkSweep.equals(oldCollector);
 234             String msg = String.format(
 235                     "Incomplete batch only allowed for '%s' with -XX:+ExplicitGCInvokesConcurrent",
 236                     GCHelper.gcConcurrentMarkSweep);
 237             Asserts.assertTrue(isConcurrentMarkSweep && isExplicitGCInvokesConcurrent, msg);
 238 
 239             // This batch is incomplete, but that is allowed with the current settings.
 240             // Remove the incomplete batch.
 241             returnEvents.removeAll(lastBatchEvents);
 242         }
 243         return returnEvents;
 244     }
 245 


 248      * @param arg The argument to search for
 249      * @return true if the argument is on the command line.
 250      */
 251     private boolean hasInputArgument(String arg) {
 252         RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
 253         List<String> arguments = runtimeMxBean.getInputArguments();
 254         for (String currArg : arguments) {
 255             if (currArg.equals(arg)) {
 256                 return true;
 257             }
 258         }
 259         return false;
 260     }
 261 
 262     /**
 263      * Get all events that has the specified gcId.
 264      * @param events All events.
 265      * @param gcId The specified gcId.
 266      * @return A list of the events with the specified gcId.
 267      */
 268     private List<FLREvent> getEventsWithGcId(List<FLREvent> events, int gcId) {
 269         List<FLREvent> batchEvents = new ArrayList<FLREvent>();
 270         for (FLREvent event : events) {
 271             if (GCHelper.isGcEvent(event) && GCHelper.getGcId(event) == gcId) {
 272                 batchEvents.add(event);
 273             }
 274         }
 275         return batchEvents;
 276     }
 277 
 278     /**
 279      * Checks if at least one event in the list has one of the specified paths.
 280      * @param events All events.
 281      * @param paths The paths to search for.
 282      * @return true if at least one of the events has one of the specified paths.
 283      */
 284     private boolean containsAnyPath(List<FLREvent> events, String[] paths) {
 285         Set<String> pathSet = new HashSet<String>(Arrays.asList(paths));
 286         for (FLREvent event : events) {
 287             if (pathSet.contains(event.getPath())) {
 288                 return true;
 289             }
 290         }
 291         return false;
 292     }
 293 
 294     /**
 295      * Return the highest gcId in the list.
 296      * @param events All events.
 297      * @return the highest gcId found in the list or -1 if no event had a gcId.
 298      */
 299     private int getLastGcId(List<FLREvent> events) {
 300         int lastGcId = -1;
 301         for (FLREvent event : events) {
 302             if (GCHelper.isGcEvent(event)) {
 303                 int gcId = GCHelper.getGcId(event);
 304                 if (gcId > lastGcId) {
 305                     lastGcId = gcId;
 306                 }
 307             }
 308         }
 309         Asserts.assertTrue(lastGcId != -1, "No gcId found");
 310         return lastGcId;
 311     }
 312 
 313     /**
 314      * Verifies collection count reported by flight recorder events against the values
 315      * reported by GarbageCollectionMXBean.
 316      * Number of collections should match exactly.
 317      * Sum pause time are allowed some margin of error because of rounding errors in measurements.
 318      */
 319     private void verifyCollectionCount(GCHelper.CollectionSummary eventCounts, GCHelper.CollectionSummary beanCounts) {
 320         verifyCollectionCount(youngCollector, eventCounts.collectionCountYoung, beanCounts.collectionCountYoung);
 321         verifyCollectionCount(oldCollector, eventCounts.collectionCountOld, beanCounts.collectionCountOld);
 322     }
 323 


 383                             countAfterGc++;
 384                         } else {
 385                             Asserts.assertTrue(false, "Unknown value for heap_summary.when: '" + when + "'");
 386                         }
 387                     }
 388                 }
 389                 if (!GCHelper.gcConcurrentMarkSweep.equals(batch.getName())) {
 390                     // We do not get heap_summary events for ConcurrentMarkSweep
 391                     Asserts.assertEquals(1, countBeforeGc, "Unexpected number of heap_summary.before_gc");
 392                     Asserts.assertEquals(1, countAfterGc, "Unexpected number of heap_summary.after_gc");
 393                 }
 394             } catch (Throwable e) {
 395                 throw e;
 396             }
 397         }
 398     }
 399 
 400     /**
 401      * Verify that all gcId are unique.
 402      */
 403     private void verifyUniqueIds(List<GCHelper.GcBatch> batches, Set<Integer> gcIds) {
 404         for (GCHelper.GcBatch batch : batches) {
 405             Integer gcId = new Integer(batch.getGcId());
 406             Asserts.assertFalse(gcIds.contains(gcId), "Duplicate gcId: " + gcId);
 407             gcIds.add(gcId);
 408         }
 409     }
 410 
 411     /**
 412      * Verify phase events.
 413      */
 414     private void verifyPhaseEvents(List<GCHelper.GcBatch> batches) {
 415         for (GCHelper.GcBatch batch : batches) {
 416             for(FLREvent event : batch.getEvents()) {
 417                 // Only check events that start with "vm/gc/phases/"
 418                 if (event.getPath().startsWith(GCHelper.event_phases_group)) {
 419                     long batchStartTime = batch.getEndEvent().getStartTime();
 420                     Asserts.assertGreaterOrEqualThan(event.getStartTime(), batchStartTime, "Phase startTime >= batch startTime");
 421                     long minDuration = 0;
 422                     long duration = event.getTimestamp() - event.getStartTime();
 423                     Asserts.assertGreaterOrEqualThan(duration, minDuration, "Phase event duration >= " + minDuration);
 424                 }
 425             }


com/oracle/jfr/gc/GCEventAll.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File