1 /* 2 * Copyright (c) 2013, 2019, 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.testlibrary.jfr; 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.testlibrary.Asserts; 34 import jdk.testlibrary.jfr.EventNames; 35 import jdk.testlibrary.jfr.Events; 36 import jdk.testlibrary.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.PSHeapSummary); 45 recording.enable(EventNames.MetaspaceSummary).withThreshold(Duration.ofMillis(0)); 46 47 recording.start(); 48 // To eliminate the risk of being in the middle of a GC when the recording starts/stops, 49 // we run 5 System.gc() and ignores the first and last GC. 50 GCHelper.callSystemGc(5, true); 51 recording.stop(); 52 53 if (!checkCollectors(recording, expectedYoungCollector, expectedOldCollector)) { 54 return; 55 } 56 List<RecordedEvent> events = GCHelper.removeFirstAndLastGC(Events.fromRecording(recording)); 57 for (RecordedEvent event : events) { 58 System.out.println("Event:" + event); 59 } 60 61 Asserts.assertFalse(events.isEmpty(), "Expected at least one event."); 62 Asserts.assertEquals(events.size() % 2, 0, "Events should come in pairs"); 63 64 int lastHeapGcId = -1; 65 int lastPSGcId = -1; 66 int lastMetaspaceGcId = -1; 67 68 for (RecordedEvent event : events) { 69 final String eventName = event.getEventType().getName(); 70 switch (eventName) { 71 case EventNames.GCHeapSummary: 72 lastHeapGcId = checkGcId(event, lastHeapGcId); 73 checkHeapEventContent(event); 74 break; 75 case EventNames.PSHeapSummary: 76 lastPSGcId = checkGcId(event, lastPSGcId); 77 checkPSEventContent(event); 78 break; 79 case EventNames.MetaspaceSummary: 80 lastMetaspaceGcId = checkGcId(event, lastMetaspaceGcId); 81 checkMetaspaceEventContent(event); 82 break; 83 default: 84 System.out.println("Failed event: " + event); 85 Asserts.fail("Unknown event type: " + eventName); 86 } 87 } 88 89 // Sanity check. Not complete. 90 Asserts.assertEquals(lastHeapGcId, lastMetaspaceGcId, "Should have gotten perm gen events for all GCs"); 91 } 92 93 private static void checkMetaspaceEventContent(RecordedEvent event) { 94 long totalUsed = Events.assertField(event, "metaspace.used").atLeast(0L).getValue(); 95 long totalCommitted = Events.assertField(event, "metaspace.committed").atLeast(totalUsed).getValue(); 96 long totalReserved = Events.assertField(event, "metaspace.reserved").atLeast(totalCommitted).getValue(); 97 98 long dataUsed = Events.assertField(event, "dataSpace.used").atLeast(0L).getValue(); 99 long dataCommitted = Events.assertField(event, "dataSpace.committed").atLeast(dataUsed).getValue(); 100 long dataReserved = Events.assertField(event, "dataSpace.reserved").atLeast(dataCommitted).getValue(); 101 102 long classUsed = Events.assertField(event, "classSpace.used").atLeast(0L).getValue(); 103 long classCommitted = Events.assertField(event, "classSpace.committed").atLeast(classUsed).getValue(); 104 long classReserved = Events.assertField(event, "classSpace.reserved").atLeast(classCommitted).getValue(); 105 106 Asserts.assertEquals(dataCommitted + classCommitted, totalCommitted, "Wrong committed memory"); 107 Asserts.assertEquals(dataUsed + classUsed, totalUsed, "Wrong used memory"); 108 Asserts.assertEquals(dataReserved + classReserved, totalReserved, "Wrong reserved memory"); 109 } 110 111 private static int checkGcId(RecordedEvent event, int currGcId) { 112 int gcId = Events.assertField(event, "gcId").getValue(); 113 String when = Events.assertField(event, "when").notEmpty().getValue(); 114 if ("Before GC".equals(when)) { 115 Asserts.assertGreaterThan(gcId, currGcId, "gcId should be increasing"); 116 } else { 117 Asserts.assertEquals(gcId, currGcId, "After should have same gcId as last Before event"); 118 } 119 return gcId; 120 } 121 122 private static void checkHeapEventContent(RecordedEvent event) { 123 checkVirtualSpace(event, "heapSpace"); 124 long heapUsed = Events.assertField(event, "heapUsed").atLeast(0L).getValue(); 125 long start = Events.assertField(event, "heapSpace.start").atLeast(0L).getValue(); 126 long committedEnd = Events.assertField(event, "heapSpace.committedEnd").above(start).getValue(); 127 Asserts.assertLessThanOrEqual(heapUsed, committedEnd- start, "used can not exceed size"); 128 } 129 130 private static void checkPSEventContent(RecordedEvent event) { 131 checkVirtualSpace(event, "oldSpace"); 132 checkVirtualSpace(event, "youngSpace"); 133 checkSpace(event, "oldObjectSpace"); 134 checkSpace(event, "edenSpace"); 135 checkSpace(event, "fromSpace"); 136 checkSpace(event, "toSpace"); 137 138 checkPSYoungSizes(event); 139 checkPSYoungStartEnd(event); 140 } 141 142 private static void checkPSYoungSizes(RecordedEvent event) { 143 long youngSize = (long)Events.assertField(event, "youngSpace.committedEnd").getValue() - 144 (long)Events.assertField(event, "youngSpace.start").getValue(); 145 long edenSize = (long)Events.assertField(event, "edenSpace.end").getValue() - 146 (long)Events.assertField(event, "edenSpace.start").getValue(); 147 long fromSize = (long)Events.assertField(event, "fromSpace.end").getValue() - 148 (long)Events.assertField(event, "fromSpace.start").getValue(); 149 long toSize = (long)Events.assertField(event, "toSpace.end").getValue() - 150 (long)Events.assertField(event, "toSpace.start").getValue(); 151 Asserts.assertGreaterThanOrEqual(youngSize, edenSize + fromSize + toSize, "Young sizes don't match"); 152 } 153 154 private static void checkPSYoungStartEnd(RecordedEvent event) { 155 long oldEnd = Events.assertField(event, "oldSpace.reservedEnd").getValue(); 156 long youngStart = Events.assertField(event, "youngSpace.start").getValue(); 157 long youngEnd = Events.assertField(event, "youngSpace.committedEnd").getValue(); 158 long edenStart = Events.assertField(event, "edenSpace.start").getValue(); 159 long edenEnd = Events.assertField(event, "edenSpace.end").getValue(); 160 long fromStart = Events.assertField(event, "fromSpace.start").getValue(); 161 long fromEnd = Events.assertField(event, "fromSpace.end").getValue(); 162 long toStart = Events.assertField(event, "toSpace.start").getValue(); 163 long toEnd = Events.assertField(event, "toSpace.end").getValue(); 164 Asserts.assertEquals(oldEnd, youngStart, "Young should start where old ends"); 165 Asserts.assertEquals(youngStart, edenStart, "Eden should be placed first in young"); 166 if (fromStart < toStart) { 167 // [eden][from][to] 168 Asserts.assertGreaterThanOrEqual(fromStart, edenEnd, "From should start after eden"); 169 Asserts.assertLessThanOrEqual(fromEnd, toStart, "To should start after From"); 170 Asserts.assertLessThanOrEqual(toEnd, youngEnd, "To should start after From"); 171 } else { 172 // [eden][to][from] 173 Asserts.assertGreaterThanOrEqual(toStart, edenEnd, "From should start after eden"); 174 Asserts.assertLessThanOrEqual(toEnd, fromStart, "To should start after From"); 175 Asserts.assertLessThanOrEqual(fromEnd, youngEnd, "To should start after From"); 176 } 177 } 178 179 private static void checkVirtualSpace(RecordedEvent event, String structName) { 180 long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue(); 181 long committedEnd = Events.assertField(event, structName + ".committedEnd").above(start).getValue(); 182 Events.assertField(event, structName + ".reservedEnd").atLeast(committedEnd); 183 long committedSize = Events.assertField(event, structName + ".committedSize").atLeast(0L).getValue(); 184 Events.assertField(event, structName + ".reservedSize").atLeast(committedSize); 185 } 186 187 private static void checkSpace(RecordedEvent event, String structName) { 188 long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue(); 189 long end = Events.assertField(event, structName + ".end").above(start).getValue(); 190 long used = Events.assertField(event, structName + ".used").atLeast(0L).getValue(); 191 long size = Events.assertField(event, structName + ".size").atLeast(used).getValue(); 192 Asserts.assertEquals(size, end - start, "Size mismatch"); 193 } 194 195 private static boolean checkCollectors(Recording recording, String expectedYoung, String expectedOld) throws Exception { 196 for (RecordedEvent event : Events.fromRecording(recording)) { 197 if (Events.isEventType(event, EventNames.GCConfiguration)) { 198 final String young = Events.assertField(event, "youngCollector").notEmpty().getValue(); 199 final String old = Events.assertField(event, "oldCollector").notEmpty().getValue(); 200 if (young.equals(expectedYoung) && old.equals(expectedOld)) { 201 return true; 202 } 203 // TODO: We treat wrong collector types as an error. Old test only warned. Not sure what is correct. 204 Asserts.fail(String.format("Wrong collector types: got('%s','%s'), expected('%s','%s')", 205 young, old, expectedYoung, expectedOld)); 206 } 207 } 208 Asserts.fail("Missing event type " + EventNames.GCConfiguration); 209 return false; 210 } 211 }