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