JMH @Fork的目的是什么?

时间:2016-01-27 19:50:33

标签: java benchmarking jmh

如果IIUC每个fork创建一个单独的虚拟机,原因是每个虚拟机实例可能在JIT指令中略有不同的情况下运行?

我也很好奇时间属性在下面的注释中做了什么:

@Warmup(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)

TIA, 奥莱

3 个答案:

答案 0 :(得分:17)

JMH提供fork功能有几个原因。一个是上面Rafael讨论的编译配置文件分离。但是这种行为不受@Forks注释的控制(除非你选择0分叉,这意味着没有子进程分叉来运行基准测试)。您可以选择通过使用预热模式控件(-wm)来运行所有基准测试作为基准热身的一部分(从而为JIT创建混合配置文件)。

现实情况是,很多事情都可以合谋倾斜你的结果,多次运行任何基准测试来建立逐次运行的差异是JMH支持的一个重要做法(并且大多数手工框架都没有帮助)。运行差异的原因可能包括(但我确定还有更多):

  • CPU在某个C状态下启动并在负载面上放大频率,然后过热并将其缩小。您可以在某些操作系统上控制此问题。

  • 进程的内存对齐可能会导致分页行为差异。

  • 后台应用程序活动。
  • 操作系统的CPU分配会有所不同,导致每次运行使用不同的CPU集。
  • 页面缓存内容和交换
  • 同时触发JIT编译并可能导致不同的结果(当大量代码正在测试时,这将会发生)。请注意,小型单线程基准测试通常不会出现此问题。
  • GC行为可以在不同的运行时间内触发,导致不同的结果。

使用至少一些分支运行您的基准测试将有助于消除这些差异,并让您了解在基准测试中看到的运行差异。我建议您从默认值10开始,然后根据您的基准测试将其减去(或增加)。

答案 1 :(得分:8)

JVM通过创建应用程序行为的配置文件来优化应用程序。创建fork以重置此配置文件。否则,运行:

benchmarkFoo();
benchmarkBar();

可能导致与

不同的测量结果
benchmarkBar();
benchmarkFoo();

因为第一个基准的轮廓影响了第二个基准。

时间决定了JMH用于升温或运行基准的支出的长度。如果这些时间缩短,您的VM可能无法充分预热,或者您的结果可能具有过高的标准偏差。

答案 2 :(得分:2)

更新

JMH(Java Microbenchmark线束)已添加到JDK 从JDK 12开始。

@Fork批注,指示将如何执行基准测试value参数控制基准测试将执行多少次,而warmup参数控制基准测试将空试多少次在收集结果之前。

示例:

@Benchmark
@Fork(value = 1, warmups = 3)
@BenchmarkMode(Mode.AverageTime)
public void myMethod() {
    // Do nothing
}

这会指示 JMH 在运行实时基准测试之前,先运行三个热身叉并舍弃结果