JMH@Fork的目的是什么



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

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

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

TIA,奥莱

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

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

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

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

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

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

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

benchmarkFoo();
benchmarkBar();

可能导致的测量值与

benchmarkBar();
benchmarkFoo();

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

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

更新:

JMH(Java Microbenchmark Harness)已被添加到JDK中 从 JDK 12 开始。

@Fork注释,指示基准测试的执行方式 value参数控制基准测试的执行次数,warmup参数控制基准测试在收集结果之前试运行的次数。

例:

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

这指示JMH运行三个预热叉并丢弃结果,然后再进行实时定时基准测试

相关内容

  • 没有找到相关文章

最新更新