使用 parallel() 时 JMH 吞吐量值不一致
Inconsistent JMH Throughput Values When Using paralell()
我是 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
多次 运行 后观察到相同的行为。
在减少预热迭代后,我仍然看到 ops/s 在 5/6 次迭代后有所下降。
测试套件中使用并行操作的其他基准测试始终如一地执行。
我是 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 温度查看此行为是否再次发生。
当 运行ning 确实显示与 Erratic performance of Arrays.stream().map().sum() 中的方法类似的编译模式时使用 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
,但我认为这不是此问题的根本原因。
编辑 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 内联有了一些了解。
intel i7-4810MQ
据我所知,那是一部手机 CPU。检查它是否耗尽了其热设计范围并降低 CPU 时钟以避免过热。
我几乎已经确认您正在经历与 post 中描述的完全相同的行为:Erratic performance of Arrays.stream().map().sum()
如果您 运行 测试的时间足够长(1000 次迭代),您会发现性能在某个时候得到了恢复。原因是 JIT 编译器的一个笨拙的内联决定,它撕裂了热循环代码。请参阅链接 post,了解 Paul Sandoz 的精彩报道。
我是 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
多次 运行 后观察到相同的行为。 在减少预热迭代后,我仍然看到 ops/s 在 5/6 次迭代后有所下降。 测试套件中使用并行操作的其他基准测试始终如一地执行。
我是 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 温度查看此行为是否再次发生。
当 运行ning 确实显示与 Erratic performance of Arrays.stream().map().sum() 中的方法类似的编译模式时使用 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
,但我认为这不是此问题的根本原因。
编辑 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 内联有了一些了解。
intel i7-4810MQ
据我所知,那是一部手机 CPU。检查它是否耗尽了其热设计范围并降低 CPU 时钟以避免过热。
我几乎已经确认您正在经历与 post 中描述的完全相同的行为:Erratic performance of Arrays.stream().map().sum()
如果您 运行 测试的时间足够长(1000 次迭代),您会发现性能在某个时候得到了恢复。原因是 JIT 编译器的一个笨拙的内联决定,它撕裂了热循环代码。请参阅链接 post,了解 Paul Sandoz 的精彩报道。