1 /* 2 * Copyright (c) 2020, Oracle and/or its affiliates. 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 * @test TestGarbageCollectorMXBean 26 * @requires vm.gc.Z & !vm.graal.enabled 27 * @summary Test ZGC garbage collector MXBean 28 * @modules java.management 29 * @run main/othervm -XX:+UseZGC -Xms256M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 256 512 30 * @run main/othervm -XX:+UseZGC -Xms512M -Xmx512M -Xlog:gc TestGarbageCollectorMXBean 512 512 31 */ 32 33 import java.lang.management.ManagementFactory; 34 import java.util.concurrent.atomic.AtomicInteger; 35 import java.util.concurrent.atomic.AtomicLong; 36 import javax.management.Notification; 37 import javax.management.NotificationEmitter; 38 import javax.management.NotificationListener; 39 import javax.management.openmbean.CompositeData; 40 41 import com.sun.management.GarbageCollectionNotificationInfo; 42 43 public class TestGarbageCollectorMXBean { 44 private static final long startTime = System.nanoTime(); 45 46 private static void log(String msg) { 47 final String elapsedSeconds = String.format("%.3fs", (System.nanoTime() - startTime) / 1_000_000_000.0); 48 System.out.println("[" + elapsedSeconds + "] (" + Thread.currentThread().getName() + ") " + msg); 49 } 50 51 public static void main(String[] args) throws Exception { 52 final long M = 1024 * 1024; 53 final long initialCapacity = Long.parseLong(args[0]) * M; 54 final long maxCapacity = Long.parseLong(args[1]) * M; 55 final AtomicInteger cycles = new AtomicInteger(); 56 final AtomicInteger errors = new AtomicInteger(); 57 58 final NotificationListener listener = (Notification notification, Object ignored) -> { 59 final var type = notification.getType(); 60 if (!type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 61 // Ignore 62 return; 63 } 64 65 final var data = (CompositeData)notification.getUserData(); 66 final var info = GarbageCollectionNotificationInfo.from(data); 67 final var name = info.getGcName(); 68 final var id = info.getGcInfo().getId(); 69 final var action = info.getGcAction(); 70 final var cause = info.getGcCause(); 71 final var startTime = info.getGcInfo().getStartTime(); 72 final var endTime = info.getGcInfo().getEndTime(); 73 final var duration = info.getGcInfo().getDuration(); 74 final var memoryUsageBeforeGC = info.getGcInfo().getMemoryUsageBeforeGc().get("ZHeap"); 75 final var memoryUsageAfterGC = info.getGcInfo().getMemoryUsageAfterGc().get("ZHeap"); 76 77 log(name + " (" + type + ")"); 78 log(" Id: " + id); 79 log(" Action: " + action); 80 log(" Cause: " + cause); 81 log(" StartTime: " + startTime); 82 log(" EndTime: " + endTime); 83 log(" Duration: " + duration); 84 log(" MemoryUsageBeforeGC: " + memoryUsageBeforeGC); 85 log(" MemoryUsageAfterGC: " + memoryUsageAfterGC); 86 log(""); 87 88 if (name.equals("ZGC")) { 89 cycles.incrementAndGet(); 90 } else { 91 log("ERROR: Name"); 92 errors.incrementAndGet(); 93 } 94 95 if (!action.equals("end of major GC")) { 96 log("ERROR: Action"); 97 errors.incrementAndGet(); 98 } 99 100 if (memoryUsageBeforeGC.getInit() != initialCapacity) { 101 log("ERROR: MemoryUsageBeforeGC.init"); 102 errors.incrementAndGet(); 103 } 104 105 if (memoryUsageBeforeGC.getUsed() > initialCapacity) { 106 log("ERROR: MemoryUsageBeforeGC.used"); 107 errors.incrementAndGet(); 108 } 109 110 if (memoryUsageBeforeGC.getCommitted() != initialCapacity) { 111 log("ERROR: MemoryUsageBeforeGC.committed"); 112 errors.incrementAndGet(); 113 } 114 115 if (memoryUsageBeforeGC.getMax() != maxCapacity) { 116 log("ERROR: MemoryUsageBeforeGC.max"); 117 errors.incrementAndGet(); 118 } 119 120 if (!cause.equals("System.gc()")) { 121 log("ERROR: Cause"); 122 errors.incrementAndGet(); 123 } 124 125 if (startTime > endTime) { 126 log("ERROR: StartTime"); 127 errors.incrementAndGet(); 128 } 129 130 if (endTime - startTime != duration) { 131 log("ERROR: Duration"); 132 errors.incrementAndGet(); 133 } 134 }; 135 136 // Collect garbage created at startup 137 System.gc(); 138 139 // Register GC event listener 140 for (final var collector : ManagementFactory.getGarbageCollectorMXBeans()) { 141 final NotificationEmitter emitter = (NotificationEmitter)collector; 142 emitter.addNotificationListener(listener, null, null); 143 } 144 145 final int minCycles = 5; 146 147 // Run GCs 148 for (int i = 0; i < minCycles; i++) { 149 log("Starting GC " + i); 150 System.gc(); 151 } 152 153 // Wait at most 90 seconds 154 for (int i = 0; i < 90; i++) { 155 log("Waiting..."); 156 Thread.sleep(1000); 157 158 if (cycles.get() >= minCycles) { 159 log("All events received!"); 160 break; 161 } 162 } 163 164 final int actualCycles = cycles.get(); 165 final int actualErrors = errors.get(); 166 167 log(" minCycles: " + minCycles); 168 log("actualCycles: " + actualCycles); 169 log("actualErrors: " + actualErrors); 170 171 // Verify number of cycle events 172 if (actualCycles < minCycles) { 173 throw new Exception("Unexpected cycles"); 174 } 175 176 // Verify number of errors 177 if (actualErrors != 0) { 178 throw new Exception("Unexpected errors"); 179 } 180 } 181 }