/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ import java.util.List; import java.util.ArrayList; import java.util.Arrays; import java.util.NoSuchElementException; import java.util.Set; import java.util.HashSet; import static jrockit.Asserts.*; import java.lang.management.RuntimeMXBean; import java.lang.management.ManagementFactory; import oracle.jrockit.jfr.parser.FLREvent; import oracle.jrockit.jfr.parser.FLRStruct; import jrockit.jfr.TestRecording; /* * @test TestObjectCountAfterGCEvent * @key jfr * @library ../common * * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent ParallelOld * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent G1Old * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseConcMarkSweepGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent ConcurrentMarkSweep */ public class TestObjectCountAfterGCEvent { private static final String objectCountEventPath = "vm/gc/detailed/object_count_after_gc"; private static final String gcEventPath = "vm/gc/collector/garbage_collection"; public static void main(String[] args) throws Exception { String gcName = args[0]; TestRecording r = new TestRecording(); try { enableEvent(r, objectCountEventPath); enableEvent(r, gcEventPath); ObjectCountEventVerifier.createTestData(); r.start(); System.gc(); if (gcName.equals("ConcurrentMarkSweep") && isExplicitGCConcurrent()) { System.gc(); } r.stop(); List allEvents = getRecordedEvents(r); if (gcName.equals("ConcurrentMarkSweep") && isExplicitGCConcurrent()) { allEvents = removeEventsFromUnfinishedCMS(allEvents); } List gcEvents = selectGCEventsWithName(allEvents, gcName); assertNotEmpty(gcEvents, "Expected at least one " + gcEventPath + " event"); Set gcIds = new HashSet<>(); gcIds.addAll(gcIdsFromEvents(gcEvents)); List objectCountEvents = selectEventsWithPath(allEvents, objectCountEventPath); assertNotEmpty(gcEvents, "Expected at least one " + objectCountEventPath + " event"); List targetObjectCountEvents = selectObjectCountEventsWithIds(objectCountEvents, gcIds); assertNotEmpty(targetObjectCountEvents, "Expected at least one " + objectCountEventPath + " event for gc " + gcName); ObjectCountEventVerifier.verify(objectCountEvents); } catch (Throwable t) { r.copyTo("TestObjectCountAfterGCEvent.jfr"); throw t; } finally { r.close(); } } private static List selectObjectCountEventsWithIds(List events, Set gcIds) throws Exception { List selected = new ArrayList(); for (FLREvent e : events) { if (gcIds.contains(getGCIdFromEvent(e))) { selected.add(e); } } return selected; } private static List getRecordedEvents(TestRecording r) throws Exception { return r.parser().findJVMEvents(".*"); } private static void enableEvent(TestRecording r, String path) throws Exception { r.createJVMSetting(path, true, false, 0, 0); } private static List selectEventsWithPath(List events, String path) throws Exception { List selection = new ArrayList(); for (FLREvent e : events) { if (e.getPath().equals(path)) { selection.add(e); } } return selection; } private static List selectEventsWithPathPrefix(List events, String path) throws Exception { List selection = new ArrayList(); for (FLREvent e : events) { if (e.getPath().startsWith(path)) { selection.add(e); } } return selection; } private static List removeEventsFromUnfinishedCMS(List events) throws Exception { List additionalGCIds = gcIdsNotPresentInCollectionEvents(events); StringBuilder msg = new StringBuilder(); msg.append('['); for (Integer gcId : additionalGCIds) { msg.append(" " + gcId); } msg.append(" ]"); assertLE(additionalGCIds.size(), 1, "Expected at most one additional gcId from a concurrent CMS, but got " + msg.toString()); if (additionalGCIds.isEmpty()) { return events; } return removeEventsWithGCId(events, additionalGCIds.get(0)); } private static List gcIdsNotPresentInCollectionEvents(List events) throws Exception { List gcEvents = selectEventsWithPath(events, "vm/gc/collector/garbage_collection"); List gcIds = gcIdsFromEvents(gcEvents); List gcPhases = selectEventsWithPathPrefix(events, "vm/gc/phases"); Set phaseIds = new HashSet(); phaseIds.addAll(gcIdsFromEvents(gcPhases)); for (Integer gcId : gcIds) { phaseIds.remove(gcId); } return Arrays.asList(phaseIds.toArray(new Integer[phaseIds.size()])); } public static List gcIdsFromEvents(List events) throws Exception { List gcIds = new ArrayList<>(); for (FLREvent e : events) { if (hasGCId(e)) { gcIds.add(getGCIdFromEvent(e)); } } return gcIds; } private static List removeEventsWithGCId(List events, Integer gcId) throws Exception { List selected = new ArrayList(); for (FLREvent e : events) { if (hasGCId(e)) { if (getGCIdFromEvent(e) != gcId) { selected.add(e); } } } return selected; } private static Integer getGCIdFromEvent(FLREvent e) { return (Integer) e.getValue("gcId"); } private static boolean hasGCId(FLREvent e) { try { e.getValue("gcId"); return true; } catch (NoSuchElementException exc) { return false; } } private static boolean isExplicitGCConcurrent() { RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); List args = runtimeMxBean.getInputArguments(); for (String arg : args) { if (arg.equals("-XX:+ExplicitGCInvokesConcurrent")) { return true; } } return false; } public static List selectGCEventsWithName(List events, String name) throws Exception { List gcEvents = selectEventsWithPath(events, gcEventPath); List selected = new ArrayList<>(); for (FLREvent e : gcEvents) { FLRStruct resolved = (FLRStruct) e.getResolvedValue("name"); String gcName = (String) resolved.getValue("name"); if (gcName.equals(name)) { selected.add(e); } } return selected; } }