1 /* 2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.jfr.event.gc.heapsummary; 27 28 import java.time.Duration; 29 import java.util.List; 30 31 import jdk.jfr.Recording; 32 import jdk.jfr.consumer.RecordedEvent; 33 import jdk.test.lib.Asserts; 34 import jdk.test.lib.jfr.EventNames; 35 import jdk.test.lib.jfr.Events; 36 import jdk.test.lib.jfr.GCHelper; 37 38 public class HeapSummaryEventAllGcs { 39 40 public static void test(String expectedYoungCollector, String expectedOldCollector) throws Exception { 41 Recording recording = new Recording(); 42 recording.enable(EventNames.GCConfiguration); 43 recording.enable(EventNames.GCHeapSummary); 44 recording.enable(EventNames.G1HeapSummary); 45 recording.enable(EventNames.PSHeapSummary); 46 recording.enable(EventNames.MetaspaceSummary).withThreshold(Duration.ofMillis(0)); 47 48 recording.start(); 49 // To eliminate the risk of being in the middle of a GC when the recording starts/stops, 50 // we run 5 System.gc() and ignores the first and last GC. 51 GCHelper.callSystemGc(5, true); 52 recording.stop(); 53 54 if (!checkCollectors(recording, expectedYoungCollector, expectedOldCollector)) { 55 return; 56 } 57 List<RecordedEvent> events = GCHelper.removeFirstAndLastGC(Events.fromRecording(recording)); 58 for (RecordedEvent event : events) { 59 System.out.println("Event:" + event); 60 } 61 62 Asserts.assertFalse(events.isEmpty(), "Expected at least one event."); 63 Asserts.assertEquals(events.size() % 2, 0, "Events should come in pairs"); 64 65 int lastHeapGcId = -1; 66 int lastG1GcId = -1; 67 int lastPSGcId = -1; 68 int lastMetaspaceGcId = -1; 69 70 for (RecordedEvent event : events) { 71 final String eventName = event.getEventType().getName(); 72 switch (eventName) { 73 case EventNames.GCHeapSummary: 74 lastHeapGcId = checkGcId(event, lastHeapGcId); 75 checkHeapEventContent(event); 76 break; 77 case EventNames.G1HeapSummary: 78 lastG1GcId = checkGcId(event, lastG1GcId); 79 checkG1EventContent(event); 80 break; 81 case EventNames.PSHeapSummary: 82 lastPSGcId = checkGcId(event, lastPSGcId); 83 checkPSEventContent(event); 84 break; 85 case EventNames.MetaspaceSummary: 86 lastMetaspaceGcId = checkGcId(event, lastMetaspaceGcId); 87 checkMetaspaceEventContent(event); 88 break; 89 default: 90 System.out.println("Failed event: " + event); 91 Asserts.fail("Unknown event type: " + eventName); 92 } 93 } 94 95 // Sanity check. Not complete. 96 Asserts.assertEquals(lastHeapGcId, lastMetaspaceGcId, "Should have gotten perm gen events for all GCs"); 97 } 98 99 private static void checkMetaspaceEventContent(RecordedEvent event) { 100 long totalUsed = Events.assertField(event, "metaspace.used").atLeast(0L).getValue(); 101 long totalCommitted = Events.assertField(event, "metaspace.committed").atLeast(totalUsed).getValue(); 102 long totalReserved = Events.assertField(event, "metaspace.reserved").atLeast(totalCommitted).getValue(); 103 104 long dataUsed = Events.assertField(event, "dataSpace.used").atLeast(0L).getValue(); 105 long dataCommitted = Events.assertField(event, "dataSpace.committed").atLeast(dataUsed).getValue(); 106 long dataReserved = Events.assertField(event, "dataSpace.reserved").atLeast(dataCommitted).getValue(); 107 108 long classUsed = Events.assertField(event, "classSpace.used").atLeast(0L).getValue(); 109 long classCommitted = Events.assertField(event, "classSpace.committed").atLeast(classUsed).getValue(); 110 long classReserved = Events.assertField(event, "classSpace.reserved").atLeast(classCommitted).getValue(); 111 112 Asserts.assertEquals(dataCommitted + classCommitted, totalCommitted, "Wrong committed memory"); 113 Asserts.assertEquals(dataUsed + classUsed, totalUsed, "Wrong used memory"); 114 Asserts.assertEquals(dataReserved + classReserved, totalReserved, "Wrong reserved memory"); 115 } 116 117 private static int checkGcId(RecordedEvent event, int currGcId) { 118 int gcId = Events.assertField(event, "gcId").getValue(); 119 String when = Events.assertField(event, "when").notEmpty().getValue(); 120 if ("Before GC".equals(when)) { 121 Asserts.assertGreaterThan(gcId, currGcId, "gcId should be increasing"); 122 } else { 123 Asserts.assertEquals(gcId, currGcId, "After should have same gcId as last Before event"); 124 } 125 return gcId; 126 } 127 128 private static void checkHeapEventContent(RecordedEvent event) { 129 checkVirtualSpace(event, "heapSpace"); 130 long heapUsed = Events.assertField(event, "heapUsed").atLeast(0L).getValue(); 131 long start = Events.assertField(event, "heapSpace.start").atLeast(0L).getValue(); 132 long committedEnd = Events.assertField(event, "heapSpace.committedEnd").above(start).getValue(); 133 Asserts.assertLessThanOrEqual(heapUsed, committedEnd- start, "used can not exceed size"); 134 } 135 136 private static void checkG1EventContent(RecordedEvent event) { 137 long edenUsedSize = Events.assertField(event, "edenUsedSize").atLeast(0L).getValue(); 138 long edenTotalSize = Events.assertField(event, "edenTotalSize").atLeast(0L).getValue(); 139 Asserts.assertLessThanOrEqual(edenUsedSize, edenTotalSize, "used can not exceed size"); 140 Events.assertField(event, "survivorUsedSize").atLeast(0L); 141 Events.assertField(event, "numberOfRegions").atLeast(0); 142 } 143 144 private static void checkPSEventContent(RecordedEvent event) { 145 checkVirtualSpace(event, "oldSpace"); 146 checkVirtualSpace(event, "youngSpace"); 147 checkSpace(event, "oldObjectSpace"); 148 checkSpace(event, "edenSpace"); 149 checkSpace(event, "fromSpace"); 150 checkSpace(event, "toSpace"); 151 152 checkPSYoungSizes(event); 153 checkPSYoungStartEnd(event); 154 } 155 156 private static void checkPSYoungSizes(RecordedEvent event) { 157 long youngSize = (long)Events.assertField(event, "youngSpace.committedEnd").getValue() - 158 (long)Events.assertField(event, "youngSpace.start").getValue(); 159 long edenSize = (long)Events.assertField(event, "edenSpace.end").getValue() - 160 (long)Events.assertField(event, "edenSpace.start").getValue(); 161 long fromSize = (long)Events.assertField(event, "fromSpace.end").getValue() - 162 (long)Events.assertField(event, "fromSpace.start").getValue(); 163 long toSize = (long)Events.assertField(event, "toSpace.end").getValue() - 164 (long)Events.assertField(event, "toSpace.start").getValue(); 165 Asserts.assertGreaterThanOrEqual(youngSize, edenSize + fromSize + toSize, "Young sizes don't match"); 166 } 167 168 private static void checkPSYoungStartEnd(RecordedEvent event) { 169 long oldEnd = Events.assertField(event, "oldSpace.reservedEnd").getValue(); 170 long youngStart = Events.assertField(event, "youngSpace.start").getValue(); 171 long youngEnd = Events.assertField(event, "youngSpace.committedEnd").getValue(); 172 long edenStart = Events.assertField(event, "edenSpace.start").getValue(); 173 long edenEnd = Events.assertField(event, "edenSpace.end").getValue(); 174 long fromStart = Events.assertField(event, "fromSpace.start").getValue(); 175 long fromEnd = Events.assertField(event, "fromSpace.end").getValue(); 176 long toStart = Events.assertField(event, "toSpace.start").getValue(); 177 long toEnd = Events.assertField(event, "toSpace.end").getValue(); 178 Asserts.assertEquals(oldEnd, youngStart, "Young should start where old ends"); 179 Asserts.assertEquals(youngStart, edenStart, "Eden should be placed first in young"); 180 if (fromStart < toStart) { 181 // [eden][from][to] 182 Asserts.assertGreaterThanOrEqual(fromStart, edenEnd, "From should start after eden"); 183 Asserts.assertLessThanOrEqual(fromEnd, toStart, "To should start after From"); 184 Asserts.assertLessThanOrEqual(toEnd, youngEnd, "To should start after From"); 185 } else { 186 // [eden][to][from] 187 Asserts.assertGreaterThanOrEqual(toStart, edenEnd, "From should start after eden"); 188 Asserts.assertLessThanOrEqual(toEnd, fromStart, "To should start after From"); 189 Asserts.assertLessThanOrEqual(fromEnd, youngEnd, "To should start after From"); 190 } 191 } 192 193 private static void checkVirtualSpace(RecordedEvent event, String structName) { 194 long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue(); 195 long committedEnd = Events.assertField(event, structName + ".committedEnd").above(start).getValue(); 196 Events.assertField(event, structName + ".reservedEnd").atLeast(committedEnd); 197 long committedSize = Events.assertField(event, structName + ".committedSize").atLeast(0L).getValue(); 198 Events.assertField(event, structName + ".reservedSize").atLeast(committedSize); 199 } 200 201 private static void checkSpace(RecordedEvent event, String structName) { 202 long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue(); 203 long end = Events.assertField(event, structName + ".end").above(start).getValue(); 204 long used = Events.assertField(event, structName + ".used").atLeast(0L).getValue(); 205 long size = Events.assertField(event, structName + ".size").atLeast(used).getValue(); 206 Asserts.assertEquals(size, end - start, "Size mismatch"); 207 } 208 209 private static boolean checkCollectors(Recording recording, String expectedYoung, String expectedOld) throws Exception { 210 for (RecordedEvent event : Events.fromRecording(recording)) { 211 if (Events.isEventType(event, EventNames.GCConfiguration)) { 212 final String young = Events.assertField(event, "youngCollector").notEmpty().getValue(); 213 final String old = Events.assertField(event, "oldCollector").notEmpty().getValue(); 214 if (young.equals(expectedYoung) && old.equals(expectedOld)) { 215 return true; 216 } 217 // TODO: We treat wrong collector types as an error. Old test only warned. Not sure what is correct. 218 Asserts.fail(String.format("Wrong collector types: got('%s','%s'), expected('%s','%s')", 219 young, old, expectedYoung, expectedOld)); 220 } 221 } 222 Asserts.fail("Missing event type " + EventNames.GCConfiguration); 223 return false; 224 } 225 }