项目作者: fineconstant

项目描述 :
JMH benchmark comparing Fibonacci sequence variations (dynamic programming) on different JVM implementations
高级语言: Scala
项目地址: git://github.com/fineconstant/dynamic-programming-jmh-jvm.git


Dynamic programming by the example of the Fibonacci sequence and measured with JMH

JMH Benchmarks

Profiled with jprofiler Java profiler.

Running benchmarks:

  • ./run-jmh-benchmarks.sh
  • ./run-jmh-jfr-benchmarks.sh - additionally records Flight Recorder file from JMH run

FibonacciJmhBenchmark

  1. import java.util.concurrent.TimeUnit
  2. import org.openjdk.jmh.annotations._
  3. import org.openjdk.jmh.infra.Blackhole
  4. @BenchmarkMode(Array(Mode.Throughput))
  5. @OutputTimeUnit(TimeUnit.SECONDS)
  6. @State(Scope.Benchmark)
  7. @Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
  8. @Measurement(iterations = 20, time = 1, timeUnit = TimeUnit.SECONDS)
  9. @Fork(10)
  10. @Threads(1)
  11. class FibonacciJmhBenchmark {
  12. private val fibonacciN = 25
  13. @Benchmark
  14. def fibonacciNaive(bh: Blackhole): Unit = {
  15. bh.consume(FibonacciNaive(fibonacciN))
  16. }
  17. @Benchmark
  18. def fibonacciNaiveMemoization(bh: Blackhole): Unit = {
  19. bh.consume(FibonacciNaiveMemoization(fibonacciN))
  20. }
  21. @Benchmark
  22. def fibonacciTailrec(bh: Blackhole): Unit = {
  23. bh.consume(FibonacciTailrec(fibonacciN))
  24. }
  25. @Benchmark
  26. def fibonacciStream(bh: Blackhole): Unit = {
  27. bh.consume(FibonacciStream(fibonacciN))
  28. }
  29. @Benchmark
  30. def fibonacciBottomUp(bh: Blackhole): Unit = {
  31. bh.consume(FibonacciBottomUp(fibonacciN))
  32. }
  33. }

Fibonacci algorithms

FibonacciNaive

  1. object FibonacciNaive {
  2. def apply(n: Int): BigInt = {
  3. n match {
  4. case 0 => BigInt(0)
  5. case 1 => BigInt(1)
  6. case 2 => BigInt(1)
  7. case _ => FibonacciNaive(n - 2) + FibonacciNaive(n - 1)
  8. }
  9. }
  10. }

FibonacciNaiveMemoization

  1. import scala.collection.mutable
  2. object FibonacciNaiveMemoization {
  3. def apply(n: Int): BigInt = {
  4. val cache = mutable.WeakHashMap.empty[Int, BigInt]
  5. def _fibonacci(n: Int): BigInt = {
  6. cache.getOrElse(n, n match {
  7. case 0 =>
  8. val y = BigInt(0)
  9. cache.put(n, y)
  10. y
  11. case 1 =>
  12. val y = BigInt(1)
  13. cache.put(n, y)
  14. y
  15. case _ =>
  16. val y = _fibonacci(n - 2) + _fibonacci(n - 1)
  17. cache.put(n, y)
  18. y
  19. })
  20. }
  21. _fibonacci(n)
  22. }
  23. }

FibonacciTailrec

  1. import scala.annotation.tailrec
  2. object FibonacciTailrec {
  3. def apply(n: Int): BigInt = {
  4. @tailrec
  5. def _fibonacci(n: Int, nMinusTwo: BigInt, nMinusOne: BigInt): BigInt = {
  6. n match {
  7. case 0 => nMinusTwo
  8. case 1 => nMinusOne
  9. case _ => _fibonacci(n - 1, nMinusOne, nMinusOne + nMinusTwo)
  10. }
  11. }
  12. _fibonacci(n, 0, 1)
  13. }
  14. }

FibonacciStream

  1. object FibonacciStream {
  2. def apply(n: Int): BigInt = {
  3. def _fibonacci(nMinusTwo: BigInt, nMinusOne: BigInt): Stream[BigInt] =
  4. nMinusTwo #:: _fibonacci(nMinusOne, nMinusTwo + nMinusOne)
  5. _fibonacci(0, 1).apply(n)
  6. }
  7. }

FibonacciBottomUp

  1. object FibonacciBottomUp {
  2. def apply(n: Int): BigInt = {
  3. def _fibonacci(n: Int): BigInt = {
  4. var nMinusTwo = BigInt(0)
  5. var nMinusOne = BigInt(1)
  6. var currentN = BigInt(0)
  7. for (_ <- 0 until n) {
  8. nMinusTwo = nMinusOne
  9. nMinusOne = currentN
  10. currentN = nMinusTwo + nMinusOne
  11. }
  12. currentN
  13. }
  14. n match {
  15. case 0 => BigInt(0)
  16. case 1 => BigInt(1)
  17. case 2 => BigInt(1)
  18. case _ => _fibonacci(n)
  19. }
  20. }
  21. }

Benchmarks results

JDK 1.8 HotSpot

  1. openjdk version "1.8.0_202"
  2. OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_202-b08)
  3. OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.202-b08, mixed mode)
  1. Benchmark Mode Cnt Score Error Units
  2. FibonacciJmhBenchmark.fibonacciTailrec thrpt 200 2001547.362 ± 6868.334 ops/s
  3. FibonacciJmhBenchmark.fibonacciBottomUp thrpt 200 1805695.925 ± 16442.757 ops/s
  4. FibonacciJmhBenchmark.fibonacciStream thrpt 200 1117719.733 ± 4825.625 ops/s
  5. FibonacciJmhBenchmark.fibonacciNaiveMemoization thrpt 200 563011.785 ± 14488.654 ops/s
  6. FibonacciJmhBenchmark.fibonacciNaive thrpt 200 621.838 ± 0.509 ops/s

