使用paralell()时JMH吞吐量值不一致

时间:2015-07-25 00:21:49

标签: java-8 jmh

我是JHM的新手,为了测试它我编写了以下简单的方法

@Benchmark
@OutputTimeUnit(TimeUnit.SECONDS)
public long sumPar(){
    return 
            LongStream.rangeClosed(1, LIMIT)
                      .parallel()
                      .sum();
}

测试结果差异很大

# JMH 1.10.3 (released 8 days ago)
# VM version: JDK 1.8.0_45, VM 25.45-b02
# VM invoker: /usr/lib/jvm/java-8-oracle/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: testStreams.Bench.sumPar

# Run progress: 22.21% complete, ETA 00:02:33
# Fork: 1 of 1
# Warmup Iteration   1: 53.495 ops/s
# Warmup Iteration   2: 57.971 ops/s
# Warmup Iteration   3: 57.622 ops/s
# Warmup Iteration   4: 58.113 ops/s
# Warmup Iteration   5: 57.861 ops/s
Iteration   1: 50.414 ops/s
Iteration   2: 9.207 ops/s
Iteration   3: 9.176 ops/s
Iteration   4: 9.212 ops/s
Iteration   5: 9.175 ops/s

多次运行后观察到相同的行为。 在减少预热迭代后,我仍然看到在5/6次迭代后ops / s下降。 测试套件中使用并行操作的其他基准测试始终如一。

我是JMH的新手,我有几个问题。

  • JMH中是否有任何配置参数我可以调整以获得更少的差异?
  • 这是所讨论方法的多次迭代的预期行为吗?
  • 如果JHM正确报告我如何调试此方法并找出操作/丢弃的原因?

一些规格

intel i7-4810MQ @ 2.80GHz
16GB RAM
Ubuntu 14.04 running on virtual box on windows host
virtual machine is alloacted 3 CPU cores
JDK 1.8.0_45
JMH 1.10.3

修改

感谢所有的反馈,非常感谢。

我今天早上重新运行基准测试,整晚都把笔记本电脑关了。不一致的行为已完全消失。我将迭代次数增加到1000次,而且仍然保持一致。

检查CPU温度是否稳定在84度。

我无法重现此问题,下次我认为我的CPU可能会过热我想重新运行此基准测试并监控CPU温度以查看此行为是否重新发生。

在运行时使用-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining确实显示了Erratic performance of Arrays.stream().map().sum()中方法的类似编译模式,但我不认为这是此问题的根本原因。

编辑2

能够通过添加-XX:MaxInlineLevel=12标志来重现和解决。

DevBox:~/test$ java -jar target/benchmarks.jar testStreams.Bench -i 5 -wi 5 -f 1
# JMH 1.10.3 (released 8 days ago)
# VM version: JDK 1.8.0_45, VM 25.45-b02
# VM invoker: /usr/lib/jvm/java-8-oracle/jre/bin/java
# VM options: <none>
# Warmup: 5 iterations, 1 s each
# Measurement: 5 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: testStreams.Bench.sumPar

# Run progress: 0.00% complete, ETA 00:00:30
# Fork: 1 of 1
# Warmup Iteration   1: 53.672 ops/s
# Warmup Iteration   2: 57.720 ops/s
# Warmup Iteration   3: 58.320 ops/s
# Warmup Iteration   4: 58.174 ops/s
# Warmup Iteration   5: 58.680 ops/s
Iteration   1: 49.810 ops/s
Iteration   2: 9.109 ops/s
Iteration   3: 9.427 ops/s
Iteration   4: 9.437 ops/s
Iteration   5: 9.436 ops/s
DevBox:~/test$ java -XX:MaxInlineLevel=12 -jar target/benchmarks.jar testStreams.Bench -i 1000 -wi 5 -f 1
# JMH 1.10.3 (released 8 days ago)
# VM version: JDK 1.8.0_45, VM 25.45-b02
# VM invoker: /usr/lib/jvm/java-8-oracle/jre/bin/java
# VM options: -XX:MaxInlineLevel=12
# Warmup: 5 iterations, 1 s each
# Measurement: 1000 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: testStreams.Bench.sumPar

# Run progress: 0.00% complete, ETA 00:50:16
# Fork: 1 of 1
# Warmup Iteration   1: 53.888 ops/s
# Warmup Iteration   2: 58.328 ops/s
# Warmup Iteration   3: 58.468 ops/s
# Warmup Iteration   4: 58.455 ops/s
# Warmup Iteration   5: 57.937 ops/s
Iteration   1: 58.717 ops/s
Iteration   2: 59.494 ops/s
Iteration   3: 60.013 ops/s
Iteration   4: 59.506 ops/s
Iteration   5: 51.543 ops/s

在以前省略-XX:MaxInlineLevel=12之前,仍然没有找到根本原因,以解释为什么我无法重现该问题。据我所知,我使用相同的设置。我的笔记本电脑闲置了一段时间之后,我可能会尝试再次运行基准测试,但是现在我很高兴我对JIT内联有所了解。

2 个答案:

答案 0 :(得分:2)

我几乎已经确认您遇到了与此帖中描述的完全相同的行为:Erratic performance of Arrays.stream().map().sum()

如果你运行测试的时间足够长(1000次迭代),你会发现在某些时候性能得以恢复。原因是JIT编译器做出了一个尴尬的内联决定,它破坏了热循环代码。请参阅链接帖子,了解Paul Sandoz的优秀报道。

答案 1 :(得分:1)

  

intel i7-4810MQ

据我所知,这是一款移动CPU。检查它是否耗尽其热设计包络并限制CPU时钟以避免过热。