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 -Dprecise=true 34 * TestChurnNotifications 35 * 36 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 37 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=passive 38 * -XX:-ShenandoahDegeneratedGC -Dprecise=true 39 * TestChurnNotifications 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 * -Dprecise=false 51 * TestChurnNotifications 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 * -Dprecise=false 63 * TestChurnNotifications 64 */ 65 66 /* 67 * @test id=static 68 * @summary Check that MX notifications are reported for all cycles 69 * @library /test/lib / 70 * @requires vm.gc.Shenandoah 71 * 72 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 73 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=static 74 * -Dprecise=false 75 * TestChurnNotifications 76 */ 77 78 /* 79 * @test id=compact 80 * @summary Check that MX notifications are reported for all cycles 81 * @library /test/lib / 82 * @requires vm.gc.Shenandoah 83 * 84 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 85 * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=compact 86 * -Dprecise=false 87 * TestChurnNotifications 88 */ 89 90 /* 91 * @test id=iu 92 * @summary Check that MX notifications are reported for all cycles 93 * @library /test/lib / 94 * @requires vm.gc.Shenandoah 95 * 96 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 97 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGCHeuristics=aggressive 98 * -Dprecise=false 99 * TestChurnNotifications 100 * 101 * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions 102 * -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu 103 * -Dprecise=false 104 * TestChurnNotifications 105 */ 106 107 import java.util.*; 108 import java.util.concurrent.atomic.*; 109 import javax.management.*; 110 import java.lang.management.*; 111 import javax.management.openmbean.*; 112 113 import jdk.test.lib.Utils; 114 115 import com.sun.management.GarbageCollectionNotificationInfo; 116 117 public class TestChurnNotifications { 118 119 static final long HEAP_MB = 128; // adjust for test configuration above 120 static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation 121 122 // Should we track the churn precisely? 123 // Precise tracking is only reliable when GC is fully stop-the-world. Otherwise, 124 // we cannot tell, looking at heap used before/after, what was the GC churn. 125 static final boolean PRECISE = Boolean.getBoolean("precise"); 126 127 static final long M = 1024 * 1024; 128 129 static volatile Object sink; 130 131 public static void main(String[] args) throws Exception { 132 final long startTime = System.currentTimeMillis(); 133 134 final AtomicLong churnBytes = new AtomicLong(); 135 136 NotificationListener listener = new NotificationListener() { 137 @Override 138 public void handleNotification(Notification n, Object o) { 139 if (n.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 140 GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) n.getUserData()); 141 Map<String, MemoryUsage> mapBefore = info.getGcInfo().getMemoryUsageBeforeGc(); 142 Map<String, MemoryUsage> mapAfter = info.getGcInfo().getMemoryUsageAfterGc(); 143 144 MemoryUsage before = mapBefore.get("Shenandoah"); 145 MemoryUsage after = mapAfter.get("Shenandoah"); 146 147 if ((before != null) && (after != null)) { 148 long diff = before.getUsed() - after.getUsed(); 149 if (diff > 0) { 150 churnBytes.addAndGet(diff); 151 } 152 } 153 } 154 } 155 }; 156 157 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 158 ((NotificationEmitter) bean).addNotificationListener(listener, null, null); 159 } 160 161 final int size = 100_000; 162 long count = TARGET_MB * 1024 * 1024 / (16 + 4 * size); 163 164 long mem = count * (16 + 4 * size); 165 166 for (int c = 0; c < count; c++) { 167 sink = new int[size]; 168 } 169 170 System.gc(); 171 172 long minExpected = PRECISE ? (mem - HEAP_MB * 1024 * 1024) : 1; 173 long maxExpected = mem + HEAP_MB * 1024 * 1024; 174 long actual = 0; 175 176 // Look at test timeout to figure out how long we can wait without breaking into timeout. 177 // Default to 1/4 of the remaining time in 1s steps. 178 final long STEP_MS = 1000; 179 long spentTime = System.currentTimeMillis() - startTime; 180 long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - spentTime) / STEP_MS / 4; 181 182 // Wait until enough notifications are accrued to match minimum boundary. 183 long tries = 0; 184 while (tries++ < maxTries) { 185 actual = churnBytes.get(); 186 if (minExpected <= actual) { 187 // Wait some more to test if we are breaking the maximum boundary. 188 Thread.sleep(5000); 189 actual = churnBytes.get(); 190 break; 191 } 192 Thread.sleep(STEP_MS); 193 } 194 195 String msg = "Expected = [" + minExpected / M + "; " + maxExpected / M + "] (" + mem / M + "), actual = " + actual / M; 196 if (minExpected <= actual && actual <= maxExpected) { 197 System.out.println(msg); 198 } else { 199 throw new IllegalStateException(msg); 200 } 201 } 202 }