8059625: JEP-JDK-8043304: Test task: DTrace- tests for segmented codecache feature
authordpochepk
Thu, 25 Dec 2014 15:57:38 +0300
changeset 28392 f64a0abbff20
parent 28391 899a849e55f8
child 28393 18701d7781e7
8059625: JEP-JDK-8043304: Test task: DTrace- tests for segmented codecache feature Reviewed-by: sspitsyn, twisti, fzhinkin, iignatyev
hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java
hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTestScript.d
hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTestWorker.java
hotspot/test/compiler/testlibrary/CompilerUtils.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dtrace/DtraceResultsAnalyzer.java
hotspot/test/testlibrary/com/oracle/java/testlibrary/dtrace/DtraceRunner.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTest.java	Thu Dec 25 15:57:38 2014 +0300
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.Utils;
+import com.oracle.java.testlibrary.dtrace.DtraceResultsAnalyzer;
+import com.oracle.java.testlibrary.dtrace.DtraceRunner;
+import java.io.IOException;
+import java.lang.reflect.Executable;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/*
+ * @test SegmentedCodeCacheDtraceTest
+ * @bug 8015774
+ * @requires os.family=="solaris"
+ * @library /testlibrary /compiler/testlibrary /../../test/lib
+ * @build SegmentedCodeCacheDtraceTestWorker
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ *     sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+TieredCompilation
+ *     -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *     SegmentedCodeCacheDtraceTest
+ * @summary testing of dtrace for segmented code cache
+ */
+public class SegmentedCodeCacheDtraceTest {
+
+    private static final String WORKER_CLASS_NAME
+            = SegmentedCodeCacheDtraceTestWorker.class.getName();
+    private static final String JAVA_OPTS = " -XX:+DTraceMethodProbes "
+            + "-Xbootclasspath/a:" + System.getProperty("test.classes") + " "
+            + "-XX:+UnlockDiagnosticVMOptions "
+            + "-XX:+WhiteBoxAPI -XX:+SegmentedCodeCache "
+            + "-XX:CompileCommand=compileonly,"
+            + WORKER_CLASS_NAME + "::* "
+            + " -classpath " + System.getProperty("test.class.path") + " "
+            + String.join(" ", Utils.getTestJavaOpts());
+    private static final String DTRACE_SCRIPT
+            = "SegmentedCodeCacheDtraceTestScript.d";
+    private static final List<Executable> MLIST =
+            SegmentedCodeCacheDtraceTestWorker.TESTED_METHODS_LIST;
+    private static final int WORKER_METHODS_COUNT = MLIST.size();
+
+    private void runTest(TestCombination tc) {
+        String params = MLIST.stream()
+                .map(Executable::getName)
+                .map(x -> tc.data.get(x).compileLevel + " " + tc.data.get(x).isInlined)
+                .collect(Collectors.joining(" "));
+        DtraceRunner runner = new DtraceRunner();
+        runner.runDtrace(JDKToolFinder.getTestJDKTool("java"), JAVA_OPTS,
+                WORKER_CLASS_NAME, params, Paths.get(System.getProperty("test.src"),
+                        DTRACE_SCRIPT).toString(),
+                DtraceRunner.PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION,
+                new SegmentedCodeCacheDtraceResultsAnalyzer());
+    }
+
+    private static TestCombination generateUniqueCombination(
+            int[] availableLevels, Set<TestCombination> combinations) {
+        int len = availableLevels.length;
+        /* first, check if we're out of combinations. */
+        int maxCombinationsCount
+                = (1 << WORKER_METHODS_COUNT)
+                * (int) Math.pow(len, WORKER_METHODS_COUNT);
+        if (combinations.size() == maxCombinationsCount) {
+            return null;
+        }
+        Random r = Utils.getRandomInstance();
+        while (combinations.size() < maxCombinationsCount) {
+            int levels[] = new int[WORKER_METHODS_COUNT];
+            boolean inlines[] = new boolean[WORKER_METHODS_COUNT];
+            for (int i = 0; i < WORKER_METHODS_COUNT; i++) {
+                levels[i] = availableLevels[r.nextInt(len)];
+                inlines[i] = r.nextBoolean();
+            }
+            TestCombination tc = new TestCombination(levels, inlines);
+            if (combinations.add(tc)) {
+                return tc;
+            }
+        }
+        return null;
+    }
+
+    public static void main(String args[]) {
+        int iterations
+                = Integer.getInteger("com.oracle.java.testlibrary.iterations", 1);
+        if (!DtraceRunner.dtraceAvailable()) {
+            System.out.println("INFO: There is no dtrace avaiable. Skipping.");
+            return;
+        }
+        int[] availableLevels = CompilerUtils.getAvailableCompilationLevels();
+        // adding one more entry(zero) for interpeter
+        availableLevels
+                = Arrays.copyOf(availableLevels, availableLevels.length + 1);
+        Set<TestCombination> combinations = new HashSet<>();
+        for (int i = 0; i < iterations; i++) {
+            TestCombination tc
+                    = generateUniqueCombination(availableLevels, combinations);
+            if (tc == null) {
+                System.out.println("INFO: no more combinations available");
+                return;
+            } else {
+                System.out.println("INFO: Running testcase for: " + tc);
+                new SegmentedCodeCacheDtraceTest().runTest(tc);
+            }
+        }
+    }
+
+    private static class MethodData {
+
+        public final int compileLevel;
+        public final boolean isInlined;
+        public final String name;
+
+        public MethodData(String name, int compileLevel, boolean isInlined) {
+            this.name = name;
+            this.compileLevel = compileLevel;
+            this.isInlined = isInlined;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == null || !(o instanceof MethodData)) {
+                return false;
+            }
+            MethodData md = (MethodData) o;
+            return md.compileLevel == compileLevel
+                    && md.isInlined == isInlined
+                    && md.name.equals(name);
+        }
+
+        @Override
+        public int hashCode() {
+            return 100 * name.hashCode() + 10 * compileLevel + (isInlined ? 1 : 0);
+        }
+
+        @Override
+        public String toString() {
+            return name + " " + compileLevel + " " + isInlined;
+        }
+    }
+
+    private static class TestCombination {
+
+        private final Map<String, MethodData> data;
+
+        public TestCombination(int compLevels[], boolean inlines[]) {
+            Map<String, MethodData> d = new HashMap<>();
+            for (int i = 0; i < MLIST.size(); i++) {
+                d.put(MLIST.get(i).getName(), new MethodData(MLIST.get(i).getName(),
+                        compLevels[i], inlines[i]));
+            }
+            data = Collections.unmodifiableMap(d);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == null || !(o instanceof TestCombination)) {
+                return false;
+            }
+            TestCombination second = (TestCombination) o;
+            return second.data.equals(data);
+        }
+
+        @Override
+        public int hashCode() {
+            int sum = 0;
+            for (MethodData md : data.values()) {
+                sum += md.hashCode();
+            }
+            return sum;
+        }
+
+        private String getMethodDescString(MethodData md) {
+            return (md == null)
+                    ? null
+                    : String.format("Method %s compilation level %d and %s",
+                            md.name, md.compileLevel,
+                            md.isInlined ? "inlined" : "not inlined");
+        }
+
+        @Override
+        public String toString() {
+            return data.values().stream().map(m -> getMethodDescString(m))
+                    .collect(Collectors.joining(Utils.NEW_LINE,
+                                    "Combination: ", ""));
+        }
+    }
+
+    private class SegmentedCodeCacheDtraceResultsAnalyzer
+            implements DtraceResultsAnalyzer {
+
+        private static final int EXPECTED_MATCH_COUNT = 2;
+
+        private final Pattern checkPattern;
+
+        public SegmentedCodeCacheDtraceResultsAnalyzer() {
+            String workerClassRegExp = "\\s*" + WORKER_CLASS_NAME + "\\.";
+            String delimeter = "\\(\\)V\\*?" + workerClassRegExp;
+            String suffix = "test\\(\\)V\\*?" + workerClassRegExp
+                    + "main\\(\\[Ljava\\/lang\\/String;\\)V";
+            StringBuilder sb = new StringBuilder(workerClassRegExp);
+            // method order is important, so, going from list tail to head,
+            // accoring to call order representation in stacktrace
+            for (int i = MLIST.size() - 1; i > -1; i--) {
+                sb.append(MLIST.get(i).getName()).append(delimeter);
+            }
+            sb.append(suffix);
+            checkPattern = Pattern.compile(sb.toString());
+            /* such pattern match should pass on a stacktrace like
+             CPU     ID                    FUNCTION:NAME
+             0  53573 __1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_:method-entry ustack:
+
+             libjvm.so`__1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_+0x39c
+             SegmentedCodeCacheDtraceTestWorker.baz()V*
+             SegmentedCodeCacheDtraceTestWorker.bar()V
+             SegmentedCodeCacheDtraceTestWorker.foo()V*
+             SegmentedCodeCacheDtraceTestWorker.test()V
+             SegmentedCodeCacheDtraceTestWorker.main([Ljava/lang/String;)V
+             0xffffffff6b0004b8
+             libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x94c
+             libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_+0xa64
+             libjvm.so`jni_CallStaticVoidMethod+0x508
+             libjli.so`JavaMain+0x584
+             libc.so.1`_lwp_start
+             jstack:
+
+             libjvm.so`__1cNSharedRuntimeTdtrace_method_entry6FpnKJavaThread_pnGMethod__i_+0x39c
+             SegmentedCodeCacheDtraceTestWorker.baz()V*
+             SegmentedCodeCacheDtraceTestWorker.bar()V
+             SegmentedCodeCacheDtraceTestWorker.foo()V*
+             SegmentedCodeCacheDtraceTestWorker.test()V
+             SegmentedCodeCacheDtraceTestWorker.main([Ljava/lang/String;)V
+             0xffffffff6b0004b8
+             libjvm.so`__1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x94c
+             libjvm.so`__1cRjni_invoke_static6FpnHJNIEnv__pnJJavaValue_pnI_jobject_nLJNICallType_pnK_jmethodID_pnSJNI_ArgumentPusher_pnGThread__v_+0xa64
+             libjvm.so`jni_CallStaticVoidMethod+0x508
+             libjli.so`JavaMain+0x584
+             libc.so.1`_lwp_start
+             */
+        }
+
+        protected List<String> loadLog(String dtraceOutFile) throws IOException {
+            return Files.readAllLines(Paths.get(dtraceOutFile));
+        }
+
+        @Override
+        public void analyze(OutputAnalyzer oa, String dtraceOutFilePath) {
+            oa.shouldHaveExitValue(0);
+            List<String> dOut;
+            try {
+                dOut = loadLog(dtraceOutFilePath);
+            } catch (IOException e) {
+                throw new Error("Can't load log", e);
+            }
+            StringBuilder allDtraceOutput = new StringBuilder();
+            for (String entry : dOut) {
+                allDtraceOutput.append(entry);
+            }
+            int matchCount = getMatchCount(allDtraceOutput.toString());
+            Asserts.assertEQ(matchCount, EXPECTED_MATCH_COUNT,
+                    "Unexpected output match amount. expected: "
+                    + EXPECTED_MATCH_COUNT + " but found " + matchCount);
+        }
+
+        protected int getMatchCount(String source) {
+            Matcher m = checkPattern.matcher(source);
+            int matchCount = 0;
+            while (m.find()) {
+                matchCount++;
+            }
+            return matchCount;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTestScript.d	Thu Dec 25 15:57:38 2014 +0300
@@ -0,0 +1,33 @@
+#!/usr/sbin/dtrace -s
+
+/*
+ Copyright (c) 2014, 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.
+*/
+ 
+hotspot$target:::method-entry
+/ copyinstr(arg3, arg4) == "baz" /
+{
+    printf("ustack:\n");
+    ustack(50, 500);
+    printf("jstack:\n");
+    jstack();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/codecache/dtrace/SegmentedCodeCacheDtraceTestWorker.java	Thu Dec 25 15:57:38 2014 +0300
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import com.oracle.java.testlibrary.Utils;
+import java.lang.reflect.Executable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import sun.hotspot.WhiteBox;
+
+public class SegmentedCodeCacheDtraceTestWorker {
+
+    private static final String METHOD1_NAME = "foo";
+    private static final String METHOD2_NAME = "bar";
+    private static final String METHOD3_NAME = "baz";
+    public static final List<Executable> TESTED_METHODS_LIST;
+    private final WhiteBox wb;
+    private final int compLevels[];
+
+    static {
+        List<Executable> methods = new ArrayList<>();
+        try {
+            // method order is important. Need to place methods in call order,
+            // to be able to verify results later
+            methods.add(SegmentedCodeCacheDtraceTestWorker.class.getMethod(METHOD1_NAME));
+            methods.add(SegmentedCodeCacheDtraceTestWorker.class.getMethod(METHOD2_NAME));
+            methods.add(SegmentedCodeCacheDtraceTestWorker.class.getMethod(METHOD3_NAME));
+        } catch (NoSuchMethodException e) {
+            throw new Error("TESTBUG: no expected method found", e);
+        }
+        TESTED_METHODS_LIST = Collections.unmodifiableList(methods);
+    }
+
+    protected static final boolean BACKGROUND_COMPILATION
+            = WhiteBox.getWhiteBox().getBooleanVMFlag("BackgroundCompilation");
+
+    public static void main(String[] args) {
+        if (args.length != 2 * TESTED_METHODS_LIST.size()) {
+            throw new Error("Usage: java <thisClass> <fooCompLevel> <fooInlined>"
+                    + "<barCompLevel> <barInlined> "
+                    + "<bazCompLevel> <bazInlined>");
+        } else {
+            int compLevels[] = new int[TESTED_METHODS_LIST.size()];
+            boolean inlines[] = new boolean[TESTED_METHODS_LIST.size()];
+            for (int i = 0; i < TESTED_METHODS_LIST.size(); i++) {
+                compLevels[i] = Integer.parseInt(args[2 * i]);
+                inlines[i] = Boolean.parseBoolean(args[2 * i + 1]);
+            }
+            new SegmentedCodeCacheDtraceTestWorker(compLevels, inlines).test();
+        }
+    }
+
+    public SegmentedCodeCacheDtraceTestWorker(int compLevels[], boolean inlines[]) {
+        wb = WhiteBox.getWhiteBox();
+        this.compLevels = Arrays.copyOf(compLevels, compLevels.length);
+        for (int i = 0; i < compLevels.length; i++) {
+            if (inlines[i]) {
+                wb.testSetForceInlineMethod(TESTED_METHODS_LIST.get(i), true);
+            } else {
+                wb.testSetDontInlineMethod(TESTED_METHODS_LIST.get(i), true);
+            }
+        }
+    }
+
+    private void waitForCompilation(Executable executable, int compLevel) {
+        if (compLevel > 0) {
+            Utils.waitForCondition(() -> wb.isMethodCompiled(executable));
+        }
+    }
+
+    protected void test() {
+        for (int i = 0; i < TESTED_METHODS_LIST.size(); i++) {
+            Executable method = TESTED_METHODS_LIST.get(i);
+            int compLevel = compLevels[i];
+            wb.enqueueMethodForCompilation(method, compLevel);
+            waitForCompilation(method, compLevel);
+        }
+        foo();
+    }
+
+    public static void foo() {
+        bar();
+    }
+
+    public static void bar() {
+        baz();
+    }
+
+    public static void baz() {
+        System.out.println("Reached baz method");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/testlibrary/CompilerUtils.java	Thu Dec 25 15:57:38 2014 +0300
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.Platform;
+import java.util.stream.IntStream;
+import sun.hotspot.WhiteBox;
+
+public class CompilerUtils {
+
+    private CompilerUtils() {
+        // to prevent from instantiation
+    }
+
+    /**
+     * Returns available compilation levels
+     *
+     * @return int array with compilation levels
+     */
+    public static int[] getAvailableCompilationLevels() {
+        if (!WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompiler")) {
+            return new int[0];
+        }
+        if (WhiteBox.getWhiteBox().getBooleanVMFlag("TieredCompilation")) {
+            Long flagValue = WhiteBox.getWhiteBox()
+                    .getIntxVMFlag("TieredStopAtLevel");
+            int maxLevel = flagValue.intValue();
+            Asserts.assertEQ(new Long(maxLevel), flagValue,
+                    "TieredStopAtLevel has value out of int capacity");
+            return IntStream.rangeClosed(1, maxLevel).toArray();
+        } else {
+            if (Platform.isServer()) {
+                return new int[]{4};
+            }
+            if (Platform.isClient() || Platform.isMinimal()) {
+                return new int[]{1};
+            }
+        }
+        return new int[0];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dtrace/DtraceResultsAnalyzer.java	Thu Dec 25 15:57:38 2014 +0300
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.java.testlibrary.dtrace;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public interface DtraceResultsAnalyzer {
+    public void analyze(OutputAnalyzer oa, String logFilePath);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/dtrace/DtraceRunner.java	Thu Dec 25 15:57:38 2014 +0300
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.java.testlibrary.dtrace;
+
+import com.oracle.java.testlibrary.Asserts;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DtraceRunner {
+
+    private static final String DTRACE_DEFAULT_PATH = "/usr/sbin/dtrace";
+    private static final String DTRACE_PATH_PROPERTY
+            = "com.oracle.test.dtrace.path";
+    private static final String OUTPUT_FILE_DTRACE_OPTION = "o";
+    private static final String RUN_COMMAND_DTRACE_OPTION = "c";
+    private static final String RUN_SCRIPT_DTRACE_OPTION = "s";
+    private static final String ALLOW_ZERO_PROBE_DESCRIPTION_DTRACE_OPTION = "Z";
+    private static final String DTRACE_OPTION_PREFIX = "-";
+    public static final String PERMIT_DESTRUCTIVE_ACTIONS_DTRACE_OPTION = "w";
+    public static final String DTRACE_OUT_LOG = "dtrace.out";
+
+    private final String dtraceExecutable;
+
+    public DtraceRunner() {
+        dtraceExecutable = getDtracePath();
+    }
+
+    private List<String> getLaunchCmd(String java, String javaOpts,
+            String execClass, String testArgs, String dtraceScript,
+            String dtraceAddOpts) {
+        Asserts.assertTrue(!java.matches("\\s"), "Current dtrace implementation"
+                + " can't handle whitespaces in application path");
+        List<String> result = new ArrayList<>();
+        result.add(dtraceExecutable);
+        result.add(DTRACE_OPTION_PREFIX + System.getProperty("sun.arch.data.model"));
+        result.add(DTRACE_OPTION_PREFIX
+                + ALLOW_ZERO_PROBE_DESCRIPTION_DTRACE_OPTION
+                + ((dtraceAddOpts == null) ? "" : dtraceAddOpts)
+                + RUN_SCRIPT_DTRACE_OPTION); // run_script should be last one
+        result.add(dtraceScript);
+        result.add(DTRACE_OPTION_PREFIX + OUTPUT_FILE_DTRACE_OPTION);
+        result.add(DTRACE_OUT_LOG);
+        result.add(DTRACE_OPTION_PREFIX + RUN_COMMAND_DTRACE_OPTION);
+        result.add(java + " " + javaOpts + " " + execClass + " " + testArgs);
+        return result;
+    }
+
+    private void backupLogFile(File file) {
+        if (file.exists()) {
+            file.renameTo(new File(file.getPath() + ".bak"));
+        }
+    }
+
+    public void runDtrace(String java, String javaOpts, String execClass,
+            String testArgs, String dtraceScript, String dtraceAddOpts,
+            DtraceResultsAnalyzer analyzer) {
+        backupLogFile(new File(DTRACE_OUT_LOG));
+        ProcessBuilder pbuilder = new ProcessBuilder(
+                getLaunchCmd(java, javaOpts, execClass, testArgs,
+                        dtraceScript, dtraceAddOpts));
+        OutputAnalyzer oa;
+        try {
+            oa = new OutputAnalyzer(pbuilder.start());
+        } catch (IOException e) {
+            throw new Error("TESTBUG: Can't start process", e);
+        }
+        analyzer.analyze(oa, DTRACE_OUT_LOG);
+    }
+
+    public static boolean dtraceAvailable() {
+        String path = getDtracePath();
+        if (path == null) {
+            return false;
+        }
+        // now we'll launch dtrace to trace itself just to be sure it works
+        // and have all additional previleges set
+        ProcessBuilder pbuilder = new ProcessBuilder(path, path);
+        try {
+            OutputAnalyzer oa = new OutputAnalyzer(pbuilder.start());
+            if (oa.getExitValue() != 0) {
+                return false;
+            }
+        } catch (IOException e) {
+            throw new Error("Couldn't launch dtrace", e);
+        }
+        return true;
+    }
+
+    private static String getDtracePath() {
+        String propPath = System.getProperty(DTRACE_PATH_PROPERTY);
+        if (propPath != null && new File(propPath).exists()) {
+            return propPath;
+        } else if (new File(DTRACE_DEFAULT_PATH).exists()) {
+            return DTRACE_DEFAULT_PATH;
+        }
+        return null;
+    }
+}