JMH@Fork的目的是什么?

2022-09-01 09:37:35

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

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

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

蒂亚, 奥莱


答案 1

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

现实情况是,许多事情可能会以某种方式倾斜您的结果,并且多次运行任何基准以建立运行到运行方差是JMH支持的重要实践(大多数手工制作的框架都无济于事)。运行到运行方差的原因可能包括(但我确信还有更多):

  • CPU从特定的C状态开始,并在面对负载时放大频率,然后过热并缩小它。您可以在某些操作系统上控制此问题。

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

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

使用至少几个分叉运行基准测试将有助于摆脱这些差异,并让您了解在基准测试中看到的运行到运行方差。我建议你从默认值10开始,然后根据你的基准测试,通过实验性地减少(或增加它)。


答案 2

JVM 通过创建应用程序行为的概要文件来优化应用程序。创建分叉是为了重置此配置文件。否则,运行:

benchmarkFoo();
benchmarkBar();

可能导致不同的测量值

benchmarkBar();
benchmarkFoo();

因为第一个基准的概况会影响第二个基准。

时间决定了JMH用于预热或运行基准测试的支出长度。如果这些时间较短,则 VM 可能未充分预热,或者结果可能具有过高的标准差。


推荐