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 31 * 32 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 33 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 34 * -XX:+ShenandoahDegeneratedGC 35 * TestPauseNotifications 36 * 37 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 38 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 39 * -XX:-ShenandoahDegeneratedGC 40 * TestPauseNotifications 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 48 * 49 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 50 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive 51 * TestPauseNotifications 52 */ 53 54 /* 55 * @test id=adaptive 56 * @summary Check that MX notifications are reported for all cycles 57 * @library /test/lib / 58 * @requires vm.gc.Shenandoah 59 * 60 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 61 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive 62 * TestPauseNotifications 63 */ 64 65 /* 66 * @test id=static 67 * @summary Check that MX notifications are reported for all cycles 68 * @library /test/lib / 69 * @requires vm.gc.Shenandoah 70 * 71 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 72 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=static 73 * TestPauseNotifications 74 */ 75 76 /* 77 * @test id=compact 78 * @summary Check that MX notifications are reported for all cycles 79 * @library /test/lib / 80 * @requires vm.gc.Shenandoah 81 * 82 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 83 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 84 * TestPauseNotifications 85 */ 86 87 /* 88 * @test id=generational 89 * @summary Check that MX notifications are reported for all cycles 90 * @library /test/lib / 91 * @requires vm.gc.Shenandoah 92 * 93 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 94 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational 95 * TestPauseNotifications 96 */ 97 98 import java.util.*; 99 import java.util.concurrent.atomic.*; 100 import javax.management.*; 101 import java.lang.management.*; 102 import javax.management.openmbean.*; 103 104 import jdk.test.lib.Utils; 105 106 import com.sun.management.GarbageCollectionNotificationInfo; 107 108 public class TestPauseNotifications { 109 110 static final long HEAP_MB = 128; // adjust for test configuration above 111 static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation 112 113 static volatile Object sink; 114 115 private static boolean isExpectedPauseAction(String action) { 116 return "Init Mark".equals(action) || "Final Mark".equals(action) || "Full GC".equals(action) 117 || "Degenerated GC".equals(action) || "Init Update Refs".equals(action) 118 || "Final Update Refs".equals(action) || "Final Roots".equals(action); 119 } 120 121 public static void main(String[] args) throws Exception { 122 final long startTimeNanos = System.nanoTime(); 123 124 final AtomicLong pausesDuration = new AtomicLong(); 125 final AtomicLong cyclesDuration = new AtomicLong(); 126 final AtomicLong pausesCount = new AtomicLong(); 127 final AtomicLong cyclesCount = new AtomicLong(); 128 129 NotificationListener listener = new NotificationListener() { 130 @Override 131 public void handleNotification(Notification n, Object o) { 132 if (n.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 133 GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) n.getUserData()); 134 135 System.out.println("Received: " + info.getGcName() + "/" + info.getGcAction()); 136 137 138 long d = info.getGcInfo().getDuration(); 139 140 String name = info.getGcName(); 141 if (name.contains("Shenandoah")) { 142 if (name.equals("Shenandoah Pauses")) { 143 pausesCount.incrementAndGet(); 144 pausesDuration.addAndGet(d); 145 if (!isExpectedPauseAction(info.getGcAction())) { 146 throw new IllegalStateException("Unknown action: " + info.getGcAction()); 147 } 148 } else if (name.equals("Shenandoah Cycles")) { 149 cyclesCount.incrementAndGet(); 150 cyclesDuration.addAndGet(d); 151 } else { 152 throw new IllegalStateException("Unknown name: " + name); 153 } 154 } 155 } 156 } 157 }; 158 159 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 160 ((NotificationEmitter) bean).addNotificationListener(listener, null, null); 161 } 162 163 final int size = 100_000; 164 long count = TARGET_MB * 1024 * 1024 / (16 + 4 * size); 165 166 for (int c = 0; c < count; c++) { 167 sink = new int[size]; 168 } 169 170 // Look at test timeout to figure out how long we can wait without breaking into timeout. 171 // Default to 1/4 of the remaining time in 1s steps. 172 final long STEP_MS = 1000; 173 long spentTimeNanos = System.nanoTime() - startTimeNanos; 174 long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - (spentTimeNanos / 1_000_000L)) / STEP_MS / 4; 175 176 long actualPauses = 0; 177 long actualCycles = 0; 178 179 // Wait until enough notifications are accrued to match minimum boundary. 180 long minExpected = 10; 181 182 long tries = 0; 183 while (tries++ < maxTries) { 184 actualPauses = pausesCount.get(); 185 actualCycles = cyclesCount.get(); 186 if (minExpected <= actualPauses && minExpected <= actualCycles) { 187 // Wait a little bit to catch the lingering notifications. 188 Thread.sleep(5000); 189 actualPauses = pausesCount.get(); 190 actualCycles = cyclesCount.get(); 191 break; 192 } 193 Thread.sleep(STEP_MS); 194 } 195 196 { 197 String msg = "Pauses expected = [" + minExpected + "; +inf], actual = " + actualPauses; 198 if (minExpected <= actualPauses) { 199 System.out.println(msg); 200 } else { 201 throw new IllegalStateException(msg); 202 } 203 } 204 205 { 206 String msg = "Cycles expected = [" + minExpected + "; +inf], actual = " + actualCycles; 207 if (minExpected <= actualCycles) { 208 System.out.println(msg); 209 } else { 210 throw new IllegalStateException(msg); 211 } 212 } 213 214 { 215 long actualPauseDuration = pausesDuration.get(); 216 long actualCycleDuration = cyclesDuration.get(); 217 218 String msg = "Pauses duration (" + actualPauseDuration + ") is expected to be not larger than cycles duration (" + actualCycleDuration + ")"; 219 220 if (actualPauseDuration <= actualCycleDuration) { 221 System.out.println(msg); 222 } else { 223 throw new IllegalStateException(msg); 224 } 225 } 226 } 227 }