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