JMH - 较低级别的基准测试
JMH - Lower-level benchmarking
我正在使用 JMH 对 JUnit 测试进行基准测试。
我的基准:
import org.openjdk.jmh.annotations.*;
public class Benchmarks {
@Benchmark
public void bmUnitTest1() {
UnitTests.UnitTest1();
}
@Benchmark
public void bmUnitTest2() {
UnitTests.UnitTest2();
}
}
我的基准跑步者:
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.concurrent.TimeUnit;
public class BenchmarkRunner {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(Benchmarks.class.getSimpleName())
.mode(Mode.SingleShotTime)
.resultFormat(ResultFormatType.CSV)
.result("target/test-classes/benchmarkcsv/BM " + System.currentTimeMillis() + ".csv")
.timeUnit(TimeUnit.MILLISECONDS)
.warmupIterations(3)
.warmupTime(TimeValue.seconds(1))
.measurementIterations(3)
.measurementTime(TimeValue.seconds(1))
.timeout(TimeValue.seconds(5))
.forks(1)
.warmupForks(1)
.threads(1)
.build();
new Runner(opt).run();
}
}
目前我正在获取整个单元测试的性能指标。我想知道是否可以在较低级别上查看这些性能指标。
示例:
UnitTest1 有多个函数调用。 Function1 耗时 10ms,Function2 耗时 20ms。
而不是看到这个(简化):
UnitTest1: 30ms/op
我想看这个:
UnitTest1: 30ms/op
Function1: 10ms/op
Function2: 20ms/op
我可以在 JMH 中执行此操作吗?如果没有,我可以使用任何替代方法来对 JUnit 测试进行基准测试吗?
JMH 有几个可以在 运行 基准测试时启用的分析器。有关详细信息,请参阅 JMHSample_35_Profilers。
其中之一是基于 async-profiler 项目的 async
分析器。它可以完全满足您的要求 - 显示您的单元测试调用的哪些方法花费最多 CPU 时间(使用堆栈跟踪!)
要启用此探查器,请调用 OptionsBuilder.addProfiler(AsyncProfiler.class, "output=flamegraph")
,或者(如果 运行 来自命令行)添加 -prof async:output=flamegraph
选项。
基准测试完成后,JMH 将生成 .html 格式的分析器报告:
如果你想获得一个扁平的配置文件 - 只使用 CPU 时间百分比的方法 - 使用不带 output
选项的 async
分析器:
ns percent samples top
---------- ------- ------- ---
1992741308 39.53% 200 java.util.stream.AbstractPipeline.copyInto
844434060 16.75% 84 java.util.stream.StreamOpFlag.isKnown
670418795 13.30% 67 java.lang.Integer.max
500609106 9.93% 50 java.util.stream.AbstractPipeline.getStreamAndOpFlags
451255844 8.95% 45 java.util.stream.AbstractPipeline.evaluate
221004309 4.38% 22 java.util.stream.ReduceOps.makeSink
140062540 2.78% 14 java.util.Spliterators$IntArraySpliterator.forEachRemaining
60012022 1.19% 6 java.util.stream.AbstractPipeline.wrapSink
39966227 0.79% 4 java.util.stream.ReduceOpsReducingSink.accept
39348309 0.78% 4 java.util.stream.ReduceOps$ReduceOp.evaluateSequential
10862017 0.22% 1 Dictionary::find(unsigned int, Symbol*, Handle)
10637320 0.21% 1 ciVirtualCallTypeData::translate_from(ProfileData const*)
10209263 0.20% 1 java.util.stream.AbstractPipeline.<init>
10155044 0.20% 1 java.util.Spliterator$OfInt.forEachRemaining
10128043 0.20% 1 PhaseChaitin::Register_Allocate()
10115108 0.20% 1 _raw_spin_unlock_irqrestore_[k]
9486501 0.19% 1 PhaseChaitin::Select()
9281194 0.18% 1 PhaseIdealLoop::optimize(PhaseIterGVN&, LoopOptsMode)
我正在使用 JMH 对 JUnit 测试进行基准测试。
我的基准:
import org.openjdk.jmh.annotations.*;
public class Benchmarks {
@Benchmark
public void bmUnitTest1() {
UnitTests.UnitTest1();
}
@Benchmark
public void bmUnitTest2() {
UnitTests.UnitTest2();
}
}
我的基准跑步者:
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.TimeValue;
import java.util.concurrent.TimeUnit;
public class BenchmarkRunner {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(Benchmarks.class.getSimpleName())
.mode(Mode.SingleShotTime)
.resultFormat(ResultFormatType.CSV)
.result("target/test-classes/benchmarkcsv/BM " + System.currentTimeMillis() + ".csv")
.timeUnit(TimeUnit.MILLISECONDS)
.warmupIterations(3)
.warmupTime(TimeValue.seconds(1))
.measurementIterations(3)
.measurementTime(TimeValue.seconds(1))
.timeout(TimeValue.seconds(5))
.forks(1)
.warmupForks(1)
.threads(1)
.build();
new Runner(opt).run();
}
}
目前我正在获取整个单元测试的性能指标。我想知道是否可以在较低级别上查看这些性能指标。
示例:
UnitTest1 有多个函数调用。 Function1 耗时 10ms,Function2 耗时 20ms。
而不是看到这个(简化):
UnitTest1: 30ms/op
我想看这个:
UnitTest1: 30ms/op
Function1: 10ms/op
Function2: 20ms/op
我可以在 JMH 中执行此操作吗?如果没有,我可以使用任何替代方法来对 JUnit 测试进行基准测试吗?
JMH 有几个可以在 运行 基准测试时启用的分析器。有关详细信息,请参阅 JMHSample_35_Profilers。
其中之一是基于 async-profiler 项目的 async
分析器。它可以完全满足您的要求 - 显示您的单元测试调用的哪些方法花费最多 CPU 时间(使用堆栈跟踪!)
要启用此探查器,请调用 OptionsBuilder.addProfiler(AsyncProfiler.class, "output=flamegraph")
,或者(如果 运行 来自命令行)添加 -prof async:output=flamegraph
选项。
基准测试完成后,JMH 将生成 .html 格式的分析器报告:
如果你想获得一个扁平的配置文件 - 只使用 CPU 时间百分比的方法 - 使用不带 output
选项的 async
分析器:
ns percent samples top
---------- ------- ------- ---
1992741308 39.53% 200 java.util.stream.AbstractPipeline.copyInto
844434060 16.75% 84 java.util.stream.StreamOpFlag.isKnown
670418795 13.30% 67 java.lang.Integer.max
500609106 9.93% 50 java.util.stream.AbstractPipeline.getStreamAndOpFlags
451255844 8.95% 45 java.util.stream.AbstractPipeline.evaluate
221004309 4.38% 22 java.util.stream.ReduceOps.makeSink
140062540 2.78% 14 java.util.Spliterators$IntArraySpliterator.forEachRemaining
60012022 1.19% 6 java.util.stream.AbstractPipeline.wrapSink
39966227 0.79% 4 java.util.stream.ReduceOpsReducingSink.accept
39348309 0.78% 4 java.util.stream.ReduceOps$ReduceOp.evaluateSequential
10862017 0.22% 1 Dictionary::find(unsigned int, Symbol*, Handle)
10637320 0.21% 1 ciVirtualCallTypeData::translate_from(ProfileData const*)
10209263 0.20% 1 java.util.stream.AbstractPipeline.<init>
10155044 0.20% 1 java.util.Spliterator$OfInt.forEachRemaining
10128043 0.20% 1 PhaseChaitin::Register_Allocate()
10115108 0.20% 1 _raw_spin_unlock_irqrestore_[k]
9486501 0.19% 1 PhaseChaitin::Select()
9281194 0.18% 1 PhaseIdealLoop::optimize(PhaseIterGVN&, LoopOptsMode)