1 /* 2 * Copyright (c) 2018, Red Hat, Inc. 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* 26 * @test id=passive 27 * @summary Check that MX notifications are reported for all cycles 28 * @library /test/lib / 29 * @requires vm.gc.Shenandoah 30 * 31 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 32 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 33 * -XX:+ShenandoahDegeneratedGC 34 * TestPauseNotifications 35 * 36 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 37 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 38 * -XX:-ShenandoahDegeneratedGC 39 * TestPauseNotifications 40 */ 41 42 /* 43 * @test id=aggressive 44 * @summary Check that MX notifications are reported for all cycles 45 * @library /test/lib / 46 * @requires vm.gc.Shenandoah 47 * 48 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 49 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive 50 * TestPauseNotifications 51 */ 52 53 /* 54 * @test id=adaptive 55 * @summary Check that MX notifications are reported for all cycles 56 * @library /test/lib / 57 * @requires vm.gc.Shenandoah 58 * 59 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 60 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive 61 * TestPauseNotifications 62 */ 63 64 /* 65 * @test id=static 66 * @summary Check that MX notifications are reported for all cycles 67 * @library /test/lib / 68 * @requires vm.gc.Shenandoah 69 * 70 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 71 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=static 72 * TestPauseNotifications 73 */ 74 75 /* 76 * @test id=compact 77 * @summary Check that MX notifications are reported for all cycles 78 * @library /test/lib / 79 * @requires vm.gc.Shenandoah 80 * 81 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 82 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 83 * TestPauseNotifications 84 */ 85 86 import java.util.*; 87 import java.util.concurrent.atomic.*; 88 import javax.management.*; 89 import java.lang.management.*; 90 import javax.management.openmbean.*; 91 92 import jdk.test.lib.Utils; 93 94 import com.sun.management.GarbageCollectionNotificationInfo; 95 96 public class TestPauseNotifications { 97 98 static final long HEAP_MB = 128; // adjust for test configuration above 99 static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation 100 101 static volatile Object sink; 102 103 private static boolean isExpectedPauseAction(String action) { 104 return "Init Mark".equals(action) || "Final Mark".equals(action) || "Full GC".equals(action) 105 || "Degenerated GC".equals(action) || "Init Update Refs".equals(action) 106 || "Final Update Refs".equals(action) || "Final Roots".equals(action); 107 } 108 109 public static void main(String[] args) throws Exception { 110 final long startTimeNanos = System.nanoTime(); 111 112 final AtomicLong pausesDuration = new AtomicLong(); 113 final AtomicLong cyclesDuration = new AtomicLong(); 114 final AtomicLong pausesCount = new AtomicLong(); 115 final AtomicLong cyclesCount = new AtomicLong(); 116 117 NotificationListener listener = new NotificationListener() { 118 @Override 119 public void handleNotification(Notification n, Object o) { 120 if (n.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 121 GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) n.getUserData()); 122 123 System.out.println("Received: " + info.getGcName() + "/" + info.getGcAction()); 124 125 126 long d = info.getGcInfo().getDuration(); 127 128 String name = info.getGcName(); 129 if (name.contains("Shenandoah")) { 130 if (name.equals("Shenandoah Pauses")) { 131 pausesCount.incrementAndGet(); 132 pausesDuration.addAndGet(d); 133 if (!isExpectedPauseAction(info.getGcAction())) { 134 throw new IllegalStateException("Unknown action: " + info.getGcAction()); 135 } 136 } else if (name.equals("Shenandoah Cycles")) { 137 cyclesCount.incrementAndGet(); 138 cyclesDuration.addAndGet(d); 139 } else { 140 throw new IllegalStateException("Unknown name: " + name); 141 } 142 } 143 } 144 } 145 }; 146 147 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 148 ((NotificationEmitter) bean).addNotificationListener(listener, null, null); 149 } 150 151 final int size = 100_000; 152 long count = TARGET_MB * 1024 * 1024 / (16 + 4 * size); 153 154 for (int c = 0; c < count; c++) { 155 sink = new int[size]; 156 } 157 158 // Look at test timeout to figure out how long we can wait without breaking into timeout. 159 // Default to 1/4 of the remaining time in 1s steps. 160 final long STEP_MS = 1000; 161 long spentTimeNanos = System.nanoTime() - startTimeNanos; 162 long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - (spentTimeNanos / 1_000_000L)) / STEP_MS / 4; 163 164 long actualPauses = 0; 165 long actualCycles = 0; 166 167 // Wait until enough notifications are accrued to match minimum boundary. 168 long minExpected = 10; 169 170 long tries = 0; 171 while (tries++ < maxTries) { 172 actualPauses = pausesCount.get(); 173 actualCycles = cyclesCount.get(); 174 if (minExpected <= actualPauses && minExpected <= actualCycles) { 175 // Wait a little bit to catch the lingering notifications. 176 Thread.sleep(5000); 177 actualPauses = pausesCount.get(); 178 actualCycles = cyclesCount.get(); 179 break; 180 } 181 Thread.sleep(STEP_MS); 182 } 183 184 { 185 String msg = "Pauses expected = [" + minExpected + "; +inf], actual = " + actualPauses; 186 if (minExpected <= actualPauses) { 187 System.out.println(msg); 188 } else { 189 throw new IllegalStateException(msg); 190 } 191 } 192 193 { 194 String msg = "Cycles expected = [" + minExpected + "; +inf], actual = " + actualCycles; 195 if (minExpected <= actualCycles) { 196 System.out.println(msg); 197 } else { 198 throw new IllegalStateException(msg); 199 } 200 } 201 202 { 203 long actualPauseDuration = pausesDuration.get(); 204 long actualCycleDuration = cyclesDuration.get(); 205 206 String msg = "Pauses duration (" + actualPauseDuration + ") is expected to be not larger than cycles duration (" + actualCycleDuration + ")"; 207 208 if (actualPauseDuration <= actualCycleDuration) { 209 System.out.println(msg); 210 } else { 211 throw new IllegalStateException(msg); 212 } 213 } 214 } 215 }