JMH @Fork的目的是什么?

34

如果我理解正确,每个分支创建一个单独的虚拟机,因为每个虚拟机实例可能会以轻微不同的JIT指令运行?

我也想知道下面注释中的time属性是用来做什么的:

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

您好,TIA(Thanks In Advance), Ole


我认为这回答了你的问题:https://dev59.com/KV8e5IYBdhLWcg3wnbVj - Tunaki
如果我理解正确,每个分支都在单独的虚拟机中运行。我们这样做是因为每个启动的虚拟机可能存在微妙的差异,导致运行时不同,因此我们可以通过方差计算来考虑这一点。 - Ole
2
是的,每次运行时JIT的行为可能会有所不同,因此分叉允许考虑到这一点。在运行基准测试时,我曾经看到过非常奇怪的情况,其中一个运行会有某个平均值,而另一个运行相同的测试则会有非常不同的平均值,仅仅是因为JIT处理事情的方式不同。 - Tunaki
太好了 - 很高兴知道 - 谢谢Tunaki。顺便说一句 - 我认为那个答案比参考资料清晰得多,如果您想将其作为答案添加。 - Ole
3个回答

37
JMH提供fork功能的原因有几个。其中之一是编译文件分离,正如Rafael所讨论的那样。但是这种行为并不受@Forks注释的控制(除非您选择0个fork,这意味着根本没有子进程分叉来运行基准测试)。您可以选择将所有基准测试作为基准测试的一部分运行(从而创建一个混合配置文件以供JIT使用),方法是使用热身模式控制(-wm)。 事实上,很多事情都可能导致您的结果倾向于某一方面,多次运行任何基准测试以建立运行与运行之间的差异是一种重要的实践,JMH支持此操作(大多数手工制作的框架都无法帮助)。造成运行到运行之间差异的原因可能包括(但我确定还有更多): - CPU以某种C状态启动,并在负载的情况下增加频率,然后过热并将其缩小。您可以在某些操作系统上控制此问题。 - 进程的内存对齐可能会导致页面行为不同。 - 后台应用程序活动。 - 操作系统的CPU分配将发生变化,导致每次运行使用不同的CPU集。 - 页面缓存内容和交换 - JIT编译是并发触发的,可能会导致不同的结果(当测试的代码较大时,通常会发生这种情况)。请注意,小型单线程基准测试通常不会出现此问题。 - GC行为可能会在运行到运行之间以稍微不同的时间触发,从而导致不同的结果。
使用至少几个fork运行基准测试将有助于消除这些差异,并让您了解到基准测试中看到的运行与运行之间的差异。我建议您从默认值10开始,并根据您的基准测试实验性地削减或增加它。

20

JVM 通过创建应用程序的行为剖面来优化应用程序。分叉是为了重置该剖面而创建的。否则,运行:

benchmarkFoo();
benchmarkBar();

可能导致不同的测量结果

benchmarkBar();
benchmarkFoo();

由于第一个基准测试的配置会影响第二个。

时间决定了 JMH 用于预热或运行基准测试的时长。如果这些时间太短,您的虚拟机可能无法充分预热,或者您的结果可能具有过高的标准偏差。


0

更新:

JMH(Java微基准测试工具)已经被添加到JDK 12中。

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

示例:

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

这个指令告诉JMH在进行真正的基准测试之前运行三个预热周期并丢弃结果


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接