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