1 /* 2 * Copyright (c) 2015, 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 TestNewSizeFlags 26 * @key gc 27 * @bug 8025166 28 * @summary Verify that young gen size conforms values specified by NewSize, MaxNewSize and Xmn options 29 * @library /testlibrary /test/lib 30 * @modules java.base/jdk.internal.misc 31 * java.management 32 * @build TestNewSizeFlags 33 * @run main ClassFileInstaller sun.hotspot.WhiteBox 34 * @run driver/timeout=240 TestNewSizeFlags 35 */ 36 37 import jdk.test.lib.AllocationHelper; 38 import java.io.IOException; 39 import java.lang.management.MemoryUsage; 40 import java.util.Arrays; 41 import java.util.Collections; 42 import java.util.LinkedList; 43 import jdk.test.lib.HeapRegionUsageTool; 44 import jdk.test.lib.OutputAnalyzer; 45 import jdk.test.lib.ProcessTools; 46 import jdk.test.lib.Utils; 47 import sun.hotspot.WhiteBox; 48 49 public class TestNewSizeFlags { 50 51 public static final long M = 1024 * 1024; 52 53 public static void main(String args[]) throws Exception { 54 LinkedList<String> options = new LinkedList<>( 55 Arrays.asList(Utils.getFilteredTestJavaOpts("(-Xm[nsx][^ ]+)|" 56 + "(-XX:(Max)?((New)|" 57 + "(Heap))((Size)|" 58 + "(Ratio))=[^ ]+)")) 59 ); 60 61 // Test NewSize and MaxNewSize 62 testNewSizeFlags(20 * M, 10 * M, 30 * M, 40 * M, options, false); 63 testNewSizeFlags(10 * M, 20 * M, 30 * M, 80 * M, options, false); 64 testNewSizeFlags(-1, 20 * M, 30 * M, 40 * M, options, false); 65 testNewSizeFlags(10 * M, -1, 30 * M, 40 * M, options, false); 66 testNewSizeFlags(20 * M, 20 * M, 30 * M, 40 * M, options, false); 67 testNewSizeFlags(20 * M, 30 * M, 40 * M, 50 * M, options, false); 68 testNewSizeFlags(30 * M, 100 * M, 150 * M, 200 * M, options, false); 69 testNewSizeFlags(20 * M, 30 * M, 128 * M, 128 * M, options, false); 70 71 // Test -Xmn 72 testXmnFlags(0, 30 * M, 40 * M, options, true); 73 testXmnFlags(20 * M, 30 * M, 40 * M, options, false); 74 testXmnFlags(50 * M, 70 * M, 100 * M, options, false); 75 } 76 77 /** 78 * Verify that NewSize and MaxNewSize flags affect young gen size. 79 * 80 * @param newSize value of NewSize option, omitted if negative 81 * @param maxNewSize value of MaxNewSize option, omitted if negative 82 * @param heapSize value of HeapSize option 83 * @param maxHeapSize value of MaxHeapSize option 84 * @param options additional options for JVM 85 * @param failureExpected true if JVM should fail with passed heap size options 86 */ 87 public static void testNewSizeFlags(long newSize, long maxNewSize, 88 long heapSize, long maxHeapSize, 89 LinkedList<String> options, 90 boolean failureExpected) throws Exception { 91 long expectedNewSize = newSize; 92 long expectedMaxNewSize = (maxNewSize >= 0 ? Math.max(maxNewSize, newSize) : maxNewSize); 93 testVMOptions(newSize, maxNewSize, 94 heapSize, maxHeapSize, 95 expectedNewSize, expectedMaxNewSize, 96 options, failureExpected); 97 } 98 99 /** 100 * Verify that -Xmn flag affect young gen size. 101 * 102 * @param mnValue value of -Xmn option 103 * @param heapSize value of HeapSize option 104 * @param maxHeapSize value of MaxHeapSize option 105 * @param options additional options for JVM 106 * @param failureExpected true if JVM should fail with passed heap size options 107 */ 108 public static void testXmnFlags(long mnValue, 109 long heapSize, long maxHeapSize, 110 LinkedList<String> options, 111 boolean failureExpected) throws Exception { 112 LinkedList<String> newOptions = new LinkedList<>(options); 113 newOptions.add("-Xmn" + mnValue); 114 testVMOptions(-1, -1, 115 heapSize, maxHeapSize, 116 mnValue, mnValue, 117 newOptions, failureExpected); 118 } 119 120 /** 121 * Verify that NewSize and MaxNewSize flags affect young gen size. 122 * 123 * @param newSize value of NewSize option, omitted if negative 124 * @param maxNewSize value of MaxNewSize option, omitted if negative 125 * @param heapSize value of HeapSize option 126 * @param maxHeapSize value of MaxHeapSize option 127 * @param expectedNewSize expected initial young gen size 128 * @param expectedMaxNewSize expected max young gen size 129 * @param options additional options for JVM 130 * @param failureExpected true if JVM should fail with passed heap size options 131 */ 132 public static void testVMOptions(long newSize, long maxNewSize, 133 long heapSize, long maxHeapSize, 134 long expectedNewSize, long expectedMaxNewSize, 135 LinkedList<String> options, boolean failureExpected) throws Exception { 136 OutputAnalyzer analyzer = startVM(options, newSize, maxNewSize, heapSize, maxHeapSize, expectedNewSize, expectedMaxNewSize); 137 138 if (failureExpected) { 139 analyzer.shouldHaveExitValue(1); 140 analyzer.shouldMatch("(Error occurred during initialization of VM)|" 141 + "(Error: Could not create the Java Virtual Machine.)"); 142 } else { 143 analyzer.shouldHaveExitValue(0); 144 } 145 } 146 147 private static OutputAnalyzer startVM(LinkedList<String> options, 148 long newSize, long maxNewSize, 149 long heapSize, long maxHeapSize, 150 long expectedNewSize, long expectedMaxNewSize) throws Exception, IOException { 151 LinkedList<String> vmOptions = new LinkedList<>(options); 152 Collections.addAll(vmOptions, 153 "-Xbootclasspath/a:.", 154 "-XX:+UnlockDiagnosticVMOptions", 155 "-XX:+WhiteBoxAPI", 156 (newSize >= 0 ? "-XX:NewSize=" + newSize : ""), 157 (maxNewSize >= 0 ? "-XX:MaxNewSize=" + maxNewSize : ""), 158 "-Xmx" + maxHeapSize, 159 "-Xms" + heapSize, 160 "-XX:GCLockerEdenExpansionPercent=0", 161 "-XX:-UseLargePages", 162 NewSizeVerifier.class.getName(), 163 Long.toString(expectedNewSize), 164 Long.toString(expectedMaxNewSize), 165 Long.toString(heapSize), 166 Long.toString(maxHeapSize) 167 ); 168 vmOptions.removeIf(String::isEmpty); 169 ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()])); 170 OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); 171 return analyzer; 172 } 173 174 /** 175 * NewSizeVerifier checks that initial young gen size is equal to expected 176 * regardful to alignment and that young gen size will not be greater than 177 * expected max size. 178 * In order to verify that young gen size will not be greater then expected 179 * max size, NewSizeVerifier do some object allocation to force garbage 180 * collection and heap expansion. 181 */ 182 public static class NewSizeVerifier { 183 184 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 185 private static final GCTypes.YoungGCType YOUNG_GC_TYPE = GCTypes.YoungGCType.getYoungGCType(); 186 private static final long HEAP_SPACE_ALIGNMENT = WB.getHeapSpaceAlignment(); 187 private static final long HEAP_ALIGNMENT = WB.getHeapAlignment(); 188 private static final long PS_VIRTUAL_SPACE_ALIGNMENT = 189 (YOUNG_GC_TYPE == GCTypes.YoungGCType.PSNew) ? WB.psVirtualSpaceAlignment() : 0; 190 191 public static final int ARRAY_LENGTH = 100; 192 public static final int CHUNK_SIZE = 1024; 193 public static final int MAX_ITERATIONS = 10; 194 public static byte garbage[][] = new byte[ARRAY_LENGTH][]; 195 196 public static void main(String args[]) throws Exception { 197 if (args.length != 4) { 198 throw new IllegalArgumentException("Expected 4 args: <expectedNewSize> <expectedMaxNewSize> <initialHeapSize> <maxHeapSize>"); 199 } 200 final long newSize = Long.valueOf(args[0]); 201 final long maxNewSize = Long.valueOf(args[1]); 202 final long initialHeapSize = Long.valueOf(args[2]); 203 final long maxHeapSize = Long.valueOf(args[3]); 204 205 // verify initial size 206 verifyNewSize(newSize, maxNewSize, initialHeapSize, maxHeapSize); 207 208 // force GC and verify that size is still correct 209 AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE, () -> (verifyNewSize(newSize, maxNewSize, initialHeapSize, maxHeapSize))); 210 allocator.allocateMemoryAndVerifyNoOOME(); 211 } 212 213 /** 214 * Verify that actual young gen size conforms NewSize and MaxNewSize values. 215 */ 216 public static Void verifyNewSize(long newSize, long maxNewSize, 217 long initialHeapSize, long maxHeapSize) { 218 long alignedNewSize = alignGenSize(newSize); 219 long alignedMaxNewSize = alignGenSize(maxNewSize); 220 long alignedXms = alignHeapSize(initialHeapSize); 221 long alignedXmx = alignHeapSize(maxHeapSize); 222 223 MemoryUsage youngGenUsage = getYoungGenUsage(); 224 long initSize = youngGenUsage.getInit(); 225 long commitedSize = youngGenUsage.getCommitted(); 226 long maxSize = youngGenUsage.getMax(); 227 228 if (newSize != -1) { 229 if (initSize < alignedNewSize) { 230 throw new RuntimeException("initial new size < NewSize value: " 231 + initSize + " < " + alignedNewSize); 232 } 233 234 if (commitedSize < alignedNewSize) { 235 throw new RuntimeException("actual new size < NewSize value: " 236 + commitedSize + " < " + alignedNewSize); 237 } 238 239 // for G1 max new size == committed new size 240 if (YOUNG_GC_TYPE != GCTypes.YoungGCType.G1 241 && maxSize < alignedNewSize) { 242 throw new RuntimeException("max new size < NewSize value: " 243 + maxSize + " < " + alignedNewSize); 244 } 245 } 246 247 if (maxNewSize != -1) { 248 if (initSize > alignedMaxNewSize) { 249 throw new RuntimeException("initial new size > MaxNewSize value: " 250 + initSize + " > " + alignedMaxNewSize); 251 } 252 253 if (commitedSize > alignedMaxNewSize) { 254 throw new RuntimeException("actual new size > MaxNewSize value: " 255 + commitedSize + " > " + alignedMaxNewSize); 256 } 257 258 if (alignedXms != alignedXmx) { 259 if (YOUNG_GC_TYPE != GCTypes.YoungGCType.G1 260 && maxSize != alignedMaxNewSize) { 261 throw new RuntimeException("max new size != MaxNewSize value: " 262 + maxSize + " != " + alignedMaxNewSize); 263 } 264 } else { 265 if (YOUNG_GC_TYPE != GCTypes.YoungGCType.G1 266 && maxSize != alignedNewSize) { 267 throw new RuntimeException("max new size != NewSize for case InitialHeapSize == MaxHeapSize value: " 268 + maxSize + " != " + alignedNewSize + " HeapSize == " + alignedXms); 269 } 270 } 271 } 272 return null; 273 } 274 275 /** 276 * Get young gen memory usage. 277 * 278 * For G1 it is EdenUsage + SurvivorUsage, 279 * for other GCs it is EdenUsage + 2 * SurvivorUsage. 280 * For G1 max value is just LONG_MAX. 281 * For all GCs used value is 0. 282 */ 283 private static MemoryUsage getYoungGenUsage() { 284 MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage(); 285 MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage(); 286 long edenUsageInit = edenUsage.getInit(); 287 long edenUsageCommited = edenUsage.getCommitted(); 288 long survivorUsageInit = survivorUsage.getInit(); 289 long survivorUsageCommited = survivorUsage.getCommitted(); 290 291 if (YOUNG_GC_TYPE == GCTypes.YoungGCType.G1) { 292 return new MemoryUsage(edenUsageInit + survivorUsageInit, 0, 293 edenUsageCommited + survivorUsageCommited, Long.MAX_VALUE); 294 } else { 295 return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0, 296 edenUsageCommited + survivorUsageCommited * 2, 297 edenUsage.getMax() + survivorUsage.getMax() * 2); 298 } 299 } 300 301 /** 302 * Align generation size regardful to used young GC. 303 */ 304 public static long alignGenSize(long value) { 305 switch (YOUNG_GC_TYPE) { 306 case DefNew: 307 case ParNew: 308 return HeapRegionUsageTool.alignDown(value, HEAP_SPACE_ALIGNMENT); 309 case PSNew: 310 return HeapRegionUsageTool.alignUp(HeapRegionUsageTool.alignDown(value, 311 HEAP_SPACE_ALIGNMENT), 312 PS_VIRTUAL_SPACE_ALIGNMENT); 313 case G1: 314 return HeapRegionUsageTool.alignUp(value, WB.g1RegionSize()); 315 default: 316 throw new RuntimeException("Unexpected young GC type"); 317 } 318 } 319 320 /** 321 * Align heap size. 322 */ 323 public static long alignHeapSize(long value){ 324 return HeapRegionUsageTool.alignUp(value,HEAP_ALIGNMENT); 325 } 326 } 327 }