6

I've created a benchmark for a method which finds out the longest common subsequence using dynamic programming:

@Benchmark
  def longestCommonSubsequenceDP(): String = {
    val s1 = "Pellentesque lacinia"
    val s2 = "Mauris purus massa"
    val up = 1
    val left = 2
    val charMatched = 3

    val s1Length = s1.length()
    val s2Length = s2.length()

    val lcsLengths = Array.fill[Int](s1Length + 1, s2Length + 1)(0)

    for (i <- 0 until s1Length) {
      for (j <- 0 until s2Length) {
        if (s1.charAt(i) == s2.charAt(j)) {
          lcsLengths(i + 1)(j + 1) = lcsLengths(i)(j) + 1
        } else {
          if (lcsLengths(i)(j + 1) >= lcsLengths(i + 1)(j)) {
            lcsLengths(i + 1)(j + 1) = lcsLengths(i)(j + 1)
          } else {
            lcsLengths(i + 1)(j + 1) = lcsLengths(i + 1)(j)
          }
        }
      }
    }

    val subSeq = new StringBuilder()
    var s1Pos = s1Length
    var s2Pos = s2Length

    do {
      if (lcsLengths(s1Pos)(s2Pos) == lcsLengths(s1Pos -1)(s2Pos)) {
        s1Pos -= 1
      } else if (lcsLengths(s1Pos)(s2Pos) == lcsLengths(s1Pos)(s2Pos - 1)) {
        s2Pos -= 1
      } else {
        assert(s1.charAt(s1Pos - 1) == s2.charAt(s2Pos - 1))
        subSeq += s1.charAt(s1Pos - 1)
        s1Pos -= 1
        s2Pos -= 1
      }

    } while (s1Pos > 0 && s2Pos > 0)

    subSeq.toString.reverse
  }

and ran it with the following configuration jmh:run -i 10 -wi 10 -f1 -t1 and got the following results:

GraalVM EE 1.0.0-rc10

[info] Benchmark                        Mode  Cnt   Score   Error   Units
[info] LCS.longestCommonSubsequenceDP  thrpt   25  91.411 ± 4.355  ops/ms

GraalVM CE 1.0.0-rc10

[info] Benchmark                        Mode  Cnt   Score   Error   Units
[info] LCS.longestCommonSubsequenceDP  thrpt   25  26.741 ± 0.408  ops/ms

OpenJDK 1.8.0_192

[info] Benchmark                        Mode  Cnt   Score   Error   Units
[info] LCS.longestCommonSubsequenceDP  thrpt   25  45.216 ± 1.956  ops/ms

Also I did another test where I created a list with thousands of objects, performed some filtering and sort on it, and thrpt was smallest on GraalVM CE.

Why this difference?

A5300
  • 409
  • 4
  • 18
  • Can you clarify your question? Are you asking why there is any performance difference at all between the two? Or are you asking what the technical improvements to EE are that make it faster? The answer to the former is simply: according to the website, the paid version is faster. The answer to the latter cannot be given, since the paid version is proprietary. – Jörg W Mittag Dec 16 '18 at 08:12
  • 1
    @JörgWMittag, yes I know EE is not open source. The question is more like why GraalVM CE is less performant than OpenJDK? And I'm asking this because GraalVM is publicized as being better. – A5300 Dec 16 '18 at 13:55
  • 1
    This benchmark shows the top performance is achieved on GraalVM, which is very consistent with the "GraalVM is publicized as being better" message, isn't it? – Oleg Šelajev Dec 17 '18 at 09:48
  • I was expecting both editions to perform better then OpenJDK, but I get your point - one test doesn't show overall performance – A5300 Dec 18 '18 at 16:36

1 Answers1

4

You get different results because the runtimes you're using have different top tier JIT compilers enabled. Unless specified otherwise (with the command flags for example):

  • OpenJDK 1.8.0_192 uses C2
  • GraalVM CE 1.0.0-rc10 uses the Graal compiler.
  • GraalVM EE 1.0.0-rc10 uses the enterprise version of the Graal compiler.

JIT compiles your code at runtime to the machine code which heavily depends on the original code, workload, JIT configuration, enabled optimizations and so on.

It is reasonable to expect that different implementations of the JIT compiler would show different results on the same benchmark.

If you're asking why GraalVM CE doesn't show better results on this particular benchmark rather the philosophical question about the difference in general; here's a short explanation. All compilers are good at something, Graal for example has excellent escape analysis and inlining algorithms, which shows great results on the code that uses abstractions: allocates objects, calls methods, etc.

This particular benchmark fills an array with ints and runs a loop. Which probably doesn't exactly allow Graal to do things it's good at. So, this is an example of a microbenchmark C2 is better at. You can probably construct a similar benchmark which GraalVM CE would show superiority over OpenJDK (perhaps you can try this one: http://www.graalvm.org/docs/examples/java-simple-stream-benchmark/).

The GraalVM team runs a large corpus of benchmarks and that's the source of the knowledge that GraalVM CE is better. However, one needs to understand that reducing a complex set of benchmarks results to a single number is not the most meaningful thing for assessing performance of any particular piece of code and its workload. One should always strive to evaluate on their code.

Oleg Šelajev
  • 3,530
  • 1
  • 17
  • 25