JDK 1.8 OpenJ9

  1. openjdk version "1.8.0_202"
  2. OpenJDK Runtime Environment (build 1.8.0_202-b08)
  3. Eclipse OpenJ9 VM (build openj9-0.12.1, JRE 1.8.0 Mac OS X amd64-64-Bit Compressed References 20190205_147 (JIT enabled, AOT enabled)
  4. OpenJ9 - 90dd8cb40
  5. OMR - d2f4534b
  6. JCL - d002501a90 based on jdk8u202-b08)
  1. Benchmark Mode Cnt Score Error Units
  2. FibonacciJmhBenchmark.fibonacciTailrec thrpt 200 1854265.775 ± 24061.462 ops/s
  3. FibonacciJmhBenchmark.fibonacciBottomUp thrpt 200 1362137.742 ± 21082.305 ops/s
  4. FibonacciJmhBenchmark.fibonacciStream thrpt 200 682050.482 ± 3478.769 ops/s
  5. FibonacciJmhBenchmark.fibonacciNaiveMemoization thrpt 200 533618.996 ± 9791.518 ops/s
  6. FibonacciJmhBenchmark.fibonacciNaive thrpt 200 435.027 ± 4.988 ops/s

JDK 1.8 GraalVM

  1. java version "1.8.0_192"
  2. Java(TM) SE Runtime Environment (build 1.8.0_192-b12)
  3. GraalVM 1.0.0-rc12 (build 25.192-b12-jvmci-0.54, mixed mode)
  1. Benchmark Mode Cnt Score Error Units
  2. FibonacciJmhBenchmark.fibonacciTailrec thrpt 200 5415798.980 ± 14753.933 ops/s
  3. FibonacciJmhBenchmark.fibonacciBottomUp thrpt 200 4420254.845 ± 4893.127 ops/s
  4. FibonacciJmhBenchmark.fibonacciStream thrpt 200 1365366.170 ± 933.818 ops/s
  5. FibonacciJmhBenchmark.fibonacciNaiveMemoization thrpt 200 901036.310 ± 1713.943 ops/s
  6. FibonacciJmhBenchmark.fibonacciNaive thrpt 200 1181.364 ± 6.406 ops/s

JDK 11.0.2 HotSpot

  1. openjdk version "11.0.2" 2019-01-15
  2. OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.2+9)
  3. OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.2+9, mixed mode)
  1. Benchmark Mode Cnt Score Error Units
  2. FibonacciJmhBenchmark.fibonacciTailrec thrpt 200 4497583.703 ± 42183.751 ops/s
  3. FibonacciJmhBenchmark.fibonacciBottomUp thrpt 200 2998348.356 ± 20048.948 ops/s
  4. FibonacciJmhBenchmark.fibonacciStream thrpt 200 944649.041 ± 6745.397 ops/s
  5. FibonacciJmhBenchmark.fibonacciNaiveMemoization thrpt 200 595821.665 ± 19302.382 ops/s
  6. FibonacciJmhBenchmark.fibonacciNaive thrpt 200 1046.870 ± 1.768 ops/s

JDK 11.0.1 OpenJ9

  1. openjdk version "11.0.1" 2018-10-16
  2. OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.1+13)
  3. Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.11.0, JRE 11 Mac OS X amd64-64-Bit Compressed References 20181020_7 (JIT enabled, AOT enabled)
  4. OpenJ9 - 090ff9dc
  5. OMR - ea548a66
  6. JCL - f62696f378 based on jdk-11.0.1+13)
  1. Benchmark Mode Cnt Score Error Units
  2. FibonacciJmhBenchmark.fibonacciTailrec thrpt 200 1748200.819 ± 32120.465 ops/s
  3. FibonacciJmhBenchmark.fibonacciBottomUp thrpt 200 1222295.070 ± 8661.716 ops/s
  4. FibonacciJmhBenchmark.fibonacciStream thrpt 200 634128.886 ± 5631.495 ops/s
  5. FibonacciJmhBenchmark.fibonacciNaiveMemoization thrpt 200 394875.229 ± 3638.218 ops/s
  6. FibonacciJmhBenchmark.fibonacciNaive thrpt 200 380.049 ± 1.844 ops/s

JDK 11.0.2 OpenJ9

  1. openjdk version "11.0.2" 2019-01-15
  2. OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.2+9)
  3. Eclipse OpenJ9 VM AdoptOpenJDK (build openj9-0.12.1, JRE 11 Mac OS X amd64-64-Bit Compressed References 20190204_123 (JIT enabled, AOT enabled)
  4. OpenJ9 - 90dd8cb40
  5. OMR - d2f4534b
  6. JCL - 289c70b684 based on )
  1. Benchmark Mode Cnt Score Error Units
  2. FibonacciJmhBenchmark.fibonacciTailrec thrpt 200 1817007.843 ± 24424.427 ops/s
  3. FibonacciJmhBenchmark.fibonacciBottomUp thrpt 200 1193490.741 ± 8880.656 ops/s
  4. FibonacciJmhBenchmark.fibonacciStream thrpt 200 638851.149 ± 3091.760 ops/s
  5. FibonacciJmhBenchmark.fibonacciNaiveMemoization thrpt 200 450829.877 ± 9917.783 ops/s
  6. FibonacciJmhBenchmark.fibonacciNaive thrpt 200 388.061 ± 2.882 ops/s

Comparison

Algorithm types vs. JVM implementations [ops/s]

Algorithm types vs. JVM implementations [ops/s]