src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java
changeset 47216 71c04702a3d5
parent 46963 089674d9949b
child 47798 9fe9292f5931
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
+import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.graalvm.compiler.core.GraalCompilerOptions;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.graalvm.compiler.test.SubprocessUtil.Subprocess;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests support for dumping graphs and other info useful for debugging a compiler crash.
+ */
+public class CompilationWrapperTest extends GraalCompilerTest {
+
+    /**
+     * Tests compilation requested by the VM.
+     */
+    @Test
+    public void testVMCompilation1() throws IOException, InterruptedException {
+        testHelper(Collections.emptyList(), Arrays.asList("-XX:+BootstrapJVMCI",
+                        "-XX:+UseJVMCICompiler",
+                        "-Dgraal.CompilationFailureAction=ExitVM",
+                        "-Dgraal.CrashAt=Object.*,String.*",
+                        "-version"));
+    }
+
+    /**
+     * Tests that {@code -Dgraal.ExitVMOnException=true} works as an alias for
+     * {@code -Dgraal.CompilationFailureAction=ExitVM}.
+     */
+    @Test
+    public void testVMCompilation2() throws IOException, InterruptedException {
+        testHelper(Collections.emptyList(), Arrays.asList("-XX:+BootstrapJVMCI",
+                        "-XX:+UseJVMCICompiler",
+                        "-Dgraal.ExitVMOnException=true",
+                        "-Dgraal.CrashAt=Object.*,String.*",
+                        "-version"));
+    }
+
+    static class Probe {
+        final String substring;
+        final int expectedOccurrences;
+        int actualOccurrences;
+        String lastMatchingLine;
+
+        Probe(String substring, int expectedOccurrences) {
+            this.substring = substring;
+            this.expectedOccurrences = expectedOccurrences;
+        }
+
+        boolean matches(String line) {
+            if (line.contains(substring)) {
+                actualOccurrences++;
+                lastMatchingLine = line;
+                return true;
+            }
+            return false;
+        }
+
+        String test() {
+            return expectedOccurrences == actualOccurrences ? null : String.format("expected %d, got %d occurrences", expectedOccurrences, actualOccurrences);
+        }
+    }
+
+    /**
+     * Tests {@link GraalCompilerOptions#MaxCompilationProblemsPerAction} in context of a
+     * compilation requested by the VM.
+     */
+    @Test
+    public void testVMCompilation3() throws IOException, InterruptedException {
+        final int maxProblems = 4;
+        Probe[] probes = {
+                        new Probe("To capture more information for diagnosing or reporting a compilation", maxProblems),
+                        new Probe("Retrying compilation of", maxProblems),
+                        new Probe("adjusting CompilationFailureAction from Diagnose to Print", 1),
+                        new Probe("adjusting CompilationFailureAction from Print to Silent", 1),
+        };
+        testHelper(Arrays.asList(probes), Arrays.asList("-XX:+BootstrapJVMCI",
+                        "-XX:+UseJVMCICompiler",
+                        "-Dgraal.CompilationFailureAction=Diagnose",
+                        "-Dgraal.MaxCompilationProblemsPerAction=" + maxProblems,
+                        "-Dgraal.CrashAt=Object.*,String.*",
+                        "-version"));
+    }
+
+    /**
+     * Tests compilation requested by Truffle.
+     */
+    @Test
+    public void testTruffleCompilation() throws IOException, InterruptedException {
+        testHelper(Collections.emptyList(),
+                        Arrays.asList(
+                                        "-Dgraal.CompilationFailureAction=ExitVM",
+                                        "-Dgraal.CrashAt=root test1"),
+                        "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
+    }
+
+    private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose");
+
+    private static void testHelper(List<Probe> initialProbes, List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
+        final File dumpPath = new File(CompilationWrapperTest.class.getSimpleName() + "_" + System.currentTimeMillis()).getAbsoluteFile();
+        List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
+        vmArgs.removeIf(a -> a.startsWith("-Dgraal."));
+        vmArgs.remove("-esa");
+        vmArgs.remove("-ea");
+        vmArgs.add("-Dgraal.DumpPath=" + dumpPath);
+        // Force output to a file even if there's a running IGV instance available.
+        vmArgs.add("-Dgraal.PrintGraphFile=true");
+        vmArgs.addAll(extraVmArgs);
+
+        Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs);
+        if (VERBOSE) {
+            System.out.println(proc);
+        }
+
+        List<Probe> probes = new ArrayList<>(initialProbes);
+        Probe diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1);
+        probes.add(diagnosticProbe);
+        probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) {
+            @Override
+            String test() {
+                return actualOccurrences > 0 ? null : "expected at least 1 occurrence";
+            }
+        });
+
+        for (String line : proc.output) {
+            for (Probe probe : probes) {
+                if (probe.matches(line)) {
+                    break;
+                }
+            }
+        }
+        for (Probe probe : probes) {
+            String error = probe.test();
+            if (error != null) {
+                Assert.fail(String.format("Did not find expected occurences of '%s' in output of command: %s%n%s", probe.substring, error, proc));
+            }
+        }
+
+        String diagnosticOutputZip = diagnosticProbe.lastMatchingLine.substring(diagnosticProbe.substring.length()).trim();
+
+        List<String> dumpPathEntries = Arrays.asList(dumpPath.list());
+
+        File zip = new File(diagnosticOutputZip).getAbsoluteFile();
+        Assert.assertTrue(zip.toString(), zip.exists());
+        Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
+        try {
+            int bgv = 0;
+            int cfg = 0;
+            ZipFile dd = new ZipFile(diagnosticOutputZip);
+            List<String> entries = new ArrayList<>();
+            for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) {
+                ZipEntry ze = e.nextElement();
+                String name = ze.getName();
+                entries.add(name);
+                if (name.endsWith(".bgv")) {
+                    bgv++;
+                } else if (name.endsWith(".cfg")) {
+                    cfg++;
+                }
+            }
+            if (bgv == 0) {
+                Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
+            }
+            if (cfg == 0) {
+                Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries));
+            }
+        } finally {
+            zip.delete();
+            dumpPath.delete();
+        }
+    }
+}