Search code examples
javascalajvmperformance-testing

Scala perf: Why is this Scala app 30x slower than the equivalent Java app?


I am a very proficient C# developer, but need to start writing code that works on the JVM. The Java language is feature poor compared to C# these days, so I was interested in the features that Scala offers.

However, when hearing that in Scala, all operators are simply methods, I became suspicious of the performance impact that would have on math-heavy computations (which is important for the types of applications my team writes)

So I ran some simple int based tests, and find that Scala is about 30x slower than the equivalent Java code. Not good! Can anyone tell me what I'm doing wrong? or how to improve the computational performance of the scala example to be on par with Java?

UPDATE1: as pointed out by the first two answers, I was being a super-noob and running this in the IntelliJ IDE. I don't know how to run the scala app via the java command line, which may be an IntelliJ issue. Thanks for the help guys, I'll need to investigate simple commandline execution of scala before I continue with perf testing, as the IDE given results are obviously too inaccurate.

UPDATE2: Luigi in the comments says in IntelliJ he gets equal times, so it seems that my wild difference isn't due to IntelliJ? Any other ideas on what this could be? I'll try getting this running via command line and post an update with my results.

UPDATE3: after running this via commandline, I get the same 30x perf difference.
My computer is a 3core AMD x64 3.4Ghz, running J2SE 6 jdk 64bit 1.6.0_31, Window7.

Here are my runtimes: Java: 210ms.
Scala: between 2000 and 7400ms (generally the 7000 range)

so, i suppose the question is still open. why is scala running so slow on my platform? something with the java 64bit runtime, or with Java 6?

runtime versions:

C:\Users\jason>java -showversion
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)

C:\Users\jason>scala
Welcome to Scala version 2.9.1-1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_31).

UPDATE 4 while my original test has a 30x difference, increasing the iterations to 100000000 causes the difference to shrink to about 33%, so it seems scala was still being dominated by some unknown initialization cost on my machine. i'll close this with the highest rated answer as i don't think we'll find out the performance problem, due to no one except me seeing the issue :(

*UPDATE 5, SOLUTION: based on the help from the 2 answers i got, i figured out the problem, see my answer below for more details (summary: the first call to System.nanoTime() takes a long time) *

Here are my sample apps:

//scala
object HelloWorld {
  //extends Application {
  def main(args: Array[String]) {
    println("hello scala")
    var total: Long = 0
    var i: Long = 0
    var x: Long=0;
    //warm up of the JVM to avoid timing of runtime initialization
    while (i < 100000)
    {
      x=i;
      x += x - 1;
      x -= x + 1;
      x += 1;
      x -= 1;
      total += x;
      i+=1;
    }
    //reset variables
    total = 0
    i = 0;
    //start timing
    var start: Long = System.nanoTime

    //run test
    while (i < 100000) {
      x=i;
      x += x - 1;
      x -= x + 1;
      x += 1;
      x -= 1;

      total += x;
      i+=1;
    }
    var end: Long = System.nanoTime
    System.out.println("ms, checksum = ")
    System.out.println((end - start) / 1000)
    System.out.println(total)
  }
}

and here is the java equivalent, 30x faster

//java
public class app {
    public static void main(String[] args)
    {
        String message = "hello, java";
        System.out.println(message);
        long total = 0;
        //warm up of the JVM to avoid timing of runtime initialization
        for(long i=0;i< 100000;i++)
        {
            long x=i;
            x+=x-1;
            x-=x+1;
            x++;
            x--;
            total+=x;
        }
        //reset variables
        total = 0;
        //start timing and run test
        long start = System.nanoTime();
        for(long i=0;i< 100000;i++)
        {
            long x=i;
            x+=x-1;
            x-=x+1;
            x++;
            x--;
            total+=x;
        }
        long end = System.nanoTime();
        System.out.println("ms, checksum = ");
        System.out.println((end-start)/1000);
        System.out.println(total);
    }
}

Solution

  • So, I guess I figured out the answer myself.

    The problem is in the call to System.nanoTime. Doing this has some initialization cost (loading up the Java base libraries, etc) which is much less expensive to load when called from the Java runtime than from the Scala runtime.

    I prove this by changing the initial value of total, instead setting it to

    var total: Long = System.nanoTime()
    

    This is added before the first "warm up" loop, and doing so now makes both versions of the app (Java and Scala) run at the same time: about 2100 for 1000000 iterations.

    Thanks for your guys' help on this, I wouldn't have figured this out without your assistance.

    ps: I'll leave the "accepted answer" as-is because I wouldn't have tracked this down without his help.