1 /*
2  * Copyright (c) 2015, 2019, 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 package gc.arguments;
25 
26 /*
27  * @test TestMinAndInitialSurvivorRatioFlags
28  * @key gc
29  * @summary Verify that MinSurvivorRatio and InitialSurvivorRatio flags work
30  * @library /test/lib
31  * @library /
32  * @modules java.base/jdk.internal.misc
33  *          java.management
34  * @build sun.hotspot.WhiteBox
35  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
36  * @run driver/timeout=240 gc.arguments.TestMinAndInitialSurvivorRatioFlags
37  */
38 
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 /* Test verifies that VM can start with any GC when MinSurvivorRatio and
49  * InitialSurvivorRatio flags passed and for Parallel GC it verifies that
50  * after start up survivor ratio equal to InitialSurvivorRatio value and
51  * that actual survivor ratio will never be less than MinSurvivorRatio.
52  */
53 public class TestMinAndInitialSurvivorRatioFlags {
54 
55     public static final long M = 1024 * 1024;
56     public static final long HEAP_SIZE = 200 * M;
57     public static final long NEW_SIZE = 100 * M;
58 
main(String args[])59     public static void main(String args[]) throws Exception {
60         LinkedList<String> options = new LinkedList<>(
61                 Arrays.asList(Utils.getFilteredTestJavaOpts("-XX:[^ ]*SurvivorRatio=[^ ]+"))
62         );
63 
64         testSurvivorRatio(5, -1, -1, options, true);
65         testSurvivorRatio(10, -1, -1, options, true);
66         testSurvivorRatio(-1, 5, 3, options, true);
67         testSurvivorRatio(-1, 15, 3, options, true);
68         testSurvivorRatio(-1, 15, 3, options, false);
69         testSurvivorRatio(-1, 10, 10, options, true);
70         testSurvivorRatio(-1, 3, 15, options, true);
71         testSurvivorRatio(-1, 3, 15, options, false);
72     }
73 
74     /**
75      * Test that MinSurvivorRatio and InitialSurvivorRatio flags work.
76      *
77      * @param survivorRatio value for -XX:SurvivorRatio option, omitted if negative
78      * @param initRatio value for -XX:InitialSurvivorRatio option, omitted if negative
79      * @param minRatio value for -XX:MinSurvivorRatio option, omitted if negative
80      * @param options additional options for VM
81      * @param useAdaptiveSizePolicy turn on or off UseAdaptiveSizePolicy option
82      */
testSurvivorRatio(int survivorRatio, int initRatio, int minRatio, LinkedList<String> options, boolean useAdaptiveSizePolicy)83     public static void testSurvivorRatio(int survivorRatio,
84             int initRatio,
85             int minRatio,
86             LinkedList<String> options,
87             boolean useAdaptiveSizePolicy) throws Exception {
88 
89         LinkedList<String> vmOptions = new LinkedList<>(options);
90         Collections.addAll(vmOptions,
91                 "-Xbootclasspath/a:.",
92                 "-XX:+UnlockDiagnosticVMOptions",
93                 "-XX:+WhiteBoxAPI",
94                 "-XX:MaxNewSize=" + NEW_SIZE, "-XX:NewSize=" + NEW_SIZE,
95                 "-Xmx" + HEAP_SIZE, "-Xms" + HEAP_SIZE,
96                 (survivorRatio >= 0 ? "-XX:SurvivorRatio=" + survivorRatio : ""),
97                 (initRatio >= 0 ? "-XX:InitialSurvivorRatio=" + initRatio : ""),
98                 (minRatio >= 0 ? "-XX:MinSurvivorRatio=" + minRatio : ""),
99                 (useAdaptiveSizePolicy ? "-XX:+UseAdaptiveSizePolicy" : "-XX:-UseAdaptiveSizePolicy"),
100                 SurvivorRatioVerifier.class.getName(),
101                 Integer.toString(survivorRatio),
102                 Integer.toString(initRatio),
103                 Integer.toString(minRatio),
104                 Boolean.toString(useAdaptiveSizePolicy)
105         );
106         vmOptions.removeIf((String p) -> p.isEmpty());
107         ProcessBuilder procBuilder = GCArguments.createJavaProcessBuilder(vmOptions.toArray(new String[vmOptions.size()]));
108         OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
109         analyzer.shouldHaveExitValue(0);
110     }
111 
112     /**
113      * Class that verifies survivor ratio.
114      * Will be executed in tested VM. Checks initial size of eden and survivor paces with alignment.
115      */
116     public static class SurvivorRatioVerifier {
117 
118         public static WhiteBox wb = WhiteBox.getWhiteBox();
119 
120         public static final int MAX_ITERATIONS = 10;
121         public static final int ARRAY_LENGTH = 10000;
122         public static final int CHUNK_SIZE = 10000;
123 
124         public static byte garbage[][] = new byte[ARRAY_LENGTH][];
125 
main(String args[])126         public static void main(String args[]) throws Exception {
127             if (args.length != 4) {
128                 throw new IllegalArgumentException("Expected 4 args: <survivorRatio> <initRatio> <minRatio> <useAdaptiveSizePolicy>");
129             }
130             final int survivorRatio = Integer.valueOf(args[0]);
131             final int initRatio = Integer.valueOf(args[1]);
132             final int minRatio = Integer.valueOf(args[2]);
133             final boolean useAdaptiveSizePolicy = Boolean.valueOf(args[3]);
134 
135             // we stop testing only here to ensure that JVM will accept
136             // both MinSurvivorRatio and InitialSurvivorRatio regardles to GC
137             if (GCTypes.YoungGCType.getYoungGCType() != GCTypes.YoungGCType.PSNew) {
138                 System.out.println("Test is only applicable to Parallel GC");
139                 return;
140             }
141 
142             // verify initial survivor ratio
143             verifySurvivorRatio(survivorRatio, initRatio, minRatio, useAdaptiveSizePolicy, true);
144 
145             // force GC
146             AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE,
147                     () -> (verifySurvivorRatio(survivorRatio, initRatio, minRatio, useAdaptiveSizePolicy, false)));
148             allocator.allocateMemoryAndVerify();
149         }
150 
151         /**
152          * Verify actual survivor ratio.
153          *
154          * @param survivorRatio value of SurvivorRatio option, omitted if negative
155          * @param initRatio value of InitialSurvivorRatio option, omitted if negative
156          * @param minRatio value of MinSurvivorRatio option, omitted if negative
157          * @param useAdaptiveSizePolicy value of UseAdaptiveSizePolicy option
158          * @param verifyInitialRatio true if we are going to verify initial ratio
159          */
verifySurvivorRatio(int survivorRatio, int initRatio, int minRatio, boolean useAdaptiveSizePolicy, boolean verifyInitialRatio)160         public static Void verifySurvivorRatio(int survivorRatio,
161                 int initRatio,
162                 int minRatio,
163                 boolean useAdaptiveSizePolicy,
164                 boolean verifyInitialRatio) {
165 
166             MemoryUsage edenUsage = HeapRegionUsageTool.getEdenUsage();
167             MemoryUsage survivorUsage = HeapRegionUsageTool.getSurvivorUsage();
168 
169             long alignedNewSize = edenUsage.getMax() + 2 * survivorUsage.getMax();
170             long generationAlignment = wb.psHeapGenerationAlignment();
171 
172             if (survivorRatio >= 0) {
173                 // -XX:SurvivorRatio was passed to JVM, actual ratio should be SurvivorRatio + 2
174                 long expectedSize = HeapRegionUsageTool.alignDown(alignedNewSize / (survivorRatio + 2),
175                         generationAlignment);
176 
177                 if (survivorUsage.getCommitted() != expectedSize) {
178                     throw new RuntimeException("Expected survivor size is: " + expectedSize
179                             + ", but observed size is: " + survivorUsage.getCommitted());
180                 }
181             } else if (verifyInitialRatio || !useAdaptiveSizePolicy) {
182                 // In case of initial ratio verification or disabled adaptive size policy
183                 // ratio should be equal to InitialSurvivorRatio value
184                 long expectedSize = HeapRegionUsageTool.alignDown(alignedNewSize / initRatio,
185                         generationAlignment);
186                 if (survivorUsage.getCommitted() != expectedSize) {
187                     throw new RuntimeException("Expected survivor size is: " + expectedSize
188                             + ", but observed size is: " + survivorUsage.getCommitted());
189                 }
190             } else {
191                 // In any other case actual survivor ratio should not be lower than MinSurvivorRatio
192                 // or is should be equal to InitialSurvivorRatio
193                 long expectedMinSize = HeapRegionUsageTool.alignDown(alignedNewSize / minRatio,
194                         generationAlignment);
195                 long expectedInitSize = HeapRegionUsageTool.alignDown(alignedNewSize / initRatio,
196                         generationAlignment);
197                 if (survivorUsage.getCommitted() != expectedInitSize
198                         && survivorUsage.getCommitted() < expectedMinSize) {
199                     throw new RuntimeException("Expected survivor size should be " + expectedMinSize
200                             + " or should be greater then " + expectedMinSize
201                             + ", but observer survivor size is " + survivorUsage.getCommitted());
202                 }
203             }
204             return null;
205         }
206     }
207 }
208