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 || "G1 Young".equals(gcBean.getName()) 74 || "ParNew".equals(gcBean.getName())) { 75 ycBean = gcBean; 76 } 77 78 if (ycBean != null) { 79 break; 80 } 81 } 82 83 if (ycBean == null) { 84 assertNotNull(ycBean, "Test failed since the MXBean for the Young Collector could not be found."); 85 return; // To remove IDE warning 86 } 87 88 System.gc(); // Clear nursery before recording 89 90 // Get total GC count before recording 91 for (GarbageCollectorMXBean gcBean : gcBeans) { 92 startGCCount += gcBean.getCollectionCount(); 93 } 94 95 Recording recording = new Recording(); 96 recording.enable(PROMOTION_IN_NEW_PLAB_NAME); 97 recording.enable(PROMOTION_OUTSIDE_PLAB_NAME); 98 recording.start(); 99 100 byte[] largeBytes = new byte[1024 * 10]; 101 byte[] smallBytes = new byte[64]; 102 103 // Some large strings to keep alive for tenuring 104 for (int i = 0; i < keepAlive.length / 2; i++) { 105 ThreadLocalRandom.current().nextBytes(largeBytes); 106 keepAlive[i] = new String(largeBytes); 107 } 108 109 // Some small strings to keep alive for tenuring 110 for (int i = keepAlive.length / 2; i < keepAlive.length; i++) { 111 ThreadLocalRandom.current().nextBytes(smallBytes); 112 keepAlive[i] = new String(smallBytes); 113 } 114 115 // Allocate temp data to force GCs until we have promoted the live data 116 for (int gcCount = 0; gcCount < MAX_TENURING_THRESHOLD * 2; gcCount++) { 117 long currentGCCount = ycBean.getCollectionCount(); 118 119 // some large strings to age 120 for (int i = 0; i < age.length / 2; i++) { 121 ThreadLocalRandom.current().nextBytes(largeBytes); 122 age[i] = new String(largeBytes); 123 } 124 125 // Some small strings to age 126 for (int i = age.length / 2; i < age.length; i++) { 127 ThreadLocalRandom.current().nextBytes(smallBytes); 128 age[i] = new String(smallBytes); 129 } 130 131 while (ycBean.getCollectionCount() <= currentGCCount + 3) { 132 ThreadLocalRandom.current().nextBytes(smallBytes); 133 dummy = new String(smallBytes); 134 } 135 } 136 137 recording.stop(); 138 139 List<RecordedEvent> events = Events.fromRecording(recording); 140 141 verifyPromotionSampleEvents(events); 142 143 recording.close(); 144 } 145 146 private static void verifyPromotionSampleEvents(List<RecordedEvent> events) 147 throws Exception { 148 149 boolean objectWasPromotedInNewPLAB = false; 150 boolean objectPromotedInNewPLABWasAged = false; 151 boolean objectPromotedInNewPLABWasTenured = false; 152 boolean objectWasPromotedOutsidePLAB = false; 153 boolean objectPromotedOutsidePLABWasAged = false; 154 boolean objectPromotedOutsidePLABWasTenured = false; 155 156 Events.hasEvents(events); 157 158 for (RecordedEvent event : events) { 159 // Read all common fields 160 Events.assertField(event, "gcId").atLeast(startGCCount).getValue(); 161 String className = (event.getEventType()).getName().toString(); 162 Events.assertField(event, "tenuringAge").atLeast(0).atMost(MAX_TENURING_THRESHOLD).getValue(); 163 Boolean tenured = Events.assertField(event, "tenured").getValue(); 164 Long objectSize = Events.assertField(event, "objectSize").above(0L).getValue(); 165 166 // Verify Class Name 167 assertNotNull(className, "Class name is null. Event: " + event); 168 assertNotEquals(className.length(), 0, "Class name is of zero length. Event: " + event); 169 170 // Verify PLAB size and direct allocation 171 if (PROMOTION_IN_NEW_PLAB_NAME.equals(event.getEventType().getName())) { 172 // Read event specific fields 173 Long plabSize = Events.assertField(event, "plabSize").above(0L).getValue(); 174 assertTrue(plabSize >= objectSize, "PLAB size is smaller than object size. Event: " + event); 175 objectWasPromotedInNewPLAB = true; 176 // Verify tenured is hard to do as objects might be tenured earlier than the max threshold 177 // but at least verify that we got the field set at least once during the test 178 if (tenured) { 179 objectPromotedInNewPLABWasTenured = true; 180 } else { 181 objectPromotedInNewPLABWasAged = true; 182 } 183 } else if (PROMOTION_OUTSIDE_PLAB_NAME.equals(event.getEventType().getName())) { 184 objectWasPromotedOutsidePLAB = true; 185 // Verify tenured is hard to do as objects might be tenured earlier than the max threshold 186 // but at least verify that we got the field set at least once during the test 187 if (tenured) { 188 objectPromotedOutsidePLABWasTenured = true; 189 } else { 190 objectPromotedOutsidePLABWasAged = true; 191 } 192 } else { 193 assertEquals(event.getEventType().getName(), "Unreachable...", "Got wrong type of event " + event); 194 } 195 196 } 197 198 // Verify that at least one event of these types occured during test 199 assertTrue(objectWasPromotedInNewPLAB, "No object in new plab was promoted in test"); 200 assertTrue(objectPromotedInNewPLABWasAged, "No object in new plab was aged in test"); 201 assertTrue(objectPromotedInNewPLABWasTenured, "No object in new plab was tenured in test"); 202 assertTrue(objectWasPromotedOutsidePLAB, "No object outside plab was promoted in test"); 203 assertTrue(objectPromotedOutsidePLABWasAged, "No object outside plab was aged in test"); 204 assertTrue(objectPromotedOutsidePLABWasTenured, "No object outside plab was tenured in test"); 205 } 206 }