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