From bf8db38250af9435a13dde822df22c3aee6dc2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Shipil=C3=ABv?= Date: Thu, 8 Jun 2023 11:16:38 +0200 Subject: [PATCH] 7903487: JMH: Make sure JMH profilers work on all tested configurations --- .github/workflows/pre-integration.yml | 7 ++ .../java/org/openjdk/jmh/it/Fixtures.java | 3 + .../it/profilers/AbstractAsmProfilerTest.java | 70 +++++++++++ .../it/profilers/ClassloadProfilerTest.java | 102 ++++++++++++++++ .../it/profilers/CompilerProfilerTest.java | 78 ++++++++++++ .../it/profilers/DTraceAsmProfilerTest.java | 65 ++++++++++ .../it/profilers/GCProfilerAllocRateTest.java | 4 +- .../GCProfilerSeparateThreadTest.java | 2 +- .../JavaFlightRecorderProfilerTest.java | 62 ++++++++++ .../profilers/LinuxPerfAsmProfilerTest.java | 65 ++++++++++ .../profilers/LinuxPerfC2CProfilerTest.java | 80 ++++++++++++ .../profilers/LinuxPerfNormProfilerTest.java | 95 +++++++++++++++ .../it/profilers/LinuxPerfProfilerTest.java | 91 ++++++++++++++ .../jmh/it/profilers/MemPoolProfilerTest.java | 90 ++++++++++++++ .../jmh/it/profilers/ProfilerTestUtils.java | 53 ++++++++ .../it/profilers/SafepointsProfilerTest.java | 115 ++++++++++++++++++ .../jmh/it/profilers/StackProfilerTest.java | 78 ++++++++++++ .../it/profilers/WinPerfAsmProfilerTest.java | 65 ++++++++++ .../jmh/profile/DTraceAsmProfiler.java | 2 +- .../jmh/profile/LinuxPerfAsmProfiler.java | 11 +- .../jmh/profile/LinuxPerfC2CProfiler.java | 5 + .../jmh/profile/LinuxPerfNormProfiler.java | 29 ++++- .../openjdk/jmh/profile/MemPoolProfiler.java | 2 +- .../org/openjdk/jmh/profile/PerfSupport.java | 11 ++ .../main/java/org/openjdk/jmh/util/Utils.java | 4 + 25 files changed, 1177 insertions(+), 12 deletions(-) create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/AbstractAsmProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ClassloadProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/CompilerProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/DTraceAsmProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/JavaFlightRecorderProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfAsmProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfC2CProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfNormProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/MemPoolProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTestUtils.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/SafepointsProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/StackProfilerTest.java create mode 100644 jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/WinPerfAsmProfilerTest.java diff --git a/.github/workflows/pre-integration.yml b/.github/workflows/pre-integration.yml index 7410e71f7..7ec1069bb 100644 --- a/.github/workflows/pre-integration.yml +++ b/.github/workflows/pre-integration.yml @@ -32,6 +32,13 @@ jobs: java-version: ${{ matrix.java }} cache: maven check-latest: true + - name: Set up perf (Linux) + run: | + sudo apt-get update + sudo apt-get install -y linux-tools-common linux-tools-generic linux-tools-`uname -r` + echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid + perf stat echo 1 + if: (runner.os == 'Linux') - name: Run build with tests (Default) run: mvn clean install -P ${{ matrix.profile }} -B --file pom.xml diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/Fixtures.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/Fixtures.java index 23731ab5f..b5c3ab849 100644 --- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/Fixtures.java +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/Fixtures.java @@ -71,4 +71,7 @@ public static boolean isDefaultProfile() { return PROFILE.equals("default"); } + public static boolean isVirtualExecutor() { + return PROFILE.contains("executor-virtual"); + } } diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/AbstractAsmProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/AbstractAsmProfilerTest.java new file mode 100644 index 000000000..7cd74d080 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/AbstractAsmProfilerTest.java @@ -0,0 +1,70 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.util.JDKVersion; + +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +@State(Scope.Thread) +public abstract class AbstractAsmProfilerTest { + + private static final int SIZE = 10_000; + + private byte[] src, dst; + + @Setup + public void setup() { + src = new byte[SIZE]; + dst = new byte[SIZE]; + } + + @Benchmark + public void work() { + // Call something that definitely results in calling a native stub. + // This should work on environments where hsdis is not available. + System.arraycopy(src, 0, dst, 0, SIZE); + } + + public static boolean checkDisassembly(String out) { + if (JDKVersion.parseMajor(System.getProperty("java.version")) >= 17) { + // Should always print, since abstract assembler is available + return out.contains("StubRoutines::"); + } else { + if (out.contains("StubRoutines::")) { + // hsdis is enabled, good + return true; + } else { + // hsdis is not enabled, okay + return out.contains(""); + } + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ClassloadProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ClassloadProfilerTest.java new file mode 100644 index 000000000..a48acfeaf --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ClassloadProfilerTest.java @@ -0,0 +1,102 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Assert; +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.ClassloaderProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class ClassloadProfilerTest { + + // Simplest Dummy class + static final byte[] CLASS = new byte[] { + (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe, + 0x00, 0x00, 0x00, 0x34, + 0x00, 0x0a, 0x0a, 0x00, 0x02, 0x00, 0x03, 0x07, + 0x00, 0x04, 0x0c, 0x00, 0x05, 0x00, 0x06, 0x01, + 0x00, 0x10, 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, + 0x61, 0x6e, 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x01, 0x00, 0x06, 0x3c, 0x69, 0x6e, + 0x69, 0x74, 0x3e, 0x01, 0x00, 0x03, 0x28, 0x29, + 0x56, 0x07, 0x00, 0x08, 0x01, 0x00, 0x05, 0x44, + 0x75, 0x6d, 0x6d, 0x79, 0x01, 0x00, 0x04, 0x43, + 0x6f, 0x64, 0x65, 0x00, 0x21, 0x00, 0x07, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x05, 0x00, 0x06, 0x00, 0x01, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x05, 0x2a, (byte) 0xb7, 0x00, + 0x01, (byte) 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + static class MyClassLoader extends ClassLoader { + public Class loadClass(String name) throws ClassNotFoundException { + if (name.equals("Dummy")) { + return defineClass(name, CLASS, 0, CLASS.length, null); + } else { + return super.loadClass(name); + } + } + } + + @Benchmark + public Class work() throws Exception { + Fixtures.work(); + ClassLoader loader = new MyClassLoader(); + return Class.forName("Dummy", true, loader); + } + + @Test + public void test() throws RunnerException { + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(ClassloaderProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + double classLoad = ProfilerTestUtils.checkedGet(sr, "·class.load.norm").getScore(); + + // Allow 5% slack + if (Math.abs(1 - classLoad) > 0.05) { + Assert.fail("Class loading rate is incorrect. Reported by profiler: " + classLoad); + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/CompilerProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/CompilerProfilerTest.java new file mode 100644 index 000000000..3d19df700 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/CompilerProfilerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.CompilerProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class CompilerProfilerTest { + + @Benchmark + public void work() { + Fixtures.work(); + } + + @Test + public void test() throws RunnerException { + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(CompilerProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + double timeTotal = ProfilerTestUtils.checkedGet(sr, "·compiler.time.total").getScore(); + double timeProfiled = ProfilerTestUtils.checkedGet(sr, "·compiler.time.profiled").getScore(); + + if (timeProfiled > timeTotal) { + throw new IllegalStateException("Profiled time is larger than total time. " + + "Total: " + timeTotal + ", Profiled: " + timeProfiled); + } + + if (timeProfiled <= 0) { + throw new IllegalStateException("Should have profiled time: " + timeProfiled); + } + + if (timeTotal <= 0) { + throw new IllegalStateException("Should have total time: " + timeTotal); + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/DTraceAsmProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/DTraceAsmProfilerTest.java new file mode 100644 index 000000000..6c21d981e --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/DTraceAsmProfilerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.DTraceAsmProfiler; +import org.openjdk.jmh.profile.ProfilerException; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; + +public class DTraceAsmProfilerTest extends AbstractAsmProfilerTest { + + @Test + public void test() throws RunnerException { + try { + new DTraceAsmProfiler(""); + } catch (ProfilerException e) { + System.out.println("Profiler is not supported or cannot be enabled, skipping test"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(DTraceAsmProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + String out = ProfilerTestUtils.checkedGet(sr, "·asm").extendedInfo(); + if (!checkDisassembly(out)) { + throw new IllegalStateException("Profile does not contain the required frame: " + out); + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerAllocRateTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerAllocRateTest.java index 4395af8b6..4d543ee6b 100644 --- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerAllocRateTest.java +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerAllocRateTest.java @@ -84,8 +84,8 @@ private void testWith(String initLine) throws RunnerException { double opsPerSec = rr.getPrimaryResult().getScore(); Map sr = rr.getSecondaryResults(); - double allocRateMB = sr.get("·gc.alloc.rate").getScore(); - double allocRateNormB = sr.get("·gc.alloc.rate.norm").getScore(); + double allocRateMB = ProfilerTestUtils.checkedGet(sr, "·gc.alloc.rate").getScore(); + double allocRateNormB = ProfilerTestUtils.checkedGet(sr, "·gc.alloc.rate.norm").getScore(); double allocRatePrimaryMB = opsPerSec * allocRateNormB / 1024 / 1024; // Allow 20% slack diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerSeparateThreadTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerSeparateThreadTest.java index 6a42a377a..a10f9f4e9 100644 --- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerSeparateThreadTest.java +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/GCProfilerSeparateThreadTest.java @@ -67,7 +67,7 @@ public void testDefault() throws RunnerException { RunResult rr = new Runner(opts).runSingle(); Map sr = rr.getSecondaryResults(); - double allocRateNormB = sr.get("·gc.alloc.rate.norm").getScore(); + double allocRateNormB = ProfilerTestUtils.checkedGet(sr, "·gc.alloc.rate.norm").getScore(); String msg = "Reported by profiler: " + allocRateNormB + ", target: " + SIZE; diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/JavaFlightRecorderProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/JavaFlightRecorderProfilerTest.java new file mode 100644 index 000000000..d2641cb55 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/JavaFlightRecorderProfilerTest.java @@ -0,0 +1,62 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.CompilerProfiler; +import org.openjdk.jmh.profile.JavaFlightRecorderProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class JavaFlightRecorderProfilerTest { + + @Benchmark + public void work() { + Fixtures.work(); + } + + @Test + public void test() throws RunnerException { + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(JavaFlightRecorderProfiler.class) + .build(); + + new Runner(opts).runSingle(); + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfAsmProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfAsmProfilerTest.java new file mode 100644 index 000000000..0964fe687 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfAsmProfilerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.LinuxPerfAsmProfiler; +import org.openjdk.jmh.profile.ProfilerException; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; + +public class LinuxPerfAsmProfilerTest extends AbstractAsmProfilerTest { + + @Test + public void test() throws RunnerException { + try { + new LinuxPerfAsmProfiler(""); + } catch (ProfilerException e) { + System.out.println("Profiler is not supported or cannot be enabled, skipping test"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(LinuxPerfAsmProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + String out = ProfilerTestUtils.checkedGet(sr, "·asm").extendedInfo(); + if (!checkDisassembly(out)) { + throw new IllegalStateException("Profile does not contain the required frame: " + out); + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfC2CProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfC2CProfilerTest.java new file mode 100644 index 000000000..1dbef346a --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfC2CProfilerTest.java @@ -0,0 +1,80 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Assert; +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.LinuxPerfC2CProfiler; +import org.openjdk.jmh.profile.ProfilerException; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class LinuxPerfC2CProfilerTest { + + @Benchmark + public void work() { + somethingInTheMiddle(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void somethingInTheMiddle() { + Fixtures.work(); + } + + @Test + public void test() throws RunnerException { + try { + new LinuxPerfC2CProfiler(); + } catch (ProfilerException e) { + System.out.println("Profiler is not supported or cannot be enabled, skipping test"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(LinuxPerfC2CProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + String text = ProfilerTestUtils.checkedGet(sr, "·perfc2c").extendedInfo(); + + Assert.assertNotNull(text); + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfNormProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfNormProfilerTest.java new file mode 100644 index 000000000..a1fc91552 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfNormProfilerTest.java @@ -0,0 +1,95 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Assert; +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.LinuxPerfNormProfiler; +import org.openjdk.jmh.profile.ProfilerException; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class LinuxPerfNormProfilerTest { + + @Benchmark + public void work() { + somethingInTheMiddle(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void somethingInTheMiddle() { + Blackhole.consumeCPU(1); + } + + @Test + public void test() throws RunnerException { + try { + new LinuxPerfNormProfiler(""); + } catch (ProfilerException e) { + System.out.println("Profiler is not supported or cannot be enabled, skipping test"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(LinuxPerfNormProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + double instructions = ProfilerTestUtils.checkedGet(sr, "instructions", "instructions:u").getScore(); + double cycles = ProfilerTestUtils.checkedGet(sr, "cycles", "cycles:u").getScore(); + double branches = ProfilerTestUtils.checkedGet(sr, "branches", "branches:u").getScore(); + + Assert.assertNotEquals(0, instructions); + Assert.assertNotEquals(0, cycles); + Assert.assertNotEquals(0, branches); + + if (branches > instructions) { + throw new IllegalStateException(String.format("Branches (%.2f) larger than instructions (%.3f)", branches, instructions)); + } + + double ipc = ProfilerTestUtils.checkedGet(sr, "IPC").getScore(); + double cpi = ProfilerTestUtils.checkedGet(sr, "CPI").getScore(); + + Assert.assertNotEquals(0, ipc); + Assert.assertNotEquals(0, cpi); + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfProfilerTest.java new file mode 100644 index 000000000..e713bc52e --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/LinuxPerfProfilerTest.java @@ -0,0 +1,91 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Assert; +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.LinuxPerfAsmProfiler; +import org.openjdk.jmh.profile.LinuxPerfProfiler; +import org.openjdk.jmh.profile.ProfilerException; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class LinuxPerfProfilerTest { + + @Benchmark + public void work() { + somethingInTheMiddle(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void somethingInTheMiddle() { + Blackhole.consumeCPU(1); + } + + @Test + public void test() throws RunnerException { + try { + new LinuxPerfProfiler(""); + } catch (ProfilerException e) { + System.out.println("Profiler is not supported or cannot be enabled, skipping test"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(LinuxPerfProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + String msg = ProfilerTestUtils.checkedGet(sr, "·perf").extendedInfo(); + + if (sr.containsKey("·ipc")) { + double ipc = ProfilerTestUtils.checkedGet(sr, "·ipc").getScore(); + double cpi = ProfilerTestUtils.checkedGet(sr, "·cpi").getScore(); + Assert.assertNotEquals(0, ipc); + Assert.assertNotEquals(0, cpi); + } + + Assert.assertTrue(msg.contains("cycles")); + Assert.assertTrue(msg.contains("instructions")); + Assert.assertTrue(msg.contains("branches")); + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/MemPoolProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/MemPoolProfilerTest.java new file mode 100644 index 000000000..3e6bc9877 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/MemPoolProfilerTest.java @@ -0,0 +1,90 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.CompilerProfiler; +import org.openjdk.jmh.profile.MemPoolProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class MemPoolProfilerTest { + + @Benchmark + public void work() { + Fixtures.work(); + } + + @Test + public void test() throws RunnerException { + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(MemPoolProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + + double usedMetaspace = ProfilerTestUtils.checkedGet(sr, "·mempool.Metaspace.used").getScore(); + double usedTotal = ProfilerTestUtils.checkedGet(sr, "·mempool.total.used").getScore(); + double usedTotalCodeheap = ProfilerTestUtils.checkedGet(sr, "·mempool.total.codeheap.used").getScore(); + + if (usedMetaspace == 0) { + throw new IllegalStateException("Metaspace used is zero"); + } + + if (usedTotal == 0) { + throw new IllegalStateException("Total used is zero"); + } + + if (usedTotalCodeheap == 0) { + throw new IllegalStateException("Total codeheap used is zero"); + } + + if (usedMetaspace > usedTotal) { + throw new IllegalStateException("Metaspace size is larger than total size. " + + "Total: " + usedTotal + ", Metaspace: " + usedMetaspace); + } + + if (usedTotalCodeheap > usedTotal) { + throw new IllegalStateException("Codeheap size is larger than total size. " + + "Total: " + usedTotal + ", Codeheap: " + usedTotalCodeheap); + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTestUtils.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTestUtils.java new file mode 100644 index 000000000..bf37cfab6 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTestUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014, 2015, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.openjdk.jmh.results.Result; + +import java.util.Arrays; +import java.util.Map; + +public class ProfilerTestUtils { + + public static Result checkedGet(Map sr, String... names) { + for (String name : names) { + Result r = sr.get(name); + if (r != null) { + return r; + } + } + + StringBuilder sb = new StringBuilder(); + for (String k : sr.keySet()) { + sb.append(k); + sb.append(" = "); + sb.append(sr.get(k)); + sb.append(System.lineSeparator()); + } + throw new IllegalStateException("Cannot find the result for " + Arrays.toString(names) + "\". Available entries: " + sb); + } + + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/SafepointsProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/SafepointsProfilerTest.java new file mode 100644 index 000000000..9b0868725 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/SafepointsProfilerTest.java @@ -0,0 +1,115 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Assert; +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.MemPoolProfiler; +import org.openjdk.jmh.profile.SafepointsProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(value = 1, jvmArgsAppend = {"-Xms1g", "-Xmx1g"}) +public class SafepointsProfilerTest { + + @Benchmark + public int[] allocate() { + return new int[1_000_000]; + } + + @Test + public void test() throws RunnerException { + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(SafepointsProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + + double interval = ProfilerTestUtils.checkedGet(sr, "·safepoints.interval").getScore(); + double pauseTotal = ProfilerTestUtils.checkedGet(sr, "·safepoints.pause").getScore(); + double ttspTotal = ProfilerTestUtils.checkedGet(sr, "·safepoints.ttsp").getScore(); + + double pauseCount = ProfilerTestUtils.checkedGet(sr, "·safepoints.pause.count").getScore(); + double ttspCount = ProfilerTestUtils.checkedGet(sr, "·safepoints.ttsp.count").getScore(); + + Assert.assertNotEquals(pauseTotal, 0); + Assert.assertNotEquals(ttspTotal, 0); + + Assert.assertNotEquals(pauseCount, 0); + Assert.assertNotEquals(ttspCount, 0); + Assert.assertEquals(ttspCount, pauseCount, 0); + + if (interval < 3000) { + throw new IllegalStateException("Interval time is too low. " + + " Interval: " + interval); + } + + if (ttspTotal > interval) { + throw new IllegalStateException("TTSP time is larger than interval time. " + + "TTSP: " + ttspTotal + ", Interval: " + interval); + } + + if (pauseTotal > interval) { + throw new IllegalStateException("Pause time is larger than interval time. " + + "Pause: " + pauseTotal + ", Interval: " + interval); + } + + if (ttspTotal > pauseTotal) { + throw new IllegalStateException("TTSP time is larger than pause time. " + + "TTSP: " + ttspTotal + ", Pause: " + pauseTotal); + } + + double lastPause = 0; + double lastTTSP = 0; + for (String suff : new String[] {"0.00", "0.50", "0.90", "0.95", "0.99", "0.999", "0.9999", "1.00"}) { + double curPause = ProfilerTestUtils.checkedGet(sr, "·safepoints.pause.p" + suff).getScore(); + double curTTSP = ProfilerTestUtils.checkedGet(sr, "·safepoints.ttsp.p" + suff).getScore(); + if (curPause < lastPause) { + throw new IllegalStateException("pause.p" + suff + " is not monotonic"); + } + if (curTTSP < lastTTSP) { + throw new IllegalStateException("ttsp.p" + suff + " is not monotonic"); + } + lastPause = curPause; + lastTTSP = curTTSP; + } + + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/StackProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/StackProfilerTest.java new file mode 100644 index 000000000..990e23689 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/StackProfilerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.JavaFlightRecorderProfiler; +import org.openjdk.jmh.profile.StackProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS) +@Fork(1) +public class StackProfilerTest { + + @Benchmark + public void work() { + somethingInTheMiddle(); + } + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public void somethingInTheMiddle() { + Fixtures.work(); + } + + @Test + public void test() throws RunnerException { + if (Fixtures.isVirtualExecutor()) { + System.out.println("Stack profiler is not reliable with virtual threads"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(StackProfiler.class, "lines=10") + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + String out = ProfilerTestUtils.checkedGet(sr, "·stack").extendedInfo(); + if (!out.contains(StackProfilerTest.class.getCanonicalName() + ".somethingInTheMiddle")) { + throw new IllegalStateException("Profile does not contain the required frame: " + out); + } + } + +} diff --git a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/WinPerfAsmProfilerTest.java b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/WinPerfAsmProfilerTest.java new file mode 100644 index 000000000..b64449161 --- /dev/null +++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/WinPerfAsmProfilerTest.java @@ -0,0 +1,65 @@ +/* + * Copyright Amazon.com Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.openjdk.jmh.it.profilers; + +import org.junit.Test; +import org.openjdk.jmh.it.Fixtures; +import org.openjdk.jmh.profile.ProfilerException; +import org.openjdk.jmh.profile.WinPerfAsmProfiler; +import org.openjdk.jmh.results.Result; +import org.openjdk.jmh.results.RunResult; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +import java.util.Map; + +public class WinPerfAsmProfilerTest extends AbstractAsmProfilerTest { + + @Test + public void test() throws RunnerException { + try { + new WinPerfAsmProfiler(""); + } catch (ProfilerException e) { + System.out.println("Profiler is not supported or cannot be enabled, skipping test"); + return; + } + + Options opts = new OptionsBuilder() + .include(Fixtures.getTestMask(this.getClass())) + .addProfiler(WinPerfAsmProfiler.class) + .build(); + + RunResult rr = new Runner(opts).runSingle(); + + Map sr = rr.getSecondaryResults(); + String out = ProfilerTestUtils.checkedGet(sr, "·asm").extendedInfo(); + if (!checkDisassembly(out)) { + throw new IllegalStateException("Profile does not contain the required frame: " + out); + } + } + +} diff --git a/jmh-core/src/main/java/org/openjdk/jmh/profile/DTraceAsmProfiler.java b/jmh-core/src/main/java/org/openjdk/jmh/profile/DTraceAsmProfiler.java index fbb0d4d7e..f4c8388fa 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/profile/DTraceAsmProfiler.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/DTraceAsmProfiler.java @@ -94,7 +94,7 @@ public Collection afterTrial(BenchmarkResult br, long pid, Fil throw new IllegalStateException("Cannot determine dtrace process PID"); } - Collection messages = Utils.tryWith("sudo", "kill", "-TERM", Long.toString(dtracePid)); + Collection messages = Utils.tryWith("sudo", "-n", "kill", "-TERM", Long.toString(dtracePid)); if (!messages.isEmpty()) { throw new IllegalStateException(messages.toString()); } diff --git a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfAsmProfiler.java b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfAsmProfiler.java index fa383c673..c948532f2 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfAsmProfiler.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfAsmProfiler.java @@ -46,11 +46,20 @@ public class LinuxPerfAsmProfiler extends AbstractPerfAsmProfiler { public LinuxPerfAsmProfiler(String initLine) throws ProfilerException { super(initLine, "cycles"); - Collection failMsg = Utils.tryWith(PerfSupport.PERF_EXEC, "stat", "--log-fd", "2", "echo", "1"); + String[] senseCmd = { PerfSupport.PERF_EXEC, "stat", "--event", Utils.join(requestedEventNames, ","), "--log-fd", "2", "echo", "1" }; + + Collection failMsg = Utils.tryWith(senseCmd); if (!failMsg.isEmpty()) { throw new ProfilerException(failMsg.toString()); } + Collection passMsg = Utils.runWith(senseCmd); + for (String ev : requestedEventNames) { + if (PerfSupport.containsUnsupported(passMsg, ev)) { + throw new ProfilerException("Unsupported event: " + ev); + } + } + try { sampleFrequency = set.valueOf(optFrequency); } catch (OptionException e) { diff --git a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfC2CProfiler.java b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfC2CProfiler.java index 6d2fdaf35..46fdfbdc1 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfC2CProfiler.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfC2CProfiler.java @@ -44,6 +44,11 @@ public final class LinuxPerfC2CProfiler implements ExternalProfiler { protected final TempFile perfBinData; public LinuxPerfC2CProfiler() throws ProfilerException { + Collection failMsg = Utils.tryWith(PerfSupport.PERF_EXEC, "c2c", "record", "echo", "1"); + if (!failMsg.isEmpty()) { + throw new ProfilerException(failMsg.toString()); + } + try { perfBinData = FileUtils.weakTempFile("perf-c2c-bin"); } catch (IOException e) { diff --git a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfNormProfiler.java b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfNormProfiler.java index abe55575e..bb0c37cbc 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfNormProfiler.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/LinuxPerfNormProfiler.java @@ -118,21 +118,32 @@ public LinuxPerfNormProfiler(String initLine) throws ProfilerException { Collection incremental = Utils.tryWith(PerfSupport.PERF_EXEC, "stat", "--log-fd", "2", "--field-separator", ",", "--interval-print", String.valueOf(incrementInterval), "echo", "1"); isIncrementable = incremental.isEmpty(); + Collection candidateEvents = new ArrayList<>(); if (userEvents != null) { for (String ev : userEvents) { if (ev.trim().isEmpty()) continue; - supportedEvents.add(ev); + candidateEvents.add(ev); } } if (supportedEvents.isEmpty()) { - for (String ev : interestingEvents) { - Collection res = Utils.tryWith(PerfSupport.PERF_EXEC, "stat", "--log-fd", "2", "--field-separator", ",", "--event", ev, "echo", "1"); - if (res.isEmpty()) { + candidateEvents.addAll(Arrays.asList(interestingEvents)); + } + + for (String ev : candidateEvents) { + String[] senseCmd = { PerfSupport.PERF_EXEC, "stat", "--log-fd", "2", "--field-separator", ",", "--event", ev, "echo", "1" }; + Collection res = Utils.tryWith(senseCmd); + if (res.isEmpty()) { + Collection out = Utils.runWith(senseCmd); + if (!PerfSupport.containsUnsupported(out, ev)) { supportedEvents.add(ev); } } } + + if (!useDefaultStats && supportedEvents.isEmpty()) { + throw new ProfilerException("No supported events."); + } } @Override @@ -331,8 +342,14 @@ private Collection process(BenchmarkResult br, File stdOut, Fi // Also figure out IPC/CPI, if enough counters available: { - long cycles = events.count("cycles"); - long instructions = events.count("instructions"); + long c1 = events.count("cycles"); + long c2 = events.count("cycles:u"); + + long i1 = events.count("instructions"); + long i2 = events.count("instructions:u"); + + long cycles = (c1 != 0) ? c1 : c2; + long instructions = (i1 != 0) ? i1 : i2; if (cycles != 0 && instructions != 0) { results.add(new PerfResult("CPI", "clks/insn", 1.0 * cycles / instructions)); results.add(new PerfResult("IPC", "insns/clk", 1.0 * instructions / cycles)); diff --git a/jmh-core/src/main/java/org/openjdk/jmh/profile/MemPoolProfiler.java b/jmh-core/src/main/java/org/openjdk/jmh/profile/MemPoolProfiler.java index 7bded8be8..07b7be50f 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/profile/MemPoolProfiler.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/MemPoolProfiler.java @@ -57,7 +57,7 @@ public Collection afterIteration(BenchmarkParams benchmarkPara long sum = 0L; for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) { long used = bean.getPeakUsage().getUsed(); - if (bean.getName().contains("CodeHeap")) { + if (bean.getName().contains("CodeHeap") || bean.getName().contains("Code Cache")) { sumCodeHeap += used; } sum += used; diff --git a/jmh-core/src/main/java/org/openjdk/jmh/profile/PerfSupport.java b/jmh-core/src/main/java/org/openjdk/jmh/profile/PerfSupport.java index b286fde73..03fcad5a1 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/profile/PerfSupport.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/profile/PerfSupport.java @@ -24,6 +24,8 @@ */ package org.openjdk.jmh.profile; +import java.util.Collection; + class PerfSupport { static final String PERF_EXEC; @@ -33,4 +35,13 @@ class PerfSupport { PERF_EXEC = (perf == null) ? "perf" : perf; } + public static boolean containsUnsupported(Collection msgs, String event) { + for (String m : msgs) { + if (m.contains(event) && m.contains("")) { + return true; + } + } + return false; + } + } diff --git a/jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java b/jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java index 07a87a6e5..232122d9c 100644 --- a/jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java +++ b/jmh-core/src/main/java/org/openjdk/jmh/util/Utils.java @@ -528,6 +528,10 @@ public static Process runAsync(String... cmd) { } } + public static Collection runWith(String... cmds) { + return runWith(Arrays.asList(cmds)); + } + public static Collection runWith(List cmd) { Collection messages = new ArrayList<>(); try {