我正在尝试编写jmh基准测试。
我遇到了许多博客,提到了jmh基准测试中的缺陷。常见的例子是
int sum() {
int a =7;
int b = 8;
return a+b;
}将被优化为
int sum() {
return 15;
}int sum(int y) {
int x = new Object();
return y;
}将被优化为
int sum(int y) {
return y;
}即删除未使用的对象初始化。
但是,这个列表并没有扩展到各种优化jvm将做什么。
下面是我面临的问题。
让我们说有几种方法,下面是调用图的样子
int methodA(CustomObjectA a) {
//do something
methodB(a);
//do something
return returnValueA;
}
int methodB(CustomObjectA a) {
//do something
methodC(a);
//do something
return returnValueB;
}
int methodC(CustomObjectA a) {
//do something
return returnValueC;
}我们将尝试对methodA进行基准测试。通过传递在状态对象中创建的CustomObjectA。但
发布于 2021-04-07 20:13:02
您是说要测试methodA,所有其他方法都是private,这就是调用链的样子吗?如果是这样的话,这里的JMH是无关紧要的--将应用什么优化,仍然将应用于该代码。也不可能知道最终会发生什么优化,因为它们在JVM上有很多,而且还依赖于许多其他因素,如操作系统、CPU等;因此,“广泛的列表”根本不可能存在。
例如,根据您在每个方法中在该//do something中所做的操作,可以省略或不删除该代码。看看这个简化的例子:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 5)
@Measurement(iterations = 5, time = 5)
public class Sample {
private static final int ME = 1;
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(Sample.class.getSimpleName())
.build();
new Runner(opt).run();
}
@Benchmark
public int methodOne(CustomObjectA a) {
simulateWork();
return 42;
}
@Benchmark
public int methodTwo(CustomObjectA a, Blackhole bh) {
bh.consume(simulateWork());
return 42;
}
@State(Scope.Thread)
public static class CustomObjectA {
}
private static double simulateWork() {
return ME << 1;
}
}不同之处在于,在方法methodTwo中,我使用了一个所谓的Blackhole (阅读这获取更多细节),而在methodOne中,我不使用。因此,从simulateWork中删除了methodOne,结果显示:
Benchmark Mode Cnt Score Error Units
Sample.methodOne avgt 25 1.950 ± 0.078 ns/op
Sample.methodTwo avgt 25 3.955 ± 0.120 ns/op另一方面,如果我稍微修改代码,使其具有尽可能小的副作用:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 5)
@Measurement(iterations = 5, time = 5)
public class Sample {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder()
.include(Sample.class.getSimpleName())
.build();
new Runner(opt).run();
}
@Benchmark
public int methodOne(CustomObjectA a) {
simulateWorkWithA(a);
return 42;
}
@Benchmark
public int methodTwo(CustomObjectA a) {
return simulateWorkWithA(a) + 42;
}
@Benchmark
public int methodThree(CustomObjectA a, Blackhole bh) {
bh.consume(simulateWorkWithA(a));
return 42;
}
@State(Scope.Thread)
public static class CustomObjectA {
int x = 0;
}
private static int simulateWorkWithA(CustomObjectA a) {
return a.x = a.x + 1;
}
}simulateWorkWithA(a)在methodOne中的消除将不会发生:
Benchmark Mode Cnt Score Error Units
Sample.methodOne avgt 25 2.267 ± 0.198 ns/op
Sample.methodThree avgt 25 3.711 ± 0.131 ns/op
Sample.methodTwo avgt 25 2.325 ± 0.008 ns/op注意,methodOne和methodTwo几乎没有区别。
https://stackoverflow.com/questions/66989430
复制相似问题