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