1 /* 2 * Copyright (c) 2018, 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 TestOldGenCollectionUsage.java 26 * @bug 8195115 27 * @summary G1 Old Gen's CollectionUsage.used is zero after mixed GC which is incorrect 28 * @key gc 29 * @requires vm.gc.G1 30 * @requires vm.opt.MaxGCPauseMillis == "null" 31 * @library /test/lib 32 * @modules java.base/jdk.internal.misc 33 * @modules java.management 34 * @build sun.hotspot.WhiteBox 35 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 36 * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:-G1UseLegacyMonitoring -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -verbose:gc -XX:SurvivorRatio=1 -Xmx12m -Xms12m -XX:MaxTenuringThreshold=1 -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 TestOldGenCollectionUsage 37 * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+G1UseLegacyMonitoring -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -verbose:gc -XX:SurvivorRatio=1 -Xmx12m -Xms12m -XX:MaxTenuringThreshold=1 -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 TestOldGenCollectionUsage 38 */ 39 40 import jdk.test.lib.Asserts; 41 import sun.hotspot.WhiteBox; 42 43 import java.util.ArrayList; 44 import java.util.List; 45 import java.util.Collections; 46 47 import java.lang.management.*; 48 49 // 8195115 says that for the "G1 Old Gen" MemoryPool, CollectionUsage.used 50 // is zero for G1 after a mixed collection, which is incorrect. 51 52 public class TestOldGenCollectionUsage { 53 54 private String poolName; 55 private String youngCollectorName; 56 private String mixedCollectorName; 57 private boolean useLegacyMonitoring; 58 59 public static void main(String [] args) throws Exception { 60 TestOldGenCollectionUsage t = new TestOldGenCollectionUsage(); 61 t.run(); 62 } 63 64 public TestOldGenCollectionUsage() { 65 useLegacyMonitoring = LegacyMonitoring.use(); 66 poolName = useLegacyMonitoring ? "G1 Old Gen" : "G1 Old Space"; 67 youngCollectorName = useLegacyMonitoring ? "G1 Young Generation" : "G1 Young"; 68 mixedCollectorName = useLegacyMonitoring ? "G1 Young Generation" : "G1 Mixed"; 69 System.out.println("Monitor G1 Old Gen pool with " + mixedCollectorName + " collector."); 70 } 71 72 public static class LegacyMonitoring { 73 private static final boolean useLegacyMonitoring = getUseLegacyMonitoring(); 74 private static boolean getUseLegacyMonitoring() { 75 return ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-XX:+G1UseLegacyMonitoring"); 76 } 77 public static boolean use() { return useLegacyMonitoring; } 78 } 79 80 public void run() { 81 // Find old space memory pool and collectors 82 List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); 83 MemoryPoolMXBean pool = null; 84 boolean foundPool = false; 85 for (int i = 0; i < pools.size(); i++) { 86 pool = pools.get(i); 87 String name = pool.getName(); 88 if (name.contains(poolName)) { 89 System.out.println("Found pool: " + name); 90 foundPool = true; 91 break; 92 } 93 } 94 if (!foundPool) { 95 throw new RuntimeException(poolName + " not found, test with -XX:+UseG1GC"); 96 } 97 98 List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans(); 99 GarbageCollectorMXBean youngCollector = null; 100 GarbageCollectorMXBean mixedCollector = null; 101 for (int i = 0; i < collectors.size(); i++) { 102 GarbageCollectorMXBean collector = collectors.get(i); 103 String name = collector.getName(); 104 if (name.equals(youngCollectorName)) { 105 System.out.println("Found young collector: " + name); 106 youngCollector = collector; 107 } 108 if (name.equals(mixedCollectorName)) { 109 System.out.println("Found mixed collector: " + name); 110 mixedCollector = collector; 111 } 112 } 113 if (youngCollector == null) { 114 throw new RuntimeException(youngCollectorName + " not found, test with -XX:+UseG1GC"); 115 } 116 if (mixedCollector == null) { 117 throw new RuntimeException(mixedCollectorName + " not found, test with -XX:+UseG1GC"); 118 } 119 120 MixedGCProvoker gcProvoker = new MixedGCProvoker(); 121 gcProvoker.allocateOldObjects(); 122 123 // Verify no non-zero result was stored for the pool 124 long usage = pool.getCollectionUsage().getUsed(); 125 System.out.println(poolName + ": usage after GC = " + usage); 126 if (usage > 0) { 127 throw new RuntimeException("Premature mixed collections(s)"); 128 } 129 130 // Verify that young collections were done 131 long youngCollectionCount = youngCollector.getCollectionCount(); 132 System.out.println(youngCollectorName + ": collection count = " 133 + youngCollectionCount); 134 long youngCollectionTime = youngCollector.getCollectionTime(); 135 System.out.println(youngCollectorName + ": collection time = " 136 + youngCollectionTime); 137 if (youngCollectionCount <= 0) { 138 throw new RuntimeException("Young collection count <= 0"); 139 } 140 if (youngCollectionTime <= 0) { 141 throw new RuntimeException("Young collector did not run"); 142 } 143 144 // Force promotion 145 gcProvoker.provokeMixedGC(); 146 147 usage = pool.getCollectionUsage().getUsed(); 148 System.out.println(poolName + ": usage after GC = " + usage); 149 if (usage <= 0) { 150 throw new RuntimeException(poolName + " found with zero usage"); 151 } 152 153 long newCollectionCount = mixedCollector.getCollectionCount(); 154 System.out.println(mixedCollectorName + ": collection count = " 155 + newCollectionCount); 156 long newCollectionTime = mixedCollector.getCollectionTime(); 157 System.out.println(mixedCollectorName + ": collection time = " 158 + newCollectionTime); 159 if (useLegacyMonitoring) { 160 if (newCollectionCount <= youngCollectionCount) { 161 throw new RuntimeException("No new collection"); 162 } 163 } else { 164 if (newCollectionCount <= 0) { 165 throw new RuntimeException("Mixed collection count <= 0"); 166 } 167 if (newCollectionTime <= 0) { 168 throw new RuntimeException("Mixed collector did not run"); 169 } 170 } 171 172 System.out.println("Test passed."); 173 } 174 175 /** 176 * Utility class to guarantee a mixed GC. The class allocates several arrays and 177 * promotes them to the oldgen. After that it tries to provoke mixed GC by 178 * allocating new objects. 179 * 180 * The necessary condition for guaranteed mixed GC is running MixedGCProvoker is 181 * running in VM with the following flags: -XX:MaxTenuringThreshold=1 -Xms12M 182 * -Xmx12M -XX:G1MixedGCLiveThresholdPercent=100 -XX:G1HeapWastePercent=0 183 * -XX:G1HeapRegionSize=1m 184 */ 185 public class MixedGCProvoker { 186 private final WhiteBox WB = WhiteBox.getWhiteBox(); 187 private final List<byte[]> liveOldObjects = new ArrayList<>(); 188 private final List<byte[]> newObjects = new ArrayList<>(); 189 190 public static final int ALLOCATION_SIZE = 20000; 191 public static final int ALLOCATION_COUNT = 15; 192 193 public void allocateOldObjects() { 194 List<byte[]> deadOldObjects = new ArrayList<>(); 195 // Allocates buffer and promotes it to the old gen. Mix live and dead old 196 // objects 197 for (int i = 0; i < ALLOCATION_COUNT; ++i) { 198 liveOldObjects.add(new byte[ALLOCATION_SIZE * 5]); 199 deadOldObjects.add(new byte[ALLOCATION_SIZE * 5]); 200 } 201 202 // Do two young collections, MaxTenuringThreshold=1 will force promotion. 203 // G1HeapRegionSize=1m guarantees that old gen regions will be filled. 204 WB.youngGC(); 205 WB.youngGC(); 206 // Check it is promoted & keep alive 207 Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), 208 "List of the objects is suppose to be in OldGen"); 209 Asserts.assertTrue(WB.isObjectInOldGen(deadOldObjects), 210 "List of the objects is suppose to be in OldGen"); 211 } 212 213 /** 214 * Waits until Concurent Mark Cycle finishes 215 * @param wb Whitebox instance 216 * @param sleepTime sleep time 217 */ 218 private void waitTillCMCFinished(int sleepTime) { 219 while (WB.g1InConcurrentMark()) { 220 if (sleepTime > -1) { 221 try { 222 Thread.sleep(sleepTime); 223 } catch (InterruptedException e) { 224 System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish"); 225 } 226 } 227 } 228 } 229 230 public void provokeMixedGC() { 231 waitTillCMCFinished(0); 232 WB.g1StartConcMarkCycle(); 233 waitTillCMCFinished(0); 234 WB.youngGC(); 235 236 System.out.println("Allocating new objects to provoke mixed GC"); 237 // Provoke a mixed collection. G1MixedGCLiveThresholdPercent=100 238 // guarantees that full old gen regions will be included. 239 for (int i = 0; i < (ALLOCATION_COUNT * 20); i++) { 240 try { 241 newObjects.add(new byte[ALLOCATION_SIZE]); 242 } catch (OutOfMemoryError e) { 243 newObjects.clear(); 244 WB.youngGC(); 245 WB.youngGC(); 246 System.out.println("OutOfMemoryError is reported, stop allocating new objects"); 247 break; 248 } 249 } 250 // check that liveOldObjects still alive 251 Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), 252 "List of the objects is suppose to be in OldGen"); 253 } 254 255 } 256 257 }