1 /* 2 * Copyright (c) 2018, Red Hat, Inc. All rights reserved. 3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. 9 * 10 * This code is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * version 2 for more details (a copy is included in the LICENSE file that 14 * accompanied this code). 15 * 16 * You should have received a copy of the GNU General Public License version 17 * 2 along with this work; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 19 * 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 21 * or visit www.oracle.com if you need additional information or have any 22 * questions. 23 * 24 */ 25 26 /* 27 * @test id=passive 28 * @summary Check that MX notifications are reported for all cycles 29 * @library /test/lib / 30 * @requires vm.gc.Shenandoah & vm.opt.ShenandoahGCMode != "generational" 31 * 32 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 33 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 34 * -XX:+ShenandoahDegeneratedGC -Dprecise=true 35 * TestChurnNotifications 36 * 37 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 38 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 39 * -XX:-ShenandoahDegeneratedGC -Dprecise=true 40 * TestChurnNotifications 41 */ 42 43 /* 44 * @test id=aggressive 45 * @summary Check that MX notifications are reported for all cycles 46 * @library /test/lib / 47 * @requires vm.gc.Shenandoah & vm.opt.ShenandoahGCMode != "generational" 48 * 49 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 50 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive 51 * -Dprecise=false 52 * TestChurnNotifications 53 */ 54 55 /* 56 * @test id=adaptive 57 * @summary Check that MX notifications are reported for all cycles 58 * @library /test/lib / 59 * @requires vm.gc.Shenandoah & vm.opt.ShenandoahGCMode != "generational" 60 * 61 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 62 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive 63 * -Dprecise=false 64 * TestChurnNotifications 65 */ 66 67 /* 68 * @test id=static 69 * @summary Check that MX notifications are reported for all cycles 70 * @library /test/lib / 71 * @requires vm.gc.Shenandoah & vm.opt.ShenandoahGCMode != "generational" 72 * 73 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 74 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=static 75 * -Dprecise=false 76 * TestChurnNotifications 77 */ 78 79 /* 80 * @test id=compact 81 * @summary Check that MX notifications are reported for all cycles 82 * @library /test/lib / 83 * @requires vm.gc.Shenandoah & vm.opt.ShenandoahGCMode != "generational" 84 * 85 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 86 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 87 * -Dprecise=false 88 * TestChurnNotifications 89 */ 90 91 /* 92 * @test id=iu 93 * @summary Check that MX notifications are reported for all cycles 94 * @library /test/lib / 95 * @requires vm.gc.Shenandoah 96 * 97 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 98 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive 99 * -Dprecise=false 100 * TestChurnNotifications 101 * 102 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 103 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu 104 * -Dprecise=false 105 * TestChurnNotifications 106 */ 107 108 /* 109 * @test id=generational 110 * @summary Check that MX notifications are reported for all cycles 111 * @library /test/lib / 112 * @requires vm.gc.Shenandoah 113 * 114 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 115 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational 116 * -Dprecise=false -Dmem.pool=Young 117 * TestChurnNotifications 118 */ 119 120 import java.util.*; 121 import java.util.concurrent.atomic.*; 122 import javax.management.*; 123 import java.lang.management.*; 124 import javax.management.openmbean.*; 125 126 import jdk.test.lib.Utils; 127 128 import com.sun.management.GarbageCollectionNotificationInfo; 129 130 public class TestChurnNotifications { 131 132 static final long HEAP_MB = 128; // adjust for test configuration above 133 static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation 134 135 // Should we track the churn precisely? 136 // Precise tracking is only reliable when GC is fully stop-the-world. Otherwise, 137 // we cannot tell, looking at heap used before/after, what was the GC churn. 138 static final boolean PRECISE = Boolean.getBoolean("precise"); 139 140 static final long M = 1024 * 1024; 141 142 static volatile Object sink; 143 144 private static final String POOL_NAME = "Young".equals(System.getProperty("mem.pool")) ? "Shenandoah Young Gen" : "Shenandoah"; 145 146 public static void main(String[] args) throws Exception { 147 final long startTimeNanos = System.nanoTime(); 148 149 final AtomicLong churnBytes = new AtomicLong(); 150 151 NotificationListener listener = new NotificationListener() { 152 @Override 153 public void handleNotification(Notification n, Object o) { 154 if (n.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 155 GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) n.getUserData()); 156 Map<String, MemoryUsage> mapBefore = info.getGcInfo().getMemoryUsageBeforeGc(); 157 Map<String, MemoryUsage> mapAfter = info.getGcInfo().getMemoryUsageAfterGc(); 158 159 MemoryUsage before = mapBefore.get(POOL_NAME); 160 MemoryUsage after = mapAfter.get(POOL_NAME); 161 162 if ((before != null) && (after != null)) { 163 long diff = before.getUsed() - after.getUsed(); 164 if (diff > 0) { 165 churnBytes.addAndGet(diff); 166 } 167 } 168 } 169 } 170 }; 171 172 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 173 ((NotificationEmitter) bean).addNotificationListener(listener, null, null); 174 } 175 176 final int size = 100_000; 177 long count = TARGET_MB * 1024 * 1024 / (16 + 4 * size); 178 179 long mem = count * (16 + 4 * size); 180 181 for (int c = 0; c < count; c++) { 182 sink = new int[size]; 183 } 184 185 System.gc(); 186 187 long minExpected = PRECISE ? (mem - HEAP_MB * 1024 * 1024) : 1; 188 long maxExpected = mem + HEAP_MB * 1024 * 1024; 189 long actual = 0; 190 191 // Look at test timeout to figure out how long we can wait without breaking into timeout. 192 // Default to 1/4 of the remaining time in 1s steps. 193 final long STEP_MS = 1000; 194 long spentTimeNanos = System.nanoTime() - startTimeNanos; 195 long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - (spentTimeNanos / 1_000_000L)) / STEP_MS / 4; 196 197 // Wait until enough notifications are accrued to match minimum boundary. 198 long tries = 0; 199 while (tries++ < maxTries) { 200 actual = churnBytes.get(); 201 if (minExpected <= actual) { 202 // Wait some more to test if we are breaking the maximum boundary. 203 Thread.sleep(5000); 204 actual = churnBytes.get(); 205 break; 206 } 207 Thread.sleep(STEP_MS); 208 } 209 210 String msg = "Expected = [" + minExpected / M + "; " + maxExpected / M + "] (" + mem / M + "), actual = " + actual / M; 211 if (minExpected <= actual && actual <= maxExpected) { 212 System.out.println(msg); 213 } else { 214 throw new IllegalStateException(msg); 215 } 216 } 217 }