1 /* 2 * Copyright (c) 2017, 2018, 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 * @build sun.hotspot.WhiteBox 31 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 32 * @run driver TestVerifyGCType 33 */ 34 35 import java.util.ArrayList; 36 import java.util.Collections; 37 38 import jdk.test.lib.Asserts; 39 import jdk.test.lib.Utils; 40 import jdk.test.lib.process.OutputAnalyzer; 41 import jdk.test.lib.process.ProcessTools; 42 import sun.hotspot.WhiteBox; 43 44 public class TestVerifyGCType { 45 public static final String VERIFY_TAG = "[gc,verify]"; 46 public static final String VERIFY_BEFORE = "Verifying Before GC"; 47 public static final String VERIFY_DURING = "Verifying During GC"; 48 public static final String VERIFY_AFTER = "Verifying After GC"; 49 50 public static void main(String args[]) throws Exception { 51 testAllVerificationEnabled(); 52 testAllExplicitlyEnabled(); 53 testFullAndRemark(); 54 testConcurrentMark(); 55 testBadVerificationType(); 56 } 57 58 private static void testAllVerificationEnabled() throws Exception { 59 // Test with all verification enabled 60 OutputAnalyzer output = testWithVerificationType(new String[0]); 61 output.shouldHaveExitValue(0); 62 63 verifyCollection("Pause Young", true, false, true, output.getStdout()); 64 verifyCollection("Pause Initial Mark", true, false, true, output.getStdout()); 65 verifyCollection("Pause Mixed", true, false, true, output.getStdout()); 66 verifyCollection("Pause Remark", false, true, false, output.getStdout()); 67 verifyCollection("Pause Cleanup", false, true, false, output.getStdout()); 68 verifyCollection("Pause Full", true, true, true, output.getStdout()); 69 } 70 71 private static void testAllExplicitlyEnabled() throws Exception { 72 OutputAnalyzer output; 73 // Test with all explicitly enabled 74 output = testWithVerificationType(new String[] { 75 "young-only", "initial-mark", "mixed", "remark", "cleanup", "full"}); 76 output.shouldHaveExitValue(0); 77 78 verifyCollection("Pause Young", true, false, true, output.getStdout()); 79 verifyCollection("Pause Initial Mark", true, false, true, output.getStdout()); 80 verifyCollection("Pause Mixed", 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 86 private static void testFullAndRemark() throws Exception { 87 OutputAnalyzer output; 88 // Test with full and remark 89 output = testWithVerificationType(new String[] {"remark", "full"}); 90 output.shouldHaveExitValue(0); 91 92 verifyCollection("Pause Young", false, false, false, output.getStdout()); 93 verifyCollection("Pause Initial Mark", false, false, false, output.getStdout()); 94 verifyCollection("Pause Mixed", false, false, false, output.getStdout()); 95 verifyCollection("Pause Remark", false, true, false, output.getStdout()); 96 verifyCollection("Pause Cleanup", false, false, false, output.getStdout()); 97 verifyCollection("Pause Full", true, true, true, output.getStdout()); 98 } 99 100 private static void testConcurrentMark() throws Exception { 101 OutputAnalyzer output; 102 // Test with full and remark 103 output = testWithVerificationType(new String[] {"initial-mark", "cleanup", "remark"}); 104 output.shouldHaveExitValue(0); 105 106 verifyCollection("Pause Young", false, false, false, output.getStdout()); 107 verifyCollection("Pause Initial Mark", true, false, true, output.getStdout()); 108 verifyCollection("Pause Mixed", false, false, false, output.getStdout()); 109 verifyCollection("Pause Remark", false, true, false, output.getStdout()); 110 verifyCollection("Pause Cleanup", false, true, false, output.getStdout()); 111 verifyCollection("Pause Full", false, false, false, output.getStdout()); 112 } 113 114 private static void testBadVerificationType() throws Exception { 115 OutputAnalyzer output; 116 // Test bad type 117 output = testWithVerificationType(new String[] {"old"}); 118 output.shouldHaveExitValue(0); 119 120 output.shouldMatch("VerifyGCType: '.*' is unknown. Available types are: young-only, initial-mark, mixed, remark, cleanup and full"); 121 verifyCollection("Pause Young", true, false, true, output.getStdout()); 122 verifyCollection("Pause Initial Mark", true, false, true, output.getStdout()); 123 verifyCollection("Pause Mixed", true, false, true, output.getStdout()); 124 verifyCollection("Pause Remark", false, true, false, output.getStdout()); 125 verifyCollection("Pause Cleanup", false, true, false, output.getStdout()); 126 verifyCollection("Pause Full", true, true, true, output.getStdout()); 127 } 128 129 private static OutputAnalyzer testWithVerificationType(String[] types) throws Exception { 130 ArrayList<String> basicOpts = new ArrayList<>(); 131 Collections.addAll(basicOpts, new String[] { 132 "-Xbootclasspath/a:.", 133 "-XX:+UnlockDiagnosticVMOptions", 134 "-XX:+UseG1GC", 135 "-XX:+WhiteBoxAPI", 136 "-Xlog:gc,gc+start,gc+verify=info", 137 "-Xms16m", 138 "-Xmx16m", 139 "-XX:ParallelGCThreads=1", 140 "-XX:G1HeapWastePercent=1", 141 "-XX:+VerifyBeforeGC", 142 "-XX:+VerifyAfterGC", 143 "-XX:+VerifyDuringGC"}); 144 145 for(String verifyType : types) { 146 basicOpts.add("-XX:VerifyGCType="+verifyType); 147 } 148 149 basicOpts.add(TriggerGCs.class.getName()); 150 151 ProcessBuilder procBuilder = ProcessTools.createJavaProcessBuilder(basicOpts.toArray( 152 new String[basicOpts.size()])); 153 OutputAnalyzer analyzer = new OutputAnalyzer(procBuilder.start()); 154 return analyzer; 155 } 156 157 private static void verifyCollection(String name, boolean expectBefore, boolean expectDuring, boolean expectAfter, String data) { 158 CollectionInfo ci = CollectionInfo.parseFirst(name, data); 159 Asserts.assertTrue(ci != null, "Expected GC not found: " + name + "\n" + data); 160 161 // Verify Before 162 verifyType(ci, expectBefore, VERIFY_BEFORE); 163 // Verify During 164 verifyType(ci, expectDuring, VERIFY_DURING); 165 // Verify After 166 verifyType(ci, expectAfter, VERIFY_AFTER); 167 } 168 169 private static void verifyType(CollectionInfo ci, boolean shouldExist, String pattern) { 170 if (shouldExist) { 171 Asserts.assertTrue(ci.containsVerification(pattern), "Missing expected verification for: " + ci.getName()); 172 } else { 173 Asserts.assertFalse(ci.containsVerification(pattern), "Found unexpected verification for: " + ci.getName()); 174 } 175 } 176 177 public static class CollectionInfo { 178 String name; 179 ArrayList<String> verification; 180 public CollectionInfo(String name) { 181 this.name = name; 182 this.verification = new ArrayList<>(); 183 System.out.println("Created CollectionInfo: " + name); 184 } 185 186 public String getName() { 187 return name; 188 } 189 190 public void addVerification(String verify) { 191 System.out.println("Adding: " + verify); 192 verification.add(verify); 193 } 194 195 public boolean containsVerification(String contains) { 196 for (String entry : verification) { 197 if (entry.contains(contains)) { 198 return true; 199 } 200 } 201 return false; 202 } 203 204 static CollectionInfo parseFirst(String name, String data) { 205 CollectionInfo result = null; 206 int firstIndex = data.indexOf(name); 207 if (firstIndex == -1) { 208 return result; 209 } 210 int nextIndex = data.indexOf(name, firstIndex + 1); 211 if (nextIndex == -1) { 212 return result; 213 } 214 // Found an entry for this name 215 result = new CollectionInfo(name); 216 String collectionData = data.substring(firstIndex, nextIndex + name.length()); 217 for (String line : collectionData.split(System.getProperty("line.separator"))) { 218 if (line.contains(VERIFY_TAG)) { 219 result.addVerification(line); 220 } 221 } 222 return result; 223 } 224 } 225 226 public static class TriggerGCs { 227 public static void main(String args[]) throws Exception { 228 WhiteBox wb = WhiteBox.getWhiteBox(); 229 // Allocate some memory that can be turned into garbage. 230 Object[] used = alloc1M(); 231 232 // Trigger the different GCs using the WhiteBox API. 233 wb.fullGC(); // full 234 235 // Memory have been promoted to old by full GC. Free 236 // some memory to be reclaimed by concurrent cycle. 237 partialFree(used); 238 wb.g1StartConcMarkCycle(); // initial-mark, remark and cleanup 239 240 // Sleep to make sure concurrent cycle is done 241 while (wb.g1InConcurrentMark()) { 242 Thread.sleep(1000); 243 } 244 245 // Trigger two young GCs, first will be young-only, second will be mixed. 246 wb.youngGC(); // young-only 247 wb.youngGC(); // mixed 248 } 249 250 private static Object[] alloc1M() { 251 Object[] ret = new Object[1024]; 252 // Alloc 1024 1k byte arrays (~1M) 253 for (int i = 0; i < ret.length; i++) { 254 ret[i] = new byte[1024]; 255 } 256 return ret; 257 } 258 259 private static void partialFree(Object[] array) { 260 // Free every other element 261 for (int i = 0; i < array.length; i+=2) { 262 array[i] = null; 263 } 264 } 265 } 266 }