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