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 TestDisableExplicitGCFlag
  26  * @requires (vm.opt.DisplayVMOutput == null) | (vm.opt.DisplayVMOutput == true)
  27  * @summary Verify that DisableExplicitGC flag affects System.gc() behavior.
  28  * @library /testlibrary /../../test/lib
  29  * @build TestDisableExplicitGCFlag
  30  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  31  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestDisableExplicitGCFlag true  false 1 1
  32  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestDisableExplicitGCFlag false false 1 1
  33  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestDisableExplicitGCFlag false true  1 0
  34  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestDisableExplicitGCFlag true  false 3 2
  35  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestDisableExplicitGCFlag false false 3 2
  36  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI TestDisableExplicitGCFlag false true  3 1
  37  */
  38 import com.oracle.java.testlibrary.*;
  39 import java.util.Arrays;
  40 import java.util.LinkedList;
  41 import java.util.List;
  42 import java.util.regex.Matcher;
  43 import java.util.regex.Pattern;
  44 import sun.hotspot.WhiteBox;
  45 
  46 public class TestDisableExplicitGCFlag {
  47 
  48     public final static String DIS_EXPLICIT_GC_FLAG = "DisableExplicitGC";
  49     public final static String[] PARALLEL_GC_OPTIONS = {"UseParallelGC", "UseParallelOldGC"};
  50     public final static Pattern SYSTEM_GC_PATTERN = Pattern.compile("System.gc\\(\\)");
  51     // Parallel and ParallelOld GC produces different output - System.gc() message occurred twice per System.gc() call
  52     public final static Pattern SYSTEM_GC_PARALLEL_PATTERN = Pattern.compile("Full GC \\(System.gc\\(\\)\\)");
  53     public final static WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
  54 
  55     public static void main(String args[]) throws Exception {
  56         boolean checkDefaultValue = Boolean.parseBoolean(args[0]);
  57         boolean checkValue = Boolean.parseBoolean(args[1]);
  58         int iterationCount = Integer.parseInt(args[2]);
  59         int expectedGCCount = Integer.parseInt(args[3]);
  60         testDisableExplicitGC(checkDefaultValue, checkValue, iterationCount, expectedGCCount);
  61     }
  62 
  63     /**
  64      * @param checkDefaultValue Check default value of DisableExplicitGC VM flag
  65      * @param checkValue check VM behavior with DisableExplicitGC=checkValue
  66      * @param iterationCount how many times provoke System.gc() with changing DisableExplicitGC flag
  67      * @param expectedGCCount how many System.gc() messages should be in VM output
  68      * @throws RuntimeException if expected count of System.gc() message does not match with occurred
  69      * @throws Exception from OutputAnalyzer or ProcessTools
  70      */
  71     public static void testDisableExplicitGC(boolean checkDefaultValue, boolean checkValue, int iterationCount, int expectedGCCount) throws Exception {
  72         List<String> vmOpts = new LinkedList(
  73                 Arrays.asList(
  74                         new String[]{
  75                             "-Xbootclasspath/a:.",
  76                             "-XX:+UnlockDiagnosticVMOptions",
  77                             "-XX:+WhiteBoxAPI",
  78                             "-XX:+PrintGC",
  79                             "-XX:+PrintGCCause",
  80                             GCProvoker.class.getName(),
  81                             Integer.toString(iterationCount)
  82                         }));
  83         // In case if we don't need to check default flag behavior - add VM option
  84         if (checkDefaultValue == false) {
  85             vmOpts.add(0, "-XX:" + (checkValue ? "+" : "-") + DIS_EXPLICIT_GC_FLAG);
  86         }
  87         vmOpts.addAll(0, Utils.getVmOptions());
  88         ProcessBuilder procBuilder
  89                 = ProcessTools.createJavaProcessBuilder(true, vmOpts.toArray(new String[0]));
  90         OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
  91         analyzer.shouldHaveExitValue(0);
  92         String output = analyzer.getOutput();
  93         System.out.println(output);
  94         checkResults(output, expectedGCCount);
  95     }
  96 
  97     private static void checkResults(String output, int expectedGCCount) {
  98         int multiplier = 1;
  99         Pattern pattern = SYSTEM_GC_PATTERN;
 100         for (String option : PARALLEL_GC_OPTIONS) {
 101             if (WHITE_BOX.getBooleanVMFlag(option)) {
 102                 pattern = SYSTEM_GC_PARALLEL_PATTERN;
 103             }
 104         }
 105         System.out.println("Expect " + expectedGCCount * multiplier + " System.gc() messages.");
 106         Matcher matcher = pattern.matcher(output);
 107         int occurrence = 0;
 108         while (matcher.find()) {
 109             ++occurrence;
 110         }
 111         if (occurrence != expectedGCCount) {
 112             throw new RuntimeException("Occurred " + occurrence + " System.gc() messages.");
 113         }
 114     }
 115 
 116     public static class GCProvoker {
 117 
 118         public static void main(String args[]) {
 119             int iterationCount = Integer.parseInt(args[0]);
 120             if (iterationCount == 1) {
 121                 System.gc();
 122             } else {
 123                 System.out.println("Will perform " + iterationCount + " iterations.");
 124                 for (int i = 0; i < iterationCount; i++) {
 125                     System.gc();
 126                     // Invert flag for next iteration
 127                     boolean value = WHITE_BOX.getBooleanVMFlag(DIS_EXPLICIT_GC_FLAG);
 128                     WHITE_BOX.setBooleanVMFlag(DIS_EXPLICIT_GC_FLAG, !value);
 129                 }
 130             }
 131         }
 132     }
 133 }