Skip to content

Commit

Permalink
7903487: JMH: Make sure JMH profilers work on all tested configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
shipilev committed Jun 8, 2023
1 parent 9384362 commit bf8db38
Show file tree
Hide file tree
Showing 25 changed files with 1,177 additions and 12 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/pre-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions jmh-core-it/src/test/java/org/openjdk/jmh/it/Fixtures.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,7 @@ public static boolean isDefaultProfile() {
return PROFILE.equals("default");
}

public static boolean isVirtualExecutor() {
return PROFILE.contains("executor-virtual");
}
}
Original file line number Diff line number Diff line change
@@ -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("<no assembly is recorded, native region>");
}
}
}

}
Original file line number Diff line number Diff line change
@@ -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<String, Result> 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);
}
}

}
Original file line number Diff line number Diff line change
@@ -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<String, Result> 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);
}
}

}
Original file line number Diff line number Diff line change
@@ -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<String, Result> sr = rr.getSecondaryResults();
String out = ProfilerTestUtils.checkedGet(sr, "·asm").extendedInfo();
if (!checkDisassembly(out)) {
throw new IllegalStateException("Profile does not contain the required frame: " + out);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ private void testWith(String initLine) throws RunnerException {
double opsPerSec = rr.getPrimaryResult().getScore();

Map<String, Result> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void testDefault() throws RunnerException {
RunResult rr = new Runner(opts).runSingle();

Map<String, Result> 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;

Expand Down
Loading

0 comments on commit bf8db38

Please sign in to comment.