Friday, April 6, 2012

Java vs Groovy vs Scala Simple Performance Test - 2

As my previous post showed, the performance of Scala was as good as Java but Groovy was obviously slower than both of them while running the Fibonacci number test and the Fibonacci number calculation was done in the recursive way.
Now let's try to revise the implementation to the for loop calculation and see their performance again.

Java
    public long fib(long n) {
        long result = 0;
        long[] prevResult = new long[]{0, 1};
        for (int i = 2; i <= n; i++) {
            result = prevResult[0] + prevResult[1];
            prevResult[0] = prevResult[1];
            prevResult[1] = result;
        }
        return result;
    }
Groovy
    def long fib(long n) {
        def result = 0
        def prevResult = [0L, 1L]
        for (int i = 2; i <= n; i++) {
            result = prevResult[0] + prevResult[1]
            prevResult[0] = prevResult[1]
            prevResult[1] = result
        }
        return result
    }
Scala
  def fib(n: Long): Long = {
    var result = 0L
    val prevResult = Array(0L, 1L)
    for (i <- 2L to n) {
      result = prevResult(0) + prevResult(1)
      prevResult(0) = prevResult(1)
      prevResult(1) = result
    }
    return result
  }

Results:
n implementation result Java Groovy Scala
10 for-loop 55 0 (ms) 1 (ms) 0 (ms)
10 recursive 55 0 (ms) 8 (ms) 13 (ms)
30 for-loop 832040 0 (ms) 1 (ms) 0 (ms)
30 recursive 832040 14 (ms) 59 (ms) 14 (ms)
50 for-loop 12586269025 0 (ms) 0 (ms) 1 (ms)
50 recursive 12586269025 153909 (ms) 285553 (ms) 156361 (ms)
100 for-loop 3736710778780434371 0 (ms) 1 (ms) 2 (ms)
500 for-loop 2171430676560690477 0 (ms) 7 (ms) 9 (ms)

I highlighted the previous test results to compare this ones.

No suprise, the for-loop boost the performance for all of them.

While n=50, Java and Scala took about 150sec and Groovy took about 285sec in the previous recursive tests. With the for-loop implementation, they all took less than 1ms. Even while running the for-loop with n=100 and n=500, the calculation time was still amazingly fast.
This can be explained by the time complexity where the recursive implementation is O(2^n) and the for-loop one is just O(n). This also demonstrates why using the right algorithm is so important.

An interesting observation was that while the calculation is taking very short time, Groovy was actually faster than Scala by a little bit. I am not sure why but it should be save to ignore the 1/2ms difference.

Base on all the results, Java was always the fastest and Scala outperformed Groovy while taking long calculation. When Groovy2 and/or JDK7 is out in Mac, I will probably do the test again and see if Groovy will catch up with the performance.

Thursday, April 5, 2012

Java vs Groovy vs Scala Simple Performance Test

There are a lot of interesting discussions/comparions about the performance between these JVM languages. 
To see the real differences in action myself, I am writing some simple tests using the well-known Fibonacci number. 

My environment:
Mac OS X - Snow Leopard
Java 1.6.0_26
Groovy 1.8.6
Scala 2.9.1-1

I implemented the Fibonacci in the recursive way and before I started, I ran some loops to "warm up" the JVM first to make the results more reasonable.
Anyway, here are the implementations:

Java
    public long recursiveFib(long n) {
        if (n == 0) {
            return 0;
        } else if (n == 1) {
            return 1;
        }
        return recursiveFib(n - 1) + recursiveFib(n - 2);
    }
Groovy
    def long recursiveFib(long n) {
        if (n == 0) {
            return 0
        } else if (n == 1) {
            return 1
        }
        return recursiveFib(n - 1) + recursiveFib(n - 2)
    }
Scala
  def recursiveFib(n: Long): Long = {
    if (n == 0) {
      return 0
    } else if (n == 1) {
      return 1
    }
    return recursiveFib(n - 1) + recursiveFib(n - 2)
  }
n result Java Groovy Scala
10 55 0 (ms) 8 (ms) 13 (ms)
30 832040 14 (ms) 59 (ms) 14 (ms)
50 12586269025 153909 (ms) 285553 (ms) 156361 (ms)

From the above table, we can see that the differences increase as n increases. One interesting thing was that while running recursiveFib(10), Scala was the slowest one. Why? I am not very sure. Probably because of the JVM wasn't "warm up" enough or there were some internal Scala's stuffs going on. That's probably a separate topic to look at.
For recursiveFib(30), Groovy is like 4 times slower than Java and Scala but probably most human can't notice the difference between 14ms and 59ms.
However, when it comes to recursiveFib(50), even Groovy is just two-fold of Java and Scala, the difference is big as 150sec vs 285sec.
Overall, Scala's performance is almost as good as Java and this is probably because of the static compile time behavior of Scala while Groovy has a long way to catch up its performance with its dynamic nature.

How to improve the Groovy performance? We can run the performance bottleneck part in Java. This for sure can increase the performance overall. However, in some cases, we can actually improve the performance by just using a right solution. For this Fibonacci number, we can use for loop instead of this recursive implementation to boost the performance. I am going to test the differences again in the next blog.