1 /* 2 * Copyright (c) 2016, 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 TestMaxMinHeapFreeRatioFlags 26 * @key gc 27 * @summary Verify that heap size changes according to max and min heap free ratios. 28 * @library /test/lib 29 * @modules java.base/jdk.internal.misc 30 * java.management 31 * @run driver/timeout=240 TestMaxMinHeapFreeRatioFlags 32 */ 33 34 import java.util.LinkedList; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import jdk.test.lib.process.OutputAnalyzer; 38 import jdk.test.lib.process.ProcessTools; 39 import jdk.test.lib.Utils; 40 import jdk.internal.misc.Unsafe; 41 42 public class TestMaxMinHeapFreeRatioFlags { 43 44 public static final long M = 1024 * 1024; 45 public static final long MAX_HEAP_SIZE = 200 * M; 46 public static final long HEAP_SIZE = 10 * M; 47 public static final long MAX_NEW_SIZE = 20 * M; 48 public static final long NEW_SIZE = 5 * M; 49 50 public static void main(String args[]) throws Exception { 51 LinkedList<String> options = new LinkedList<>( 52 Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*HeapFreeRatio","-XX:\\+ExplicitGCInvokesConcurrent")) 53 ); 54 55 negativeTest(20, false, 10, true, options); 56 negativeTest(100, true, 0, false, options); 57 negativeTest(101, false, 50, false, options); 58 negativeTest(49, true, 102, true, options); 59 negativeTest(-1, false, 50, false, options); 60 negativeTest(50, true, -1, true, options); 61 62 positiveTest(10, false, 90, false, true, options); 63 positiveTest(10, true, 80, false, true, options); 64 positiveTest(20, false, 70, true, true, options); 65 positiveTest(25, true, 65, true, true, options); 66 positiveTest(40, false, 50, false, true, options); 67 } 68 69 /** 70 * Verify that heap size will be changed to conform 71 * min and max heap free ratios. 72 * 73 * @param minRatio value of MinHeapFreeRatio option 74 * @param useXminf used Xminf option instead of MinHeapFreeRatio 75 * @param maxRatio value of MaxHeapFreeRatio option 76 * @param useXmaxf used Xmaxf option instead of MaxHeapFreeRatio 77 * @param options additional options for JVM 78 */ 79 public static void positiveTest(int minRatio, boolean useXminf, 80 int maxRatio, boolean useXmaxf, boolean shrinkHeapInSteps, 81 LinkedList<String> options) throws Exception { 82 83 LinkedList<String> vmOptions = new LinkedList<>(options); 84 Collections.addAll(vmOptions, 85 (useXminf ? "-Xminf" + minRatio / 100.0 : "-XX:MinHeapFreeRatio=" + minRatio), 86 (useXmaxf ? "-Xmaxf" + maxRatio / 100.0 : "-XX:MaxHeapFreeRatio=" + maxRatio), 87 "-Xmx" + MAX_HEAP_SIZE, 88 "-Xms" + HEAP_SIZE, 89 "-XaddExports:java.base/jdk.internal.misc=ALL-UNNAMED", 90 "-XX:NewSize=" + NEW_SIZE, 91 "-XX:MaxNewSize=" + MAX_NEW_SIZE, 92 "-XX:" + (shrinkHeapInSteps ? '+' : '-') + "ShrinkHeapInSteps", 93 RatioVerifier.class.getName(), 94 Integer.toString(minRatio), 95 Integer.toString(maxRatio), 96 Boolean.toString(shrinkHeapInSteps) 97 ); 98 99 ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()])); 100 OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); 101 analyzer.shouldHaveExitValue(0); 102 } 103 104 /** 105 * Verify that VM will fail to start with specified ratios. 106 * 107 * @param minRatio value of MinHeapFreeRatio option 108 * @param useXminf used Xminf option instead of MinHeapFreeRatio 109 * @param maxRatio value of MaxHeapFreeRatio option 110 * @param useXmaxf used Xmaxf option instead of MaxHeapFreeRatio 111 * @param options additional options for JVM 112 */ 113 public static void negativeTest(int minRatio, boolean useXminf, 114 int maxRatio, boolean useXmaxf, 115 LinkedList<String> options) throws Exception { 116 117 LinkedList<String> vmOptions = new LinkedList<>(options); 118 Collections.addAll(vmOptions, 119 (useXminf ? "-Xminf" + minRatio / 100.0 : "-XX:MinHeapFreeRatio=" + minRatio), 120 (useXmaxf ? "-Xmaxf" + maxRatio / 100.0 : "-XX:MaxHeapFreeRatio=" + maxRatio), 121 "-XaddExports:java.base/jdk.internal.misc=ALL-UNNAMED", 122 "-version" 123 ); 124 ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()])); 125 OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); 126 analyzer.shouldHaveExitValue(1); 127 analyzer.shouldContain("Error: Could not create the Java Virtual Machine."); 128 } 129 130 /** 131 * RatioVerifier will be executed in the tested VM. 132 * It will check that real heap usage after collection lies between MinHeapFreeRatio and MaxHeapFreeRatio. 133 */ 134 public static class RatioVerifier { 135 136 private static final Unsafe unsafe = Utils.getUnsafe(); 137 138 // Size of byte array that will be allocated 139 public static final int CHUNK_SIZE = 1024; 140 // Length of byte array, that will be added to "garbage" list. 141 public static final int ARRAY_LENGTH = CHUNK_SIZE - Unsafe.ARRAY_BYTE_BASE_OFFSET; 142 // Amount of tries to force heap shrinking/expansion using GC 143 public static final int GC_TRIES = 10; 144 145 // Value that will be added/substracted from expected min/max heap free ratio 146 // during memory allocation to make sure that specified limit will be exceeded. 147 public static final double OVERLOAD = 0.05; 148 // Acceptable heap free ratio limit exceedance: verification will fail if 149 // actual ratio is lower than expected min heap free ratio - VARIANCE or 150 // higher than expected max heap free ratio + VARIANCE. 151 public static final double VARIANCE = 0.025; 152 153 public static LinkedList<Object> garbage = new LinkedList<>(); 154 155 public static void main(String args[]) throws Exception { 156 if (args.length != 3) { 157 throw new IllegalArgumentException("Expected 3 args: <minRatio> <maxRatio> <shrinkHeapInSteps>"); 158 } 159 if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.PSOld) { 160 System.out.println("Test is not applicable to parallel GC"); 161 return; 162 } 163 164 double minRatio = Integer.valueOf(args[0]) / 100.0; 165 double maxRatio = Integer.valueOf(args[1]) / 100.0; 166 boolean shrinkHeapInSteps = Boolean.valueOf(args[2]); 167 168 long maxHeapSize = getMax(); 169 int gcTries = (shrinkHeapInSteps ? GC_TRIES : 1); 170 171 // Initial checks. This also links up everything in these helper methods, 172 // in case it brings more garbage. 173 forceGC(gcTries); 174 verifyRatio(minRatio, maxRatio); 175 176 // commit 0.5 of total heap size to have enough space 177 // to both shink and expand 178 while (getCommitted() < maxHeapSize / 2) { 179 garbage.add(new byte[ARRAY_LENGTH]); 180 } 181 182 forceGC(gcTries); 183 // Verify that current heap free ratio lies between specified limits 184 verifyRatio(minRatio, maxRatio); 185 186 // Estimate how much memory we have to allocate to force expansion 187 long memoryToFill = (long) (getCommitted() * (1 - minRatio + OVERLOAD)) 188 - getUsed(); 189 190 long previouslyCommitted = getCommitted(); 191 192 while (memoryToFill > 0) { 193 garbage.add(new byte[CHUNK_SIZE]); 194 memoryToFill -= CHUNK_SIZE; 195 } 196 197 forceGC(gcTries); 198 // Verify that after memory allocation heap free ratio is still conforming specified limits 199 verifyRatio(minRatio, maxRatio); 200 // Verify that heap was actually expanded 201 if (previouslyCommitted >= getCommitted()) { 202 throw new RuntimeException("Heap was not expanded."); 203 } 204 205 // Estimate how much memory we have to free to force shrinking 206 long memoryToFree = getUsed() 207 - (long) (getCommitted() * (1 - maxRatio - OVERLOAD)); 208 209 previouslyCommitted = getCommitted(); 210 211 while (memoryToFree > 0 && garbage.size() > 0) { 212 garbage.remove(garbage.size() - 1); 213 memoryToFree -= CHUNK_SIZE; 214 } 215 216 forceGC(gcTries); 217 // Verify that heap free ratio is still conforming specified limits 218 verifyRatio(minRatio, maxRatio); 219 // Verify that heap was actually shrinked 220 if (previouslyCommitted <= getCommitted()) { 221 throw new RuntimeException("Heap was not shrinked."); 222 } 223 } 224 225 public static void forceGC(int gcTries) { 226 for (int i = 0; i < gcTries; i++) { 227 System.gc(); 228 try { 229 Thread.sleep(10); 230 } catch (InterruptedException ie) { 231 } 232 } 233 } 234 235 /** 236 * Verify that heap free ratio is conforming specified limits. 237 * Actual heap free ratio may be very close to one of specified limits, 238 * but exceed for more then VARIANCE. 239 * Verification will also pass if actual ratio is not conforming limits, 240 * but it is not possible to shrink/expand heap. 241 */ 242 public static void verifyRatio(double minRatio, double maxRatio) { 243 double ratio = getHeapFreeRatio(); 244 System.out.println(minRatio + " " + ratio + " " + maxRatio); 245 if (minRatio - ratio > VARIANCE 246 && getCommitted() < getMax()) { 247 throw new RuntimeException("Current heap free ratio is lower than " 248 + "MinHeapFreeRatio (" + ratio + " vs " + minRatio + ")."); 249 } 250 if (ratio - maxRatio > VARIANCE 251 && getUsed() > getInit()) { 252 throw new RuntimeException("Current heap free ratio is higher than " 253 + "MaxHeapFreeRatio (" + ratio + " vs " + maxRatio + ")."); 254 } 255 } 256 257 /* 258 * Obtain information about heap size. 259 * 260 * For G1 information summed up for all type of regions, 261 * because tested options affect overall heap sizing. 262 * 263 * For all other GCs return information only for old gen. 264 */ 265 public static long getMax() { 266 return HeapRegionUsageTool.getOldUsage().getMax(); 267 } 268 269 public static long getInit() { 270 if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) { 271 return HeapRegionUsageTool.getEdenUsage().getInit() 272 + HeapRegionUsageTool.getSurvivorUsage().getInit() 273 + HeapRegionUsageTool.getOldUsage().getInit(); 274 } else { 275 return HeapRegionUsageTool.getOldUsage().getInit(); 276 } 277 } 278 279 public static long getUsed() { 280 if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) { 281 return HeapRegionUsageTool.getEdenUsage().getUsed() 282 + HeapRegionUsageTool.getSurvivorUsage().getUsed() 283 + HeapRegionUsageTool.getOldUsage().getUsed(); 284 } else { 285 return HeapRegionUsageTool.getOldUsage().getUsed(); 286 } 287 } 288 289 public static long getCommitted() { 290 if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) { 291 return HeapRegionUsageTool.getEdenUsage().getCommitted() 292 + HeapRegionUsageTool.getSurvivorUsage().getCommitted() 293 + HeapRegionUsageTool.getOldUsage().getCommitted(); 294 } else { 295 return HeapRegionUsageTool.getOldUsage().getCommitted(); 296 } 297 } 298 299 public static long getFree() { 300 return getCommitted() - getUsed(); 301 } 302 303 public static double getHeapFreeRatio() { 304 return getFree() / (double) getCommitted(); 305 } 306 } 307 }