1 /* 2 * Copyright (c) 2013, 2016, 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 package org.graalvm.compiler.hotspot.test; 26 27 import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; 28 import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; 29 30 import java.io.File; 31 import java.io.IOException; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.Collections; 35 import java.util.Enumeration; 36 import java.util.List; 37 import java.util.zip.ZipEntry; 38 import java.util.zip.ZipFile; 39 40 import org.graalvm.compiler.core.GraalCompilerOptions; 41 import org.graalvm.compiler.core.test.GraalCompilerTest; 42 import org.graalvm.compiler.test.SubprocessUtil; 43 import org.graalvm.compiler.test.SubprocessUtil.Subprocess; 44 import org.junit.Assert; 45 import org.junit.Test; 46 47 /** 48 * Tests support for dumping graphs and other info useful for debugging a compiler crash. 49 */ 50 public class CompilationWrapperTest extends GraalCompilerTest { 51 52 /** 53 * Tests compilation requested by the VM. 54 */ 55 @Test 56 public void testVMCompilation1() throws IOException, InterruptedException { 57 assumeManagementLibraryIsLoadable(); 58 testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", 59 "-XX:+UseJVMCICompiler", 60 "-Dgraal.CompilationFailureAction=ExitVM", 61 "-Dgraal.CrashAt=TestProgram.*", 62 "-Xcomp", 63 "-XX:CompileCommand=compileonly,*/TestProgram.print*", 64 TestProgram.class.getName())); 65 } 66 67 /** 68 * Tests that {@code -Dgraal.ExitVMOnException=true} works as an alias for 69 * {@code -Dgraal.CompilationFailureAction=ExitVM}. 70 */ 71 @Test 72 public void testVMCompilation2() throws IOException, InterruptedException { 73 assumeManagementLibraryIsLoadable(); 74 testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", 75 "-XX:+UseJVMCICompiler", 76 "-Dgraal.ExitVMOnException=true", 77 "-Dgraal.CrashAt=TestProgram.*", 78 "-Xcomp", 79 "-XX:CompileCommand=compileonly,*/TestProgram.print*", 80 TestProgram.class.getName())); 81 } 82 83 static class Probe { 84 final String substring; 85 final int expectedOccurrences; 86 int actualOccurrences; 87 String lastMatchingLine; 88 89 Probe(String substring, int expectedOccurrences) { 90 this.substring = substring; 91 this.expectedOccurrences = expectedOccurrences; 92 } 93 94 boolean matches(String line) { 95 if (line.contains(substring)) { 96 actualOccurrences++; 97 lastMatchingLine = line; 98 return true; 99 } 100 return false; 101 } 102 103 String test() { 104 return expectedOccurrences == actualOccurrences ? null : String.format("expected %d, got %d occurrences", expectedOccurrences, actualOccurrences); 105 } 106 } 107 108 /** 109 * Tests {@link GraalCompilerOptions#MaxCompilationProblemsPerAction} in context of a 110 * compilation requested by the VM. 111 */ 112 @Test 113 public void testVMCompilation3() throws IOException, InterruptedException { 114 assumeManagementLibraryIsLoadable(); 115 final int maxProblems = 2; 116 Probe retryingProbe = new Probe("Retrying compilation of", maxProblems) { 117 @Override 118 String test() { 119 return actualOccurrences > 0 && actualOccurrences <= maxProblems ? null : String.format("expected occurrences to be in [1 .. %d]", maxProblems); 120 } 121 }; 122 Probe adjustmentProbe = new Probe("adjusting CompilationFailureAction from Diagnose to Print", 1) { 123 @Override 124 String test() { 125 if (retryingProbe.actualOccurrences >= maxProblems) { 126 if (actualOccurrences == 0) { 127 return "expected at least one occurrence"; 128 } 129 } 130 return null; 131 } 132 }; 133 Probe[] probes = { 134 retryingProbe, 135 adjustmentProbe 136 }; 137 testHelper(Arrays.asList(probes), Arrays.asList("-XX:-TieredCompilation", 138 "-XX:+UseJVMCICompiler", 139 "-Dgraal.CompilationFailureAction=Diagnose", 140 "-Dgraal.MaxCompilationProblemsPerAction=" + maxProblems, 141 "-Dgraal.CrashAt=TestProgram.*", 142 "-Xcomp", 143 "-XX:CompileCommand=compileonly,*/TestProgram.print*", 144 TestProgram.class.getName())); 145 } 146 147 /** 148 * Tests compilation requested by Truffle. 149 */ 150 @Test 151 public void testTruffleCompilation1() throws IOException, InterruptedException { 152 assumeManagementLibraryIsLoadable(); 153 testHelper(Collections.emptyList(), 154 Arrays.asList( 155 "-Dgraal.CompilationFailureAction=ExitVM", 156 "-Dgraal.TrufflePerformanceWarningsAreFatal=true", 157 "-Dgraal.CrashAt=root test1"), 158 "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); 159 } 160 161 /** 162 * Tests that TruffleCompilationExceptionsAreFatal works as expected. 163 */ 164 @Test 165 public void testTruffleCompilation2() throws IOException, InterruptedException { 166 Probe[] probes = { 167 new Probe("Exiting VM due to TruffleCompilationExceptionsAreFatal=true", 1), 168 }; 169 testHelper(Arrays.asList(probes), 170 Arrays.asList( 171 "-Dgraal.CompilationFailureAction=Silent", 172 "-Dgraal.TruffleCompilationExceptionsAreFatal=true", 173 "-Dgraal.CrashAt=root test1"), 174 "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); 175 } 176 177 /** 178 * Tests that TrufflePerformanceWarningsAreFatal generates diagnostic output. 179 */ 180 @Test 181 public void testTruffleCompilation3() throws IOException, InterruptedException { 182 assumeManagementLibraryIsLoadable(); 183 Probe[] probes = { 184 new Probe("Exiting VM due to TrufflePerformanceWarningsAreFatal=true", 1), 185 }; 186 testHelper(Arrays.asList(probes), 187 Arrays.asList( 188 "-Dgraal.CompilationFailureAction=Silent", 189 "-Dgraal.TrufflePerformanceWarningsAreFatal=true", 190 "-Dgraal.CrashAt=root test1:PermanentBailout"), 191 "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test"); 192 } 193 194 private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose"); 195 196 private static void testHelper(List<Probe> initialProbes, List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException { 197 final File dumpPath = new File(CompilationWrapperTest.class.getSimpleName() + "_" + System.currentTimeMillis()).getAbsoluteFile(); 198 List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine()); 199 vmArgs.removeIf(a -> a.startsWith("-Dgraal.")); 200 vmArgs.remove("-esa"); 201 vmArgs.remove("-ea"); 202 vmArgs.add("-Dgraal.DumpPath=" + dumpPath); 203 // Force output to a file even if there's a running IGV instance available. 204 vmArgs.add("-Dgraal.PrintGraphFile=true"); 205 vmArgs.addAll(extraVmArgs); 206 207 Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs); 208 if (VERBOSE) { 209 System.out.println(proc); 210 } 211 212 List<Probe> probes = new ArrayList<>(initialProbes); 213 Probe diagnosticProbe = null; 214 if (!extraVmArgs.contains("-Dgraal.TruffleCompilationExceptionsAreFatal=true")) { 215 diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1); 216 probes.add(diagnosticProbe); 217 probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) { 218 @Override 219 String test() { 220 return actualOccurrences > 0 ? null : "expected at least 1 occurrence"; 221 } 222 }); 223 } 224 225 for (String line : proc.output) { 226 for (Probe probe : probes) { 227 if (probe.matches(line)) { 228 break; 229 } 230 } 231 } 232 for (Probe probe : probes) { 233 String error = probe.test(); 234 if (error != null) { 235 Assert.fail(String.format("Did not find expected occurences of '%s' in output of command: %s%n%s", probe.substring, error, proc)); 236 } 237 } 238 if (diagnosticProbe != null) { 239 String line = diagnosticProbe.lastMatchingLine; 240 int substringStart = line.indexOf(diagnosticProbe.substring); 241 int substringLength = diagnosticProbe.substring.length(); 242 String diagnosticOutputZip = line.substring(substringStart + substringLength).trim(); 243 244 List<String> dumpPathEntries = Arrays.asList(dumpPath.list()); 245 246 File zip = new File(diagnosticOutputZip).getAbsoluteFile(); 247 Assert.assertTrue(zip.toString(), zip.exists()); 248 Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName())); 249 try { 250 int bgvOrCfgFiles = 0; 251 ZipFile dd = new ZipFile(diagnosticOutputZip); 252 List<String> entries = new ArrayList<>(); 253 for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) { 254 ZipEntry ze = e.nextElement(); 255 String name = ze.getName(); 256 entries.add(name); 257 if (name.endsWith(".bgv") || name.endsWith(".cfg")) { 258 bgvOrCfgFiles++; 259 } 260 } 261 if (bgvOrCfgFiles == 0) { 262 Assert.fail(String.format("Expected at least one .bgv or .cfg file in %s: %s%n%s", diagnosticOutputZip, entries, proc)); 263 } 264 } finally { 265 zip.delete(); 266 dumpPath.delete(); 267 } 268 } 269 } 270 } 271 272 class TestProgram { 273 public static void main(String[] args) { 274 printHello1(); 275 printWorld1(); 276 printHello2(); 277 printWorld2(); 278 printHello3(); 279 printWorld3(); 280 } 281 282 private static void printHello1() { 283 System.out.println("Hello1"); 284 } 285 286 private static void printWorld1() { 287 System.out.println("World1"); 288 } 289 290 private static void printHello2() { 291 System.out.println("Hello2"); 292 } 293 294 private static void printWorld2() { 295 System.out.println("World2"); 296 } 297 298 private static void printHello3() { 299 System.out.println("Hello3"); 300 } 301 302 private static void printWorld3() { 303 System.out.println("World3"); 304 } 305 }