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