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