我有一个@Param
控制输入大小的基准测试,例如:
@State(Scope.Benchmark)
class MyBenchmark {
@Param({"100", "10000", "1000000"})
public int ARRAY_SIZE;
public int[] INPUT;
@Setup
public void setUp() {
INPUT = new int[ARRAY_SIZE];
// ...
}
@Benchmark
public void compute() {
// ...
}
}
当输入很大时,compute
在预热期间没有被调用足够的次数来触发编译。由于我想测量峰值性能,因此我希望确保在预热期间调用该方法以进行编译。
是否有好的方法来做到这一点?我可以设置更大的预热迭代次数,但这将适用于所有输入大小,而实际上只需要对不被编译的大输入。
与其增加迭代次数,不如尝试提前编译。
从JDK 9开始,有-XX:CompileThresholdScaling
JVM选项来调整编译策略的频率和阈值。值越小,编译开始越早。
。-XX:CompileThresholdScaling=0.05
将使阈值降低20倍。
该选项可以全局应用,也可以基于每个方法。例如,要将其仅应用于compute
基准测试,请添加以下注释:
@Benchmark
@Fork(jvmArgsAppend = {"-XX:CompileCommand=CompileThresholdScaling,*MyBenchmark*::compute*,0.05"})
public void compute() {
// ...
}
或者,您可以将较大的参数值提取到另一个@State
对象中,并使用不同的@Warmup
选项创建一个单独的基准测试方法:
@State(Scope.Benchmark)
public static class SmallParams {
@Param({"100", "10000"})
int size;
}
@State(Scope.Benchmark)
public static class LargeParams {
@Param({"1000000"})
int size;
}
@Benchmark
@Warmup(iterations = 5)
public void computeSmall(SmallParams params) {
//
}
@Benchmark
@Warmup(iterations = 50)
public void computeLarge(LargeParams params) {
//
}
或者只运行两次基准测试,重写命令行中的参数:
-p size=100,10000 -wi 5
-p size=1000000 -wi 50