1 /*
   2  * Copyright (c) 2017, 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 TestVerifyGCType
  26  * @summary Test the VerifyGCType flag to ensure basic functionality.
  27  * @key gc
  28  * @requires vm.gc.G1
  29  * @library /test/lib
  30  * @run driver TestVerifyGCType
  31  */
  32 
  33 import java.util.ArrayList;
  34 import java.util.Collections;
  35 
  36 import jdk.test.lib.Asserts;
  37 import jdk.test.lib.Utils;
  38 import jdk.test.lib.process.OutputAnalyzer;
  39 import jdk.test.lib.process.ProcessTools;
  40 
  41 public class TestVerifyGCType {
  42     public static final String  VERIFY_TAG    = "[gc,verify]";
  43     public static final String  VERIFY_BEFORE = "Verifying Before GC";
  44     public static final String  VERIFY_DURING = "Verifying During GC";
  45     public static final String  VERIFY_AFTER  = "Verifying After GC";
  46 
  47     public static void main(String args[]) throws Exception {
  48         // Test with all verification enabled
  49         OutputAnalyzer output = testWithVerificationType(new String[0]);
  50         output.shouldHaveExitValue(0);
  51 
  52         verifyCollection("Pause Young", true, false, true, output.getStdout());
  53         verifyCollection("Pause Remark", false, true, false, output.getStdout());
  54         verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
  55         verifyCollection("Pause Full", true, true, true, output.getStdout());
  56 
  57         // Test with all explicitly enabled
  58         output = testWithVerificationType(new String[] {"young", "remark", "cleanup", "full"});
  59         output.shouldHaveExitValue(0);
  60 
  61         verifyCollection("Pause Young", true, false, true, output.getStdout());
  62         verifyCollection("Pause Remark", false, true, false, output.getStdout());
  63         verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
  64         verifyCollection("Pause Full", true, true, true, output.getStdout());
  65 
  66         // Test with full and remark
  67         output = testWithVerificationType(new String[] {"remark", "full"});
  68         output.shouldHaveExitValue(0);
  69 
  70         verifyCollection("Pause Young", false, false, false, output.getStdout());
  71         verifyCollection("Pause Remark", false, true, false, output.getStdout());
  72         verifyCollection("Pause Cleanup", false, false, false, output.getStdout());
  73         verifyCollection("Pause Full", true, true, true, output.getStdout());
  74 
  75         // Test bad type
  76         output = testWithVerificationType(new String[] {"old"});
  77         output.shouldHaveExitValue(0);
  78 
  79         output.shouldMatch("VerifyGCType: '.*' is unknown. Available are: young, mixed, remark, cleanup and full ");
  80         verifyCollection("Pause Young", true, false, true, output.getStdout());
  81         verifyCollection("Pause Remark", false, true, false, output.getStdout());
  82         verifyCollection("Pause Cleanup", false, true, false, output.getStdout());
  83         verifyCollection("Pause Full", true, true, true, output.getStdout());
  84 
  85         // Test bad gc
  86         output = testWithBadGC();
  87         output.shouldHaveExitValue(0);
  88         output.shouldMatch("VerifyGCType is not supported by this collector.");
  89     }
  90 
  91     private static OutputAnalyzer testWithVerificationType(String[] types) throws Exception {
  92         ArrayList<String> basicOpts = new ArrayList<>();
  93         Collections.addAll(basicOpts, new String[] {
  94                                        "-XX:+UseG1GC",
  95                                        "-XX:InitiatingHeapOccupancyPercent=1",
  96                                        "-Xlog:gc,gc+start,gc+verify=info",
  97                                        "-Xmx10m",
  98                                        "-Xms10m",
  99                                        "-Xmn2m",
 100                                        "-XX:+UnlockDiagnosticVMOptions",
 101                                        "-XX:+VerifyBeforeGC",
 102                                        "-XX:+VerifyAfterGC",
 103                                        "-XX:+VerifyDuringGC"});
 104 
 105         for(String verifyType : types) {
 106             basicOpts.add("-XX:VerifyGCType="+verifyType);
 107         }
 108 
 109         basicOpts.add(GarbageProducer.class.getName());
 110 
 111         ProcessBuilder procBuilder =  ProcessTools.createJavaProcessBuilder(basicOpts.toArray(
 112                                                                             new String[basicOpts.size()]));
 113         OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
 114         return analyzer;
 115     }
 116 
 117     private static OutputAnalyzer testWithBadGC() throws Exception {
 118         ProcessBuilder procBuilder =  ProcessTools.createJavaProcessBuilder(new String[] {
 119                 "-XX:+UseParallelGC",
 120                 "-XX:+UnlockDiagnosticVMOptions",
 121                 "-XX:VerifyGCType=full",
 122                 "-version"});
 123 
 124         OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start());
 125         return analyzer;
 126     }
 127 
 128     private static void verifyCollection(String name, boolean expectBefore, boolean expectDuring, boolean expectAfter, String data) {
 129         CollectionInfo ci = CollectionInfo.parseFirst(name, data);
 130         Asserts.assertTrue(ci != null, "Expected GC not found: " + name);
 131 
 132         // Verify Before
 133         verifyType(ci, expectBefore, VERIFY_BEFORE);
 134         // Verify During
 135         verifyType(ci, expectDuring, VERIFY_DURING);
 136         // Verify After
 137         verifyType(ci, expectAfter, VERIFY_AFTER);
 138     }
 139 
 140     private static void verifyType(CollectionInfo ci, boolean shouldExist, String pattern) {
 141         if (shouldExist) {
 142             Asserts.assertTrue(ci.containsVerification(pattern), "Missing expected verification for: " + ci.getName());
 143         } else {
 144             Asserts.assertFalse(ci.containsVerification(pattern), "Found unexpected verification for: " + ci.getName());
 145         }
 146     }
 147 
 148     public static class CollectionInfo {
 149         String name;
 150         ArrayList<String> verification;
 151         public CollectionInfo(String name) {
 152             this.name = name;
 153             this.verification = new ArrayList<>();
 154             System.out.println("Created CollectionInfo: " + name);
 155         }
 156 
 157         public String getName() {
 158             return name;
 159         }
 160 
 161         public void addVerification(String verify) {
 162             System.out.println("Adding: " + verify);
 163             verification.add(verify);
 164         }
 165 
 166         public boolean containsVerification(String contains) {
 167             for (String entry : verification) {
 168                 if (entry.contains(contains)) {
 169                     return true;
 170                 }
 171             }
 172             return false;
 173         }
 174 
 175         static CollectionInfo parseFirst(String name, String data) {
 176             CollectionInfo result = null;
 177             int firstIndex = data.indexOf(name);
 178             if (firstIndex == -1) {
 179                 return result;
 180             }
 181             int nextIndex = data.indexOf(name, firstIndex + 1);
 182             if (nextIndex == -1) {
 183                 return result;
 184             }
 185             // Found an entry for this name
 186             result = new CollectionInfo(name);
 187             String collectionData = data.substring(firstIndex, nextIndex + name.length());
 188             for (String line : collectionData.split(System.getProperty("line.separator"))) {
 189                 if (line.contains(VERIFY_TAG)) {
 190                     result.addVerification(line);
 191                 }
 192             }
 193             return result;
 194         }
 195     }
 196 
 197     public static class GarbageProducer {
 198         static Object[] garbage = new Object[100];
 199 
 200         public static void main(String args[]) throws Exception {
 201             // Ensure at least one full GC
 202             System.gc();
 203             // Alloc 10M, but only keep 1M alive.
 204             for(int i = 0; i<1000; i++) {
 205                 garbage[i%garbage.length] = new byte[10240];
 206             }
 207             // Sleep to make sure concurrent cycle is done
 208             Thread.sleep(1000);
 209         }
 210     }
 211 }