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