1 /* 2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. 3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 4 */ 5 import java.util.List; 6 import java.util.ArrayList; 7 import java.util.Arrays; 8 9 import java.util.NoSuchElementException; 10 11 import java.util.Set; 12 import java.util.HashSet; 13 14 import static jrockit.Asserts.*; 15 16 import java.lang.management.RuntimeMXBean; 17 import java.lang.management.ManagementFactory; 18 19 import oracle.jrockit.jfr.parser.FLREvent; 20 import oracle.jrockit.jfr.parser.FLRStruct; 21 import jrockit.jfr.TestRecording; 22 23 /* 24 * @test TestObjectCountAfterGCEvent 25 * @key jfr 26 * @library ../common 27 * 28 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseSerialGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld 29 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld 30 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent ParallelOld 31 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld 32 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseG1GC -XX:+ExplicitGCInvokesConcurrent -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent G1Old 33 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseConcMarkSweepGC -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent SerialOld 34 * @run main/othervm -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:+UseConcMarkSweepGC -XX:+ExplicitGCInvokesConcurrent -XX:+UnlockExperimentalVMOptions -XX:-UseFastUnorderedTimeStamps TestObjectCountAfterGCEvent ConcurrentMarkSweep 35 */ 36 public class TestObjectCountAfterGCEvent { 37 private static final String objectCountEventPath = "vm/gc/detailed/object_count_after_gc"; 38 private static final String gcEventPath = "vm/gc/collector/garbage_collection"; 39 40 public static void main(String[] args) throws Exception { 41 String gcName = args[0]; 42 43 TestRecording r = new TestRecording(); 44 try { 45 enableEvent(r, objectCountEventPath); 46 enableEvent(r, gcEventPath); 47 48 ObjectCountEventVerifier.createTestData(); 49 50 r.start(); 51 52 System.gc(); 53 if (gcName.equals("ConcurrentMarkSweep") && isExplicitGCConcurrent()) { 54 System.gc(); 55 } 56 57 r.stop(); 58 59 List<FLREvent> allEvents = getRecordedEvents(r); 60 61 if (gcName.equals("ConcurrentMarkSweep") && isExplicitGCConcurrent()) { 62 allEvents = removeEventsFromUnfinishedCMS(allEvents); 63 } 64 65 List<FLREvent> gcEvents = selectGCEventsWithName(allEvents, gcName); 66 assertNotEmpty(gcEvents, 67 "Expected at least one " + gcEventPath + " event"); 68 69 Set<Integer> gcIds = new HashSet<>(); 70 gcIds.addAll(gcIdsFromEvents(gcEvents)); 71 72 List<FLREvent> objectCountEvents = selectEventsWithPath(allEvents, objectCountEventPath); 73 assertNotEmpty(gcEvents, 74 "Expected at least one " + objectCountEventPath + " event"); 75 76 List<FLREvent> targetObjectCountEvents = 77 selectObjectCountEventsWithIds(objectCountEvents, gcIds); 78 assertNotEmpty(targetObjectCountEvents, 79 "Expected at least one " + objectCountEventPath + 80 " event for gc " + gcName); 81 82 ObjectCountEventVerifier.verify(objectCountEvents); 83 } catch (Throwable t) { 84 r.copyTo("TestObjectCountAfterGCEvent.jfr"); 85 throw t; 86 } finally { 87 r.close(); 88 } 89 } 90 91 private static List<FLREvent> selectObjectCountEventsWithIds(List<FLREvent> events, Set<Integer> gcIds) 92 throws Exception { 93 List<FLREvent> selected = new ArrayList<FLREvent>(); 94 for (FLREvent e : events) { 95 if (gcIds.contains(getGCIdFromEvent(e))) { 96 selected.add(e); 97 } 98 } 99 return selected; 100 } 101 102 private static List<FLREvent> getRecordedEvents(TestRecording r) throws Exception { 103 return r.parser().findJVMEvents(".*"); 104 } 105 106 private static void enableEvent(TestRecording r, String path) throws Exception { 107 r.createJVMSetting(path, true, false, 0, 0); 108 } 109 110 private static List<FLREvent> selectEventsWithPath(List<FLREvent> events, String path) 111 throws Exception { 112 List<FLREvent> selection = new ArrayList<FLREvent>(); 113 for (FLREvent e : events) { 114 if (e.getPath().equals(path)) { 115 selection.add(e); 116 } 117 } 118 return selection; 119 } 120 121 private static List<FLREvent> selectEventsWithPathPrefix(List<FLREvent> events, String path) 122 throws Exception { 123 List<FLREvent> selection = new ArrayList<FLREvent>(); 124 for (FLREvent e : events) { 125 if (e.getPath().startsWith(path)) { 126 selection.add(e); 127 } 128 } 129 return selection; 130 } 131 132 private static List<FLREvent> removeEventsFromUnfinishedCMS(List<FLREvent> events) 133 throws Exception { 134 List<Integer> additionalGCIds = gcIdsNotPresentInCollectionEvents(events); 135 136 StringBuilder msg = new StringBuilder(); 137 msg.append('['); 138 for (Integer gcId : additionalGCIds) { 139 msg.append(" " + gcId); 140 } 141 msg.append(" ]"); 142 assertLE(additionalGCIds.size(), 1, 143 "Expected at most one additional gcId from a concurrent CMS, but got " + msg.toString()); 144 145 if (additionalGCIds.isEmpty()) { 146 return events; 147 } 148 149 return removeEventsWithGCId(events, additionalGCIds.get(0)); 150 } 151 152 private static List<Integer> gcIdsNotPresentInCollectionEvents(List<FLREvent> events) 153 throws Exception { 154 List<FLREvent> gcEvents = selectEventsWithPath(events, "vm/gc/collector/garbage_collection"); 155 List<Integer> gcIds = gcIdsFromEvents(gcEvents); 156 List<FLREvent> gcPhases = selectEventsWithPathPrefix(events, "vm/gc/phases"); 157 Set<Integer> phaseIds = new HashSet<Integer>(); 158 phaseIds.addAll(gcIdsFromEvents(gcPhases)); 159 160 for (Integer gcId : gcIds) { 161 phaseIds.remove(gcId); 162 } 163 164 return Arrays.asList(phaseIds.toArray(new Integer[phaseIds.size()])); 165 } 166 167 public static List<Integer> gcIdsFromEvents(List<FLREvent> events) 168 throws Exception { 169 List<Integer> gcIds = new ArrayList<>(); 170 for (FLREvent e : events) { 171 if (hasGCId(e)) { 172 gcIds.add(getGCIdFromEvent(e)); 173 } 174 } 175 return gcIds; 176 } 177 178 private static List<FLREvent> removeEventsWithGCId(List<FLREvent> events, Integer gcId) 179 throws Exception { 180 List<FLREvent> selected = new ArrayList<FLREvent>(); 181 for (FLREvent e : events) { 182 if (hasGCId(e)) { 183 if (getGCIdFromEvent(e) != gcId) { 184 selected.add(e); 185 } 186 } 187 } 188 return selected; 189 } 190 191 private static Integer getGCIdFromEvent(FLREvent e) { 192 return (Integer) e.getValue("gcId"); 193 } 194 195 private static boolean hasGCId(FLREvent e) { 196 try { 197 e.getValue("gcId"); 198 return true; 199 } catch (NoSuchElementException exc) { 200 return false; 201 } 202 } 203 204 private static boolean isExplicitGCConcurrent() { 205 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); 206 List<String> args = runtimeMxBean.getInputArguments(); 207 for (String arg : args) { 208 if (arg.equals("-XX:+ExplicitGCInvokesConcurrent")) { 209 return true; 210 } 211 } 212 return false; 213 } 214 215 public static List<FLREvent> selectGCEventsWithName(List<FLREvent> events, String name) 216 throws Exception { 217 List<FLREvent> gcEvents = selectEventsWithPath(events, gcEventPath); 218 219 List<FLREvent> selected = new ArrayList<>(); 220 for (FLREvent e : gcEvents) { 221 FLRStruct resolved = (FLRStruct) e.getResolvedValue("name"); 222 String gcName = (String) resolved.getValue("name"); 223 if (gcName.equals(name)) { 224 selected.add(e); 225 } 226 } 227 return selected; 228 } 229 } 230