问题描述
如何使用JUnit测试在现有项目中运行JMH基准测试?官方文档建议使用Maven shade插件创建一个单独的项目,并在 main
方法中启动JMH。这是必要的,为什么推荐它?
How can I run JMH benchmarks inside my existing project using JUnit tests? The official documentation recommends making a separate project, using Maven shade plugin, and launching JMH inside the main
method. Is this necessary and why is it recommended?
推荐答案
我一直在使用JUnit在我现有的Maven项目中运行JMH而没有明显的不良影响。我无法回答为什么作者建议采取不同的做法。我没有观察到结果的差异。 JMH启动一个单独的JVM来运行基准来隔离它们。以下是我的工作:
I've been running JMH inside my existing Maven project using JUnit with no apparent ill effects. I cannot answer why the authors recommend doing things differently. I have not observed a difference in results. JMH launches a separate JVM to run benchmarks to isolate them. Here is what I do:
-
将JMH依赖项添加到您的POM:
Add the JMH dependencies to your POM:
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.21</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.21</version>
<scope>test</scope>
</dependency>
请注意,我已将它们放在范围 test
。
Note that I've placed them in scope test
.
在Eclipse中,您可能需要手动配置注释处理器。 NetBeans自动处理此问题。
In Eclipse, you may need to configure the annotation processor manually. NetBeans handles this automatically.
创建JUnit和JMH类。我选择将两者合二为一,但这取决于你。请注意, OptionsBuilder.include
实际上决定了从JUnit测试中运行哪些基准测试!
Create your JUnit and JMH class. I've chosen to combine both into a single class, but that is up to you. Notice that OptionsBuilder.include
is what actually determines which benchmarks will be run from your JUnit test!
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.*;
public class TestBenchmark
{
@Test public void
launchBenchmark() throws Exception {
Options opt = new OptionsBuilder()
// Specify which benchmarks to run.
// You can be more specific if you'd like to run only one benchmark per test.
.include(this.getClass().getName() + ".*")
// Set the following options as needed
.mode (Mode.AverageTime)
.timeUnit(TimeUnit.MICROSECONDS)
.warmupTime(TimeValue.seconds(1))
.warmupIterations(2)
.measurementTime(TimeValue.seconds(1))
.measurementIterations(2)
.threads(2)
.forks(1)
.shouldFailOnError(true)
.shouldDoGC(true)
//.jvmArgs("-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining")
//.addProfiler(WinPerfAsmProfiler.class)
.build();
new Runner(opt).run();
}
// The JMH samples are the best documentation for how to use it
// http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/
@State (Scope.Thread)
public static class BenchmarkState
{
List<Integer> list;
@Setup (Level.Trial) public void
initialize() {
Random rand = new Random();
list = new ArrayList<>();
for (int i = 0; i < 1000; i++)
list.add (rand.nextInt());
}
}
@Benchmark public void
benchmark1 (BenchmarkState state, Blackhole bh) {
List<Integer> list = state.list;
for (int i = 0; i < 1000; i++)
bh.consume (list.get (i));
}
}
JMH的注释处理器似乎效果不佳在NetBeans中使用compile-on-save。每当修改基准时,您可能需要执行完整的清理和构建
。 (任何建议表示赞赏!)
JMH's annotation processor seems to not work well with compile-on-save in NetBeans. You may need to do a full Clean and Build
whenever you modify the benchmarks. (Any suggestions appreciated!)
运行 launchBenchmark
测试并观看结果!
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.Foo
# JMH version: 1.21
# VM version: JDK 1.8.0_172, Java HotSpot(TM) 64-Bit Server VM, 25.172-b11
# VM invoker: /usr/lib/jvm/java-8-jdk/jre/bin/java
# VM options: <none>
# Warmup: 2 iterations, 1 s each
# Measurement: 2 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 2 threads, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.Foo.benchmark1
# Run progress: 0.00% complete, ETA 00:00:04
# Fork: 1 of 1
# Warmup Iteration 1: 4.258 us/op
# Warmup Iteration 2: 4.359 us/op
Iteration 1: 4.121 us/op
Iteration 2: 4.029 us/op
Result "benchmark1":
4.075 us/op
# Run complete. Total time: 00:00:06
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.
Benchmark Mode Cnt Score Error Units
Foo.benchmark1 avgt 2 4.075 us/op
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.013 sec
Runner.run
甚至返回 RunResult
可以进行断言的对象等。
Runner.run
even returns RunResult
objects on which you can do assertions, etc.
这篇关于如何从JUnit测试中运行JMH?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!