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 & vm.opt.ShenandoahGCMode != "generational" 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 & vm.opt.ShenandoahGCMode != "generational" 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 & vm.opt.ShenandoahGCMode != "generational" 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 & vm.opt.ShenandoahGCMode != "generational" 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 & vm.opt.ShenandoahGCMode != "generational" 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=generational 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=generational 99 * -Dprecise=false -Dmem.pool=Young 100 * TestChurnNotifications 101 */ 102 103 import java.util.*; 104 import java.util.concurrent.atomic.*; 105 import javax.management.*; 106 import java.lang.management.*; 107 import javax.management.openmbean.*; 108 109 import jdk.test.lib.Utils; 110 111 import com.sun.management.GarbageCollectionNotificationInfo; 112 113 public class TestChurnNotifications { 114 115 static final long HEAP_MB = 128; // adjust for test configuration above 116 static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation 117 118 // Should we track the churn precisely? 119 // Precise tracking is only reliable when GC is fully stop-the-world. Otherwise, 120 // we cannot tell, looking at heap used before/after, what was the GC churn. 121 static final boolean PRECISE = Boolean.getBoolean("precise"); 122 123 static final long M = 1024 * 1024; 124 125 static volatile Object sink; 126 127 private static final String POOL_NAME = "Young".equals(System.getProperty("mem.pool")) ? "Shenandoah Young Gen" : "Shenandoah"; 128 129 public static void main(String[] args) throws Exception { 130 final long startTimeNanos = System.nanoTime(); 131 132 final AtomicLong churnBytes = new AtomicLong(); 133 134 NotificationListener listener = new NotificationListener() { 135 @Override 136 public void handleNotification(Notification n, Object o) { 137 if (n.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 138 GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) n.getUserData()); 139 Map<String, MemoryUsage> mapBefore = info.getGcInfo().getMemoryUsageBeforeGc(); 140 Map<String, MemoryUsage> mapAfter = info.getGcInfo().getMemoryUsageAfterGc(); 141 142 MemoryUsage before = mapBefore.get(POOL_NAME); 143 MemoryUsage after = mapAfter.get(POOL_NAME); 144 145 if ((before != null) && (after != null)) { 146 long diff = before.getUsed() - after.getUsed(); 147 if (diff > 0) { 148 churnBytes.addAndGet(diff); 149 } 150 } 151 } 152 } 153 }; 154 155 for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { 156 ((NotificationEmitter) bean).addNotificationListener(listener, null, null); 157 } 158 159 final int size = 100_000; 160 long count = TARGET_MB * 1024 * 1024 / (16 + 4 * size); 161 162 long mem = count * (16 + 4 * size); 163 164 for (int c = 0; c < count; c++) { 165 sink = new int[size]; 166 } 167 168 System.gc(); 169 170 long minExpected = PRECISE ? (mem - HEAP_MB * 1024 * 1024) : 1; 171 long maxExpected = mem + HEAP_MB * 1024 * 1024; 172 long actual = 0; 173 174 // Look at test timeout to figure out how long we can wait without breaking into timeout. 175 // Default to 1/4 of the remaining time in 1s steps. 176 final long STEP_MS = 1000; 177 long spentTimeNanos = System.nanoTime() - startTimeNanos; 178 long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - (spentTimeNanos / 1_000_000L)) / STEP_MS / 4; 179 180 // Wait until enough notifications are accrued to match minimum boundary. 181 long tries = 0; 182 while (tries++ < maxTries) { 183 actual = churnBytes.get(); 184 if (minExpected <= actual) { 185 // Wait some more to test if we are breaking the maximum boundary. 186 Thread.sleep(5000); 187 actual = churnBytes.get(); 188 break; 189 } 190 Thread.sleep(STEP_MS); 191 } 192 193 String msg = "Expected = [" + minExpected / M + "; " + maxExpected / M + "] (" + mem / M + "), actual = " + actual / M; 194 if (minExpected <= actual && actual <= maxExpected) { 195 System.out.println(msg); 196 } else { 197 throw new IllegalStateException(msg); 198 } 199 } 200 }