1 /* 2 * Copyright (c) 2014, 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 package jdk.jfr.event.gc.detailed; 26 27 import static jdk.test.lib.Asserts.assertEquals; 28 import static jdk.test.lib.Asserts.assertNotEquals; 29 import static jdk.test.lib.Asserts.assertNotNull; 30 import static jdk.test.lib.Asserts.assertTrue; 31 32 import java.lang.management.GarbageCollectorMXBean; 33 import java.lang.management.ManagementFactory; 34 import java.util.List; 35 import java.util.concurrent.ThreadLocalRandom; 36 37 import jdk.jfr.Recording; 38 import jdk.jfr.consumer.RecordedEvent; 39 import jdk.test.lib.jfr.EventNames; 40 import jdk.test.lib.jfr.Events; 41 42 /** 43 * This is a base class for testing Promotion Events 44 * 45 * See TestPromotionEventWith* for actual test classes. Tests must set 46 * -XX:MaxTenuringThreshold=5 -XX:InitialTenuringThreshold=5 47 * 48 * @author Staffan Friberg 49 */ 50 public class PromotionEvent { 51 52 private final static String PROMOTION_IN_NEW_PLAB_NAME = EventNames.PromoteObjectInNewPLAB; 53 private final static String PROMOTION_OUTSIDE_PLAB_NAME = EventNames.PromoteObjectOutsidePLAB; 54 55 // This value needs to match the command line option set above 56 private final static int MAX_TENURING_THRESHOLD = 5; 57 58 // Keep track of the collection count just before and after JFR recording 59 private static int startGCCount = 0; 60 61 // Dummy objects to keep things alive and assure allocation happens 62 public static Object dummy; 63 public static Object[] keepAlive = new Object[128]; 64 public static Object[] age = new Object[128]; 65 66 public static void test() throws Exception { 67 GarbageCollectorMXBean ycBean = null; 68 69 List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); 70 for (GarbageCollectorMXBean gcBean : gcBeans) { 71 if ("PS Scavenge".equals(gcBean.getName()) 72 || "G1 Young Generation".equals(gcBean.getName()) 73 || ("ParNew".equals(gcBean.getName()))) { 74 ycBean = gcBean; 75 } 76 77 if (ycBean != null) { 78 break; 79 } 80 } 81 82 if (ycBean == null) { 83 assertNotNull(ycBean, "Test failed since the MXBean for the Young Collector could not be found."); 84 return; // To remove IDE warning 85 } 86 87 System.gc(); // Clear nusery before recording 88 89 // Get total GC count before recording 90 for (GarbageCollectorMXBean gcBean : gcBeans) { 91 startGCCount += gcBean.getCollectionCount(); 92 } 93 94 Recording recording = new Recording(); 95 recording.enable(PROMOTION_IN_NEW_PLAB_NAME); 96 recording.enable(PROMOTION_OUTSIDE_PLAB_NAME); 97 recording.start(); 98 99 byte[] largeBytes = new byte[1024 * 10]; 100 byte[] smallBytes = new byte[64]; 101 102 // Some large strings to keep alive for tenuring 103 for (int i = 0; i < keepAlive.length / 2; i++) { 104 ThreadLocalRandom.current().nextBytes(largeBytes); 105 keepAlive[i] = new String(largeBytes); 106 } 107 108 // Some small strings to keep alive for tenuring 109 for (int i = keepAlive.length / 2; i < keepAlive.length; i++) { 110 ThreadLocalRandom.current().nextBytes(smallBytes); 111 keepAlive[i] = new String(smallBytes); 112 } 113 114 // Allocate temp data to force GCs until we have promoted the live data 115 for (int gcCount = 0; gcCount < MAX_TENURING_THRESHOLD * 2; gcCount++) { 116 long currentGCCount = ycBean.getCollectionCount(); 117 118 // some large strings to age 119 for (int i = 0; i < age.length / 2; i++) { 120 ThreadLocalRandom.current().nextBytes(largeBytes); 121 age[i] = new String(largeBytes); 122 } 123 124 // Some small strings to age 125 for (int i = age.length / 2; i < age.length; i++) { 126 ThreadLocalRandom.current().nextBytes(smallBytes); 127 age[i] = new String(smallBytes); 128 } 129 130 while (ycBean.getCollectionCount() <= currentGCCount + 3) { 131 ThreadLocalRandom.current().nextBytes(smallBytes); 132 dummy = new String(smallBytes); 133 } 134 } 135 136 recording.stop(); 137 138 List<RecordedEvent> events = Events.fromRecording(recording); 139 140 verifyPromotionSampleEvents(events); 141 142 recording.close(); 143 } 144 145 private static void verifyPromotionSampleEvents(List<RecordedEvent> events) 146 throws Exception { 147 148 boolean objectWasPromotedInNewPLAB = false; 149 boolean objectPromotedInNewPLABWasAged = false; 150 boolean objectPromotedInNewPLABWasTenured = false; 151 boolean objectWasPromotedOutsidePLAB = false; 152 boolean objectPromotedOutsidePLABWasAged = false; 153 boolean objectPromotedOutsidePLABWasTenured = false; 154 155 Events.hasEvents(events); 156 157 for (RecordedEvent event : events) { 158 // Read all common fields 159 Events.assertField(event, "gcId").atLeast(startGCCount).getValue(); 160 String className = (event.getEventType()).getName().toString(); 161 Events.assertField(event, "tenuringAge").atLeast(0).atMost(MAX_TENURING_THRESHOLD).getValue(); 162 Boolean tenured = Events.assertField(event, "tenured").getValue(); 163 Long objectSize = Events.assertField(event, "objectSize").above(0L).getValue(); 164 165 // Verify Class Name 166 assertNotNull(className, "Class name is null. Event: " + event); 167 assertNotEquals(className.length(), 0, "Class name is of zero length. Event: " + event); 168 169 // Verify PLAB size and direct allocation 170 if (PROMOTION_IN_NEW_PLAB_NAME.equals(event.getEventType().getName())) { 171 // Read event specific fields 172 Long plabSize = Events.assertField(event, "plabSize").above(0L).getValue(); 173 assertTrue(plabSize >= objectSize, "PLAB size is smaller than object size. Event: " + event); 174 objectWasPromotedInNewPLAB = true; 175 // Verify tenured is hard to do as objects might be tenured earlier than the max threshold 176 // but at least verify that we got the field set at least once during the test 177 if (tenured) { 178 objectPromotedInNewPLABWasTenured = true; 179 } else { 180 objectPromotedInNewPLABWasAged = true; 181 } 182 } else if (PROMOTION_OUTSIDE_PLAB_NAME.equals(event.getEventType().getName())) { 183 objectWasPromotedOutsidePLAB = true; 184 // Verify tenured is hard to do as objects might be tenured earlier than the max threshold 185 // but at least verify that we got the field set at least once during the test 186 if (tenured) { 187 objectPromotedOutsidePLABWasTenured = true; 188 } else { 189 objectPromotedOutsidePLABWasAged = true; 190 } 191 } else { 192 assertEquals(event.getEventType().getName(), "Unreachable...", "Got wrong type of event " + event); 193 } 194 195 } 196 197 // Verify that at least one event of these types occured during test 198 assertTrue(objectWasPromotedInNewPLAB, "No object in new plab was promoted in test"); 199 assertTrue(objectPromotedInNewPLABWasAged, "No object in new plab was aged in test"); 200 assertTrue(objectPromotedInNewPLABWasTenured, "No object in new plab was tenured in test"); 201 assertTrue(objectWasPromotedOutsidePLAB, "No object outside plab was promoted in test"); 202 assertTrue(objectPromotedOutsidePLABWasAged, "No object outside plab was aged in test"); 203 assertTrue(objectPromotedOutsidePLABWasTenured, "No object outside plab was tenured in test"); 204 } 205 }