src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java
author erikj
Tue, 12 Sep 2017 19:03:39 +0200
changeset 47216 71c04702a3d5
parent 46963 hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java@089674d9949b
child 47798 9fe9292f5931
permissions -rw-r--r--
8187443: Forest Consolidation: Move files to unified layout Reviewed-by: darcy, ihse

/*
 * 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();
        }
    }
}