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

Java 8 使用paralell()时JMH吞吐量值不一致,java-8,jmh,Java 8,Jmh,我是JHM的新手,为了测试它,我编写了以下简单的方法 @Benchmark @OutputTimeUnit(TimeUnit.SECONDS) public long sumPar(){ return LongStream.rangeClosed(1, LIMIT) .parallel() .sum(); } 试验结果差别很大 # JMH 1.10.3 (released

我是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
编辑

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


今天早上,我把笔记本电脑关了一整晚,重新运行了基准测试。这种前后矛盾的行为已经完全消失了。我将迭代次数增加到1000次,但ops/s仍然保持一致

检查CPU温度,它稳定在84度

我无法重现这个问题,下次我认为我的CPU可能过热时,我想重新运行这个基准测试并监视CPU温度,看看是否会再次发生这种行为

运行时使用
-XX:+UnlockDiagnosticVMOptions-XX:+PrintCompilation-XX:+PrintInLine
确实显示了与中方法类似的编译模式,但我认为这不是此问题的根本原因


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

英特尔i7-4810MQ


据我所知,那是一个移动CPU。检查它是否正在耗尽其热设计外壳,并对CPU时钟进行节流以避免过热。

我已经确认,您正在经历与本文中描述的完全相同的行为:


如果您运行测试的时间足够长(1000次迭代),您将看到在某个时候性能得到恢复。原因是JIT编译器做出了一个笨拙的内联决策,它撕裂了热循环代码。请参阅保罗·桑多兹(Paul Sandoz)的精彩报道链接。

极限值是多少?减速点取决于它吗?试着降低两次,增加两次,看看。LIMIT=100_0000; u 000LI在一台有常规CPU的笔记本电脑上测试,同样的行为。我今天早上重新运行了基准测试,因为我的笔记本电脑在一夜之间关闭了。不一致的行为已经完全消失——甚至超过1000次迭代。我想@8472已经成功了。但是,我还没有重新创建问题,然后检查CPU温度以验证这一点。对于我来说,通过
@Fork(jvmArgsAppend={“-XX:-tieredcomilation”})关闭分层编译在这种情况下似乎有帮助。正如链接答案中建议的那样,增加内联深度也是如此。这几乎将这两个问题确定为相同的问题。今天早上,我用1000次迭代重新运行了基准测试。性能的下降已经消失。我认为这可能是由于CPU过热,但我还没有证实这一点。我已经通过在本地复制它来确认这不是由于过热,就像@8472一样。此外,JVM标志(特别是增加内联预算)对问题的影响是非常决定性的。抱歉,我对@the8472下面的第一个答案的理解是,他认为这是由于过热。你是如何在本地重新制作的?我在完全相同的笔记本电脑上用完全相同的设置重新运行了完全相同的基准测试,但没有重新生成它;我有点困惑。我并不是说JVM标志的效果不会提高性能——远远不是。只是我重新运行了相同的字节码(我没有重新编译类),没有重新生成问题。我认为在我的特殊情况下,性能下降是由于CPU驱动过度。
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