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