【问题标题】:Inconsistent JMH Throughput Values When Using paralell()使用 parallel() 时 JMH 吞吐量值不一致
【发布时间】:2015-07-26 01:38:56
【问题描述】:

我是 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 报告正确,我该如何调试此方法并找出 ops/s 下降的原因?

一些规格

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 次,但 ops/s 仍然保持一致。

检查 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 内联有了一些了解。

【问题讨论】:

  • LIMIT 值是多少?减速点是否取决于它?尝试降低两次并增加两次,然后看看。
  • 限制 = 100_000_000L

标签: java-8 jmh


【解决方案1】:

我已经确认您遇到的行为与这篇文章中描述的完全相同:Erratic performance of Arrays.stream().map().sum()

如果您运行测试的时间足够长(1000 次迭代),您会发现在某个时间点性能会恢复。原因是 JIT 编译器的一个尴尬的内联决定,它撕裂了热循环代码。有关 Paul Sandoz 的出色报道,请参阅链接帖子。

【讨论】:

  • 对我来说,通过@Fork(jvmArgsAppend= {"-XX:-TieredCompilation"}) 关闭分层编译似乎在这种情况下有所帮助。正如链接答案中所建议的那样增加内联深度。
  • 这几乎将这两个问题视为相同的问题。
  • 我今天早上用 1000 次迭代重新运行了基准测试。性能下降已经消失。我认为这种情况可能是由于 CPU 过热,但我还没有验证这一点。
  • 我已经通过在本地复制它来确认它不是由于过热,@the8472 也是如此。此外,JVM 标志(尤其是增加内联预算)对问题的影响是非常确定的。
  • 抱歉,我对@the8472 下面的第一个答案的理解是,他认为这是由于过热造成的。你是如何在本地重新制作的?我在完全相同的笔记本电脑上使用完全相同的设置重新运行完全相同的基准测试,并且 not 重新生成了它;我有点困惑。我并不是说 JVM 标志的效果不会提高性能——远非如此。只是我重新运行了相同的字节码(我没有重新编译该类)并且没有重新产生问题。我认为在我的特定情况下性能下降是由于 CPU 过度驱动造成的。
【解决方案2】:

英特尔 i7-4810MQ

据我所知,这是一个移动 CPU。检查它是否已耗尽其热设计范围并降低 CPU 时钟以避免过热。

【讨论】:

  • 我在一台普通 CPU 的笔记本电脑上进行了测试,行为相同。
  • 今天早上我在关闭笔记本电脑的情况下重新运行了基准测试。不一致的行为已经完全消失了——甚至超过 1000 次迭代。我认为@the8472 已经成功了。但是,我还没有重新创建问题,然后检查 CPU 温度来验证这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-22
  • 1970-01-01
相关资源
最近更新 更多