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