Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java JMH中fork之间的不同基准测试结果_Java_Performance_Benchmarking_Jmh - Fatal编程技术网

Java JMH中fork之间的不同基准测试结果

Java JMH中fork之间的不同基准测试结果,java,performance,benchmarking,jmh,Java,Performance,Benchmarking,Jmh,简言之,我的问题是:为什么JMH基准测试结果可以在fork中保持稳定,但在fork之间却存在显著差异 我在许多基准测试中观察到了这一点(通常涉及数据集的处理)。下面是一个简单的例子: import static java.util.concurrent.TimeUnit.*; import static java.util.stream.Collectors.*; import java.util.*; import org.openjdk.jmh.infra.Blackhole; impor

简言之,我的问题是:为什么JMH基准测试结果可以在fork中保持稳定,但在fork之间却存在显著差异

我在许多基准测试中观察到了这一点(通常涉及数据集的处理)。下面是一个简单的例子:

import static java.util.concurrent.TimeUnit.*;
import static java.util.stream.Collectors.*;
import java.util.*;

import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.annotations.*;

@Warmup(iterations = 5, time = 1, timeUnit = SECONDS)
@Measurement(iterations = 15, time = 1, timeUnit = SECONDS)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(MICROSECONDS)
@Fork(50)
@State(Scope.Benchmark)
public class AvgTest {
    private long[] longs = new Random(1).longs(1000).toArray();

    @Benchmark
    public void test(Blackhole bh) {
        bh.consume(Arrays.stream(longs).boxed().collect(averagingLong(x->x)));
    }
}
我使用5次1秒的预热迭代和15次1秒的测量迭代。按照
@Fork(50)
的规定,整个过程重复50次(连同JVM重启)。通常的叉子是这样的:

# Run progress: 8,00% complete, ETA 00:15:34
# Fork: 5 of 50
# Warmup Iteration   1: 10,752 us/op
# Warmup Iteration   2: 5,504 us/op
# Warmup Iteration   3: 5,107 us/op
# Warmup Iteration   4: 5,144 us/op
# Warmup Iteration   5: 5,157 us/op
Iteration   1: 5,140 us/op
Iteration   2: 5,157 us/op
Iteration   3: 5,148 us/op
Iteration   4: 5,143 us/op
Iteration   5: 5,153 us/op
Iteration   6: 5,148 us/op
Iteration   7: 5,151 us/op
Iteration   8: 5,143 us/op
Iteration   9: 5,143 us/op
Iteration  10: 5,138 us/op
Iteration  11: 5,144 us/op
Iteration  12: 5,142 us/op
Iteration  13: 5,151 us/op
Iteration  14: 5,144 us/op
Iteration  15: 5,135 us/op
# Run progress: 26,00% complete, ETA 00:12:31
# Fork: 14 of 50
# Warmup Iteration   1: 13,482 us/op
# Warmup Iteration   2: 12,800 us/op
# Warmup Iteration   3: 12,140 us/op
# Warmup Iteration   4: 12,102 us/op
# Warmup Iteration   5: 12,094 us/op
Iteration   1: 12,114 us/op
Iteration   2: 12,164 us/op
Iteration   3: 12,263 us/op
Iteration   4: 12,271 us/op
Iteration   5: 12,319 us/op
Iteration   6: 12,309 us/op
Iteration   7: 12,305 us/op
Iteration   8: 12,308 us/op
Iteration   9: 12,257 us/op
Iteration  10: 12,267 us/op
Iteration  11: 12,270 us/op
Iteration  12: 12,285 us/op
Iteration  13: 12,292 us/op
Iteration  14: 12,242 us/op
Iteration  15: 12,253 us/op
如您所见,每次迭代的结果非常稳定,标准偏差很低。然而,有时(可能几十年中有一次)我会看到这样的叉子:

# Run progress: 8,00% complete, ETA 00:15:34
# Fork: 5 of 50
# Warmup Iteration   1: 10,752 us/op
# Warmup Iteration   2: 5,504 us/op
# Warmup Iteration   3: 5,107 us/op
# Warmup Iteration   4: 5,144 us/op
# Warmup Iteration   5: 5,157 us/op
Iteration   1: 5,140 us/op
Iteration   2: 5,157 us/op
Iteration   3: 5,148 us/op
Iteration   4: 5,143 us/op
Iteration   5: 5,153 us/op
Iteration   6: 5,148 us/op
Iteration   7: 5,151 us/op
Iteration   8: 5,143 us/op
Iteration   9: 5,143 us/op
Iteration  10: 5,138 us/op
Iteration  11: 5,144 us/op
Iteration  12: 5,142 us/op
Iteration  13: 5,151 us/op
Iteration  14: 5,144 us/op
Iteration  15: 5,135 us/op
# Run progress: 26,00% complete, ETA 00:12:31
# Fork: 14 of 50
# Warmup Iteration   1: 13,482 us/op
# Warmup Iteration   2: 12,800 us/op
# Warmup Iteration   3: 12,140 us/op
# Warmup Iteration   4: 12,102 us/op
# Warmup Iteration   5: 12,094 us/op
Iteration   1: 12,114 us/op
Iteration   2: 12,164 us/op
Iteration   3: 12,263 us/op
Iteration   4: 12,271 us/op
Iteration   5: 12,319 us/op
Iteration   6: 12,309 us/op
Iteration   7: 12,305 us/op
Iteration   8: 12,308 us/op
Iteration   9: 12,257 us/op
Iteration  10: 12,267 us/op
Iteration  11: 12,270 us/op
Iteration  12: 12,285 us/op
Iteration  13: 12,292 us/op
Iteration  14: 12,242 us/op
Iteration  15: 12,253 us/op
结果也相当稳定,但比普通叉子慢2倍多

以下是每个分叉汇总(分叉编号、平均时间和标准偏差,以微秒为单位,按平均时间排序):

如您所见,对于大多数迭代,平均值落入
5.142..5.174 us
区间,然后小跳到
5.210..5.249 us
区间,然后大跳到
5.625..5.858 us
,然后是两个异常值。原始结果可在本文档中找到

那么这些跳跃和异常值是什么呢?是基准测试程序出现问题,还是生产中也会出现这种影响,我的程序在极少数情况下会慢2.5倍?这是与硬件或JVM相关的问题吗?我能在行刑开始时预测我是在快刀叉上还是在慢刀叉上吗


测量是在使用Oracle JDK 1.8.0_45和JMH 1.10.3的Windows 7 64位Intel i5四核系统中进行的。

我也多次注意到类似的问题。由于时间问题,某些方法在每个fork中的JIT编译方式不同。但是一旦编译完成,性能是稳定的——这就是为什么在一个fork中没有偏差。如果关闭
-XX:-BackgroundCompilation
-XX:-tieredcilation
也会使基准测试结果更可预测(更好!),您可能看不到这种效果。apangin,谢谢您的提示。今天晚些时候将使用
-XX:-BackgroundCompilation
重新运行基准测试。对我来说,类型配置文件应该是非常干净的,所以像内联这样的事情应该不会有太大的变化。还将检查
-XX:+printinline
,尽管使用
-XX:-tieredcomployment
可能很难分析…@apangin,但它工作得更快!但也有一个难题,在大多数迭代中,它是4.1us,但在极少数情况下(50次迭代中的3次),它大约是2.7us。使用
-XX:-BackgroundCompilation
速度较慢(约8.9us),但稳定(50个分叉中没有异常值)。明天会继续挖掘。我发现当JMH在叉子之间产生不同的分数时。但这显然不是你的情况。在您的例子中,差异似乎是由应用程序线程和后台编译器线程之间的竞争引起的。