TestNewSizeFlags.java revision 11833:1cbffa2beba6
1136644Sache/*
2136644Sache * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
321308Sache * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
421308Sache *
521308Sache * This code is free software; you can redistribute it and/or modify it
621308Sache * under the terms of the GNU General Public License version 2 only, as
721308Sache * published by the Free Software Foundation.
821308Sache *
958310Sache * This code is distributed in the hope that it will be useful, but WITHOUT
1021308Sache * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1121308Sache * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1221308Sache * version 2 for more details (a copy is included in the LICENSE file that
1321308Sache * accompanied this code).
1421308Sache *
1521308Sache * You should have received a copy of the GNU General Public License version
1621308Sache * 2 along with this work; if not, write to the Free Software Foundation,
1721308Sache * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1821308Sache *
1921308Sache * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2058310Sache * or visit www.oracle.com if you need additional information or have any
2121308Sache * questions.
2221308Sache */
2321308Sache
2421308Sache/*
2547558Sache * @test TestNewSizeFlags
2647558Sache * @key gc
2747558Sache * @bug 8025166
2847558Sache * @summary Verify that young gen size conforms values specified by NewSize, MaxNewSize and Xmn options
29136644Sache * @library /test/lib
30136644Sache * @modules java.base/jdk.internal.misc
3147558Sache *          java.management
3247558Sache * @build sun.hotspot.WhiteBox
3375406Sache * @run main ClassFileInstaller sun.hotspot.WhiteBox
3447558Sache * @run driver/timeout=240  TestNewSizeFlags
3547558Sache */
3675406Sache
3747558Sacheimport java.io.IOException;
3847558Sacheimport java.lang.management.MemoryUsage;
3947558Sacheimport java.util.Arrays;
4047558Sacheimport java.util.Collections;
4147558Sacheimport java.util.LinkedList;
4247558Sacheimport jdk.test.lib.process.OutputAnalyzer;
4347558Sacheimport jdk.test.lib.process.ProcessTools;
4447558Sacheimport jdk.test.lib.Utils;
4521308Sacheimport sun.hotspot.WhiteBox;
4621308Sache
4721308Sachepublic class TestNewSizeFlags {
48136644Sache
4947558Sache    public static final long M = 1024 * 1024;
5021308Sache
5121308Sache    public static void main(String args[]) throws Exception {
52136644Sache        LinkedList<String> options = new LinkedList<>(
53136644Sache                Arrays.asList(Utils.getFilteredTestJavaOpts("(-Xm[nsx][^ ]+)|"
54136644Sache                                + "(-XX:(Max)?((New)|"
5521308Sache                                + "(Heap))((Size)|"
5621308Sache                                + "(Ratio))=[^ ]+)"))
5721308Sache        );
5821308Sache
5921308Sache        // Test NewSize and MaxNewSize
6021308Sache        testNewSizeFlags(20 * M, 10 * M, 30 * M, 40 * M, options, false);
6121308Sache        testNewSizeFlags(10 * M, 20 * M, 30 * M, 80 * M, options, false);
6221308Sache        testNewSizeFlags(-1, 20 * M, 30 * M, 40 * M, options, false);
6321308Sache        testNewSizeFlags(10 * M, -1, 30 * M, 40 * M, options, false);
6421308Sache        testNewSizeFlags(20 * M, 20 * M, 30 * M, 40 * M, options, false);
6521308Sache        testNewSizeFlags(20 * M, 30 * M, 40 * M, 50 * M, options, false);
6621308Sache        testNewSizeFlags(30 * M, 100 * M, 150 * M, 200 * M, options, false);
6721308Sache        testNewSizeFlags(20 * M, 30 * M, 128 * M, 128 * M, options, false);
6821308Sache
6921308Sache        // Test -Xmn
7021308Sache        testXmnFlags(0, 30 * M, 40 * M, options, true);
71119610Sache        testXmnFlags(20 * M, 30 * M, 40 * M, options, false);
7221308Sache        testXmnFlags(50 * M, 70 * M, 100 * M, options, false);
7321308Sache    }
74119610Sache
7521308Sache    /**
7621308Sache     * Verify that NewSize and MaxNewSize flags affect young gen size.
77119610Sache     *
7821308Sache     * @param newSize value of NewSize option, omitted if negative
7921308Sache     * @param maxNewSize value of MaxNewSize option, omitted if negative
8021308Sache     * @param heapSize value of HeapSize option
8121308Sache     * @param maxHeapSize value of MaxHeapSize option
8221308Sache     * @param options additional options for JVM
83119610Sache     * @param failureExpected true if JVM should fail with passed heap size options
8421308Sache     */
85136644Sache    public static void testNewSizeFlags(long newSize, long maxNewSize,
86136644Sache            long heapSize, long maxHeapSize,
87136644Sache            LinkedList<String> options,
88136644Sache            boolean failureExpected) throws Exception {
8921308Sache        long expectedNewSize = newSize;
9021308Sache        long expectedMaxNewSize = (maxNewSize >= 0 ? Math.max(maxNewSize, newSize) : maxNewSize);
9121308Sache        testVMOptions(newSize, maxNewSize,
92119610Sache                heapSize, maxHeapSize,
9321308Sache                expectedNewSize, expectedMaxNewSize,
94136644Sache                options, failureExpected);
95136644Sache    }
96136644Sache
97136644Sache    /**
9821308Sache     * Verify that -Xmn flag affect young gen size.
9921308Sache     *
10021308Sache     * @param mnValue value of -Xmn option
101119610Sache     * @param heapSize value of HeapSize option
10221308Sache     * @param maxHeapSize value of MaxHeapSize option
10321308Sache     * @param options additional options for JVM
104119610Sache     * @param failureExpected true if JVM should fail with passed heap size options
10521308Sache     */
10621308Sache    public static void testXmnFlags(long mnValue,
107119610Sache            long heapSize, long maxHeapSize,
10821308Sache            LinkedList<String> options,
10921308Sache            boolean failureExpected) throws Exception {
11021308Sache        LinkedList<String> newOptions = new LinkedList<>(options);
11121308Sache        newOptions.add("-Xmn" + mnValue);
112119610Sache        testVMOptions(-1, -1,
11321308Sache                heapSize, maxHeapSize,
11421308Sache                mnValue, mnValue,
115119610Sache                newOptions, failureExpected);
11621308Sache    }
11721308Sache
11821308Sache    /**
11921308Sache     * Verify that NewSize and MaxNewSize flags affect young gen size.
12021308Sache     *
12121308Sache     * @param newSize value of NewSize option, omitted if negative
122119610Sache     * @param maxNewSize value of MaxNewSize option, omitted if negative
12321308Sache     * @param heapSize value of HeapSize option
12421308Sache     * @param maxHeapSize value of MaxHeapSize option
12521308Sache     * @param expectedNewSize expected initial young gen size
126119610Sache     * @param expectedMaxNewSize expected max young gen size
12721308Sache     * @param options additional options for JVM
12821308Sache     * @param failureExpected true if JVM should fail with passed heap size options
12921308Sache     */
130119610Sache    public static void testVMOptions(long newSize, long maxNewSize,
13121308Sache            long heapSize, long maxHeapSize,
13221308Sache            long expectedNewSize, long expectedMaxNewSize,
13321308Sache            LinkedList<String> options, boolean failureExpected) throws Exception {
134119610Sache        OutputAnalyzer analyzer = startVM(options, newSize, maxNewSize, heapSize, maxHeapSize, expectedNewSize, expectedMaxNewSize);
13521308Sache
136136644Sache        if (failureExpected) {
137136644Sache            analyzer.shouldHaveExitValue(1);
138136644Sache            analyzer.shouldMatch("(Error occurred during initialization of VM)|"
139136644Sache                    + "(Error: Could not create the Java Virtual Machine.)");
14021308Sache        } else {
14121308Sache            analyzer.shouldHaveExitValue(0);
142119610Sache        }
14321308Sache    }
14421308Sache
14521308Sache    private static OutputAnalyzer startVM(LinkedList<String> options,
14621308Sache            long newSize, long maxNewSize,
147119610Sache            long heapSize, long maxHeapSize,
14821308Sache            long expectedNewSize, long expectedMaxNewSize) throws Exception, IOException {
14921308Sache        LinkedList<String> vmOptions = new LinkedList<>(options);
15021308Sache        Collections.addAll(vmOptions,
15121308Sache                "-Xbootclasspath/a:.",
152119610Sache                "-XX:+UnlockDiagnosticVMOptions",
15321308Sache                "-XX:+WhiteBoxAPI",
15421308Sache                (newSize >= 0 ? "-XX:NewSize=" + newSize : ""),
15521308Sache                (maxNewSize >= 0 ? "-XX:MaxNewSize=" + maxNewSize : ""),
15621308Sache                "-Xmx" + maxHeapSize,
157119610Sache                "-Xms" + heapSize,
15821308Sache                "-XX:GCLockerEdenExpansionPercent=0",
15921308Sache                "-XX:-UseLargePages",
16021308Sache                NewSizeVerifier.class.getName(),
16121308Sache                Long.toString(expectedNewSize),
16221308Sache                Long.toString(expectedMaxNewSize),
16321308Sache                Long.toString(heapSize),
16421308Sache                Long.toString(maxHeapSize)
16521308Sache        );
16621308Sache        vmOptions.removeIf(String::isEmpty);
167119610Sache        ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
16821308Sache        OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
16921308Sache        return analyzer;
17047558Sache    }
17147558Sache
172119610Sache    /**
17321308Sache     * NewSizeVerifier checks that initial young gen size is equal to expected
17421308Sache     * regardful to alignment and that young gen size will not be greater than
17521308Sache     * expected max size.
17621308Sache     * In order to verify that young gen size will not be greater then expected
17721308Sache     * max size, NewSizeVerifier do some object allocation to force garbage
17821308Sache     * collection and heap expansion.
179119610Sache     */
18021308Sache    public static class NewSizeVerifier {
18121308Sache
18221308Sache        private static final WhiteBox WB = WhiteBox.getWhiteBox();
18321308Sache        private static final GCTypes.YoungGCType YOUNG_GC_TYPE = GCTypes.YoungGCType.getYoungGCType();
18421308Sache        private static final long HEAP_SPACE_ALIGNMENT = WB.getHeapSpaceAlignment();
18521308Sache        private static final long HEAP_ALIGNMENT = WB.getHeapAlignment();
186119610Sache        private static final long PS_VIRTUAL_SPACE_ALIGNMENT =
18721308Sache                (YOUNG_GC_TYPE == GCTypes.YoungGCType.PSNew) ? WB.psVirtualSpaceAlignment() : 0;
18821308Sache
18921308Sache        public static final int ARRAY_LENGTH = 100;
19021308Sache        public static final int CHUNK_SIZE = 1024;
19121308Sache        public static final int MAX_ITERATIONS = 10;
19221308Sache        public static byte garbage[][] = new byte[ARRAY_LENGTH][];
193119610Sache
19421308Sache        public static void main(String args[]) throws Exception {
19521308Sache            if (args.length != 4) {
19621308Sache                throw new IllegalArgumentException("Expected 4 args: <expectedNewSize> <expectedMaxNewSize> <initialHeapSize> <maxHeapSize>");
19721308Sache            }
198119610Sache            final long newSize = Long.valueOf(args[0]);
19921308Sache            final long maxNewSize = Long.valueOf(args[1]);
20021308Sache            final long initialHeapSize = Long.valueOf(args[2]);
20121308Sache            final long maxHeapSize = Long.valueOf(args[3]);
202119610Sache
20321308Sache            // verify initial size
20421308Sache            verifyNewSize(newSize, maxNewSize, initialHeapSize, maxHeapSize);
205119610Sache
20621308Sache            // force GC and verify that size is still correct
20721308Sache            AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE, () -> (verifyNewSize(newSize, maxNewSize, initialHeapSize, maxHeapSize)));
20821308Sache            allocator.allocateMemoryAndVerifyNoOOME();
20921308Sache        }
21021308Sache
21121308Sache        /**
21221308Sache         * Verify that actual young gen size conforms NewSize and MaxNewSize values.
21321308Sache         */
21421308Sache        public static Void verifyNewSize(long newSize, long maxNewSize,
21521308Sache                long initialHeapSize, long maxHeapSize) {
21621308Sache            long alignedNewSize = alignGenSize(newSize);
21721308Sache            long alignedMaxNewSize = alignGenSize(maxNewSize);
21821308Sache            long alignedXms = alignHeapSize(initialHeapSize);
21921308Sache            long alignedXmx = alignHeapSize(maxHeapSize);
22021308Sache
221119610Sache            MemoryUsage youngGenUsage = getYoungGenUsage();
22221308Sache            long initSize = youngGenUsage.getInit();
22321308Sache            long commitedSize = youngGenUsage.getCommitted();
22421308Sache            long maxSize = youngGenUsage.getMax();
22521308Sache
226119610Sache            if (newSize != -1) {
22721308Sache                if (initSize < alignedNewSize) {
22821308Sache                    throw new RuntimeException("initial new size < NewSize value: "
22947558Sache                            + initSize + " < " + alignedNewSize);
23047558Sache                }
23147558Sache
23247558Sache                if (commitedSize < alignedNewSize) {
23347558Sache                    throw new RuntimeException("actual new size < NewSize value: "
234119610Sache                            + commitedSize + " < " + alignedNewSize);
23521308Sache                }
23621308Sache
23721308Sache                // for G1 max new size == committed new size
238119610Sache                if (YOUNG_GC_TYPE != GCTypes.YoungGCType.G1
23921308Sache                        && maxSize < alignedNewSize) {
24021308Sache                    throw new RuntimeException("max new size < NewSize value: "
24121308Sache                            + maxSize + " < " + alignedNewSize);
24221308Sache                }
24375406Sache            }
24421308Sache
24521308Sache            if (maxNewSize != -1) {
24675406Sache                if (initSize > alignedMaxNewSize) {
24721308Sache                    throw new RuntimeException("initial new size > MaxNewSize value: "
24821308Sache                            + initSize + " > " + alignedMaxNewSize);
24921308Sache                }
25021308Sache
25121308Sache                if (commitedSize > alignedMaxNewSize) {
252136644Sache                    throw new RuntimeException("actual new size > MaxNewSize value: "
253136644Sache                            + commitedSize + " > " + alignedMaxNewSize);
25475406Sache                }
25575406Sache
25675406Sache                if (alignedXms != alignedXmx) {
25726497Sache                    if (YOUNG_GC_TYPE != GCTypes.YoungGCType.G1
25826497Sache                            && maxSize != alignedMaxNewSize) {
25926497Sache                        throw new RuntimeException("max new size != MaxNewSize value: "
26075406Sache                                + maxSize + " != " + alignedMaxNewSize);
26126497Sache                    }
26247558Sache                } else {
26347558Sache                    if (YOUNG_GC_TYPE != GCTypes.YoungGCType.G1
26447558Sache                            && maxSize != alignedNewSize) {
26547558Sache                        throw new RuntimeException("max new size != NewSize for case InitialHeapSize == MaxHeapSize value: "
26621308Sache                                + maxSize + " != " + alignedNewSize + " HeapSize == " + alignedXms);
267                    }
268                }
269            }
270            return null;
271        }
272
273        /**
274         *  Get young gen memory usage.
275         *
276         *  For G1 it is EdenUsage + SurvivorUsage,
277         *  for other GCs it is EdenUsage + 2 * SurvivorUsage.
278         *  For G1 max value is just LONG_MAX.
279         *  For all GCs used value is 0.
280         */
281        private static MemoryUsage getYoungGenUsage() {
282            MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage();
283            MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage();
284            long edenUsageInit = edenUsage.getInit();
285            long edenUsageCommited = edenUsage.getCommitted();
286            long survivorUsageInit = survivorUsage.getInit();
287            long survivorUsageCommited = survivorUsage.getCommitted();
288
289            if (YOUNG_GC_TYPE == GCTypes.YoungGCType.G1) {
290                return new MemoryUsage(edenUsageInit + survivorUsageInit, 0,
291                        edenUsageCommited + survivorUsageCommited, Long.MAX_VALUE);
292            } else {
293                return new MemoryUsage(edenUsageInit + survivorUsageInit * 2, 0,
294                        edenUsageCommited + survivorUsageCommited * 2,
295                        edenUsage.getMax() + survivorUsage.getMax() * 2);
296            }
297        }
298
299        /**
300         * Align generation size regardful to used young GC.
301         */
302        public static long alignGenSize(long value) {
303            switch (YOUNG_GC_TYPE) {
304                case DefNew:
305                case ParNew:
306                    return HeapRegionUsageTool.alignDown(value, HEAP_SPACE_ALIGNMENT);
307                case PSNew:
308                    return HeapRegionUsageTool.alignUp(HeapRegionUsageTool.alignDown(value,
309                            HEAP_SPACE_ALIGNMENT),
310                            PS_VIRTUAL_SPACE_ALIGNMENT);
311                case G1:
312                    return HeapRegionUsageTool.alignUp(value, WB.g1RegionSize());
313                default:
314                    throw new RuntimeException("Unexpected young GC type");
315            }
316        }
317
318        /**
319         * Align heap size.
320         */
321        public static long alignHeapSize(long value){
322            return HeapRegionUsageTool.alignUp(value,HEAP_ALIGNMENT);
323        }
324    }
325}
326