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.ArrayList; 6 import java.util.Collections; 7 import java.util.List; 8 import java.util.NoSuchElementException; 9 10 import jrockit.jfr.JFRHelper; 11 import jrockit.jfr.TestRecording; 12 import oracle.jrockit.jfr.parser.FLREvent; 13 import oracle.jrockit.jfr.parser.FLRStruct; 14 15 import static jrockit.Asserts.*; 16 17 public class HeapSummaryEventAllGcs { 18 19 private static int lastHeapGcId = -1; 20 private static int lastPSGcId = -1; 21 private static int lastPermGcId = -1; 22 23 public static void test(GarbageCollectionConfiguration.YoungCollector yc, 24 GarbageCollectionConfiguration.OldCollector oc) throws Exception { 25 26 if (!GarbageCollectionConfiguration.usesGCs(yc, oc)) { 27 System.out.println("WARNING: Skip the test due to invalid GCs\n" 28 + "The expected young collector: " + yc.toString() 29 + " and old collector: " + oc.toString()); 30 return; 31 } 32 33 TestRecording r = new TestRecording(); 34 try { 35 // activate the event we are interested in 36 r.createJVMSetting("vm/gc/heap/summary", true, false, 0, 0); 37 r.createJVMSetting("vm/gc/heap/ps_summary", true, false, 0, 0); 38 r.createJVMSetting("vm/gc/heap/perm_gen_summary", true, false, 0, 0); 39 40 r.start(); 41 42 // To eliminate the risk of being in the middle of a GC when the 43 // recording starts/stops, 44 // we run 3 System.gc() and ignores the first and last GC. 45 for (int c = 0; c < 3; c++) { 46 System.gc(); 47 } 48 49 r.stop(); 50 51 List<FLREvent> allEvents = r.parser().findJVMEvents("vm/gc/heap/.*summary"); 52 // Since the ordering of events are important in this test, we sort them by time stamp. 53 Collections.sort(allEvents, new JFRHelper.EventTimestampComparator()); 54 55 // Remove first and last gcId to make sure we remove any "half" GCs. 56 List<FLREvent> filteredEvents = removeFirstAndLastGC(allEvents); 57 58 try { 59 assertFalse(filteredEvents.isEmpty(), "Expected at least one event."); 60 assertEquals(filteredEvents.size() % 2, 0, "Events should come in pairs"); 61 62 for (FLREvent evt : filteredEvents) { 63 if ("vm/gc/heap/summary".equals(evt.getPath())) { 64 checkHeapGcId(evt); 65 checkHeapEventContent(evt); 66 } else if ("vm/gc/heap/ps_summary".equals(evt.getPath())) { 67 checkPSGcId(evt); 68 checkPSEventContent(evt); 69 } else { 70 assertEquals("vm/gc/heap/perm_gen_summary", evt.getPath(), "Unknown event"); 71 checkPermGcId(evt); 72 checkPermEventContent(evt); 73 } 74 } 75 76 // Sanity check. Not complete. 77 assertEquals(lastHeapGcId, lastPermGcId, "Should have gotten perm gen events for all GCs"); 78 } catch (Throwable t) { 79 System.out.println("all events:"); 80 for (FLREvent evt : filteredEvents) { 81 System.out.println(evt); 82 } 83 String filename = "HeapSummaryEventAllGcs_" + yc.name() + "_" + oc.name() + ".jfr"; 84 r.copyTo(filename); 85 System.out.println("Failed recording saved as " + filename); 86 throw t; 87 } 88 } finally { 89 r.close(); 90 } 91 } 92 93 private static void checkPermEventContent(FLREvent evt) { 94 FLRStruct permSpace = (FLRStruct)evt.getResolvedValue("permSpace"); 95 FLRStruct objectSpace = (FLRStruct)evt.getResolvedValue("objectSpace"); 96 checkVirtualSpace(permSpace); 97 checkSpace(objectSpace); 98 } 99 100 private static void checkHeapGcId(FLREvent evt) { 101 int gcId = (int) evt.getValue("gcId"); 102 FLRStruct when = ((FLRStruct) evt.getResolvedValue("when")); 103 if ("Before GC".equals(when.getValue("when"))) { 104 assertGT(gcId, lastHeapGcId, "gcId should be increasing"); 105 lastHeapGcId = gcId; 106 } else { 107 assertEquals(gcId, lastHeapGcId, "After should have same gcId as last Before event"); 108 } 109 } 110 111 private static void checkPSGcId(FLREvent evt) { 112 int gcId = (int) evt.getValue("gcId"); 113 FLRStruct when = ((FLRStruct) evt.getResolvedValue("when")); 114 if ("Before GC".equals(when.getValue("when"))) { 115 assertGT(gcId, lastPSGcId, "gcId should be increasing"); 116 lastPSGcId = gcId; 117 } else { 118 assertEquals(gcId, lastPSGcId, "After should have same gcId as last Before event"); 119 } 120 } 121 122 private static void checkPermGcId(FLREvent evt) { 123 int gcId = (int) evt.getValue("gcId"); 124 FLRStruct when = ((FLRStruct) evt.getResolvedValue("when")); 125 if ("Before GC".equals(when.getValue("when"))) { 126 assertGT(gcId, lastPermGcId, "gcId should be increasing"); 127 lastPermGcId = gcId; 128 } else { 129 assertEquals(gcId, lastPermGcId, "After should have same gcId as last Before event"); 130 } 131 } 132 133 private static void checkHeapEventContent(FLREvent evt) { 134 FLRStruct heapSpace = (FLRStruct) evt.getResolvedValue("heapSpace"); 135 checkVirtualSpace(heapSpace); 136 long used = (long) evt.getValue("heapUsed"); 137 long size = (long) heapSpace.getValue("committedEnd") 138 - (long) heapSpace.getValue("start"); 139 assertLE(used, size, "used can not exceed size"); 140 } 141 142 private static void checkPSEventContent(FLREvent evt) { 143 FLRStruct oldSpace = (FLRStruct) evt.getResolvedValue("oldSpace"); 144 checkVirtualSpace(oldSpace); 145 checkSpace((FLRStruct) evt.getResolvedValue("oldObjectSpace")); 146 147 FLRStruct youngSpace = (FLRStruct) evt.getResolvedValue("youngSpace"); 148 FLRStruct edenSpace = (FLRStruct) evt.getResolvedValue("edenSpace"); 149 FLRStruct fromSpace = (FLRStruct) evt.getResolvedValue("fromSpace"); 150 FLRStruct toSpace = (FLRStruct) evt.getResolvedValue("toSpace"); 151 checkVirtualSpace(youngSpace); 152 checkSpace(edenSpace); 153 checkSpace(fromSpace); 154 checkSpace(toSpace); 155 checkPSYoungSizes(youngSpace, edenSpace, fromSpace, toSpace); 156 checkPSYoungStartEnd(oldSpace, youngSpace, edenSpace, fromSpace, toSpace); 157 } 158 159 private static void checkPSYoungSizes(FLRStruct young, FLRStruct eden, 160 FLRStruct from, FLRStruct to) { 161 long youngSize = (long) young.getValue("committedEnd") 162 - (long) young.getValue("start"); 163 long edenSize = (long) eden.getValue("end") 164 - (long) eden.getValue("start"); 165 long fromSize = (long) from.getValue("end") 166 - (long) from.getValue("start"); 167 long toSize = (long) to.getValue("end") - (long) to.getValue("start"); 168 // We can't use equal here since we may over commit the young gen size 169 // when we do resizing 170 assertGE(youngSize, edenSize + fromSize + toSize, "Young sizes don't match"); 171 } 172 173 private static void checkPSYoungStartEnd(FLRStruct old, FLRStruct young, 174 FLRStruct eden, FLRStruct from, FLRStruct to) { 175 long oldEnd = (long) old.getValue("reservedEnd"); 176 long youngStart = (long) young.getValue("start"); 177 long youngEnd = (long) young.getValue("committedEnd"); 178 long edenStart = (long) eden.getValue("start"); 179 long edenEnd = (long) eden.getValue("end"); 180 long fromStart = (long) from.getValue("start"); 181 long fromEnd = (long) from.getValue("end"); 182 long toStart = (long) to.getValue("start"); 183 long toEnd = (long) to.getValue("end"); 184 assertEQ(oldEnd, youngStart, "Young should start where old ends"); 185 assertEQ(youngStart, edenStart, "Eden should be placed first in young"); 186 if (fromStart < toStart) { 187 // [eden][from][to] 188 assertGE(fromStart, edenEnd, "From should start after eden"); 189 assertLE(fromEnd, toStart, "To should start after From"); 190 assertLE(toEnd, youngEnd, "To should start after From"); 191 } else { 192 // [eden][to][from] 193 assertGE(toStart, edenEnd, "From should start after eden"); 194 assertLE(toEnd, fromStart, "To should start after From"); 195 assertLE(fromEnd, youngEnd, "To should start after From"); 196 } 197 } 198 199 private static void checkVirtualSpace(FLRStruct virtualSpace) { 200 long start = (long) virtualSpace.getValue("start"); 201 long committedEnd = (long) virtualSpace.getValue("committedEnd"); 202 long reservedEnd = (long) virtualSpace.getValue("reservedEnd"); 203 long committedSize = (long) virtualSpace.getValue("committedSize"); 204 long reservedSize = (long) virtualSpace.getValue("reservedSize"); 205 206 assertLT(start, committedEnd, "start must be less than committedEnd"); 207 assertLT(committedEnd, reservedEnd, "committedEnd must be less than reservedEnd"); 208 assertEQ(committedSize, committedEnd - start, "Size mismatch"); 209 assertEQ(reservedSize, reservedEnd - start, "Size mismatch"); 210 } 211 212 private static void checkSpace(FLRStruct objectSpace) { 213 long start = (long) objectSpace.getValue("start"); 214 long end = (long) objectSpace.getValue("end"); 215 long used = (long) objectSpace.getValue("used"); 216 long size = (long) objectSpace.getValue("size"); 217 218 assertLT(start, end, "start must be less than end"); 219 assertLE(used, size, "used can not exceed size"); 220 assertEQ(size, end - start, "Size mismatch"); 221 } 222 223 /** 224 * Removes gcEvents with lowest and highest gcID. This is used to filter out 225 * any incomplete GCs if the recording started/stopped in the middle of a 226 * GC. 227 * 228 * @param allEvents 229 * All events 230 * @return The remaining events when the events with the lowest and highest 231 * gcId have been removed. 232 */ 233 private static List<FLREvent> removeFirstAndLastGC(List<FLREvent> allEvents) { 234 List<FLREvent> filteredEvents = new ArrayList<FLREvent>(); 235 int minGcId = Integer.MAX_VALUE; 236 int maxGcId = Integer.MIN_VALUE; 237 238 // Find min/max gcId 239 for (FLREvent event : allEvents) { 240 try { 241 int gcId = ((Integer) event.getValue("gcId")).intValue(); 242 if (gcId < minGcId) { 243 minGcId = gcId; 244 } 245 if (gcId > maxGcId) { 246 maxGcId = gcId; 247 } 248 } catch (NoSuchElementException t) { 249 // Expected error 250 } 251 } 252 253 // Add all events execpt those with gcId = min/max gcId 254 for (FLREvent event : allEvents) { 255 try { 256 int gcId = ((Integer) event.getValue("gcId")).intValue(); 257 if (gcId == minGcId || gcId == maxGcId) { 258 continue; 259 } 260 } catch (NoSuchElementException t) { 261 // Expected error. 262 } 263 filteredEvents.add(event); 264 } 265 return filteredEvents; 266 } 267 268 }