
Justin Gehtland over at Relevance has a post about large number performance, Ruby vs Java. How quickly can you calculate 2^2^16 in either one. So I went there, added my 2 cents, and followed the comments stream.
Shortly after, two readers chimed in, measuring performance using time. As in:
time ruby test.rb time java Test
A part of me was screaming inside: “You’re not measuring the calculation! You’re measuring the cost of loading the runtime engine and library! You’re looking at the wrong thing!”
Understand this. You can’t just measure Java with time. You need to wait for the JVM to fire up and load the classpath, then you run a few iterations, depending on whether you’re running -client or -server, to let the JIT warm up, and then, and only then, you hit start on the timer.
That’s how you measure things.
But I got distracted by so many other things, I forgot to tell them that. And good thing I didn’t. Because, between then and now a few things happened that made me change my mind.
What’s important is not how long it takes the JIT to find its bearings, what’s important is how long it takes to complete the job. Period.
Every time I run Ant, I have to wait for it to complete. It doesn’t matter that Ant gets incrementally faster in each step, I guess if I wait long enough it will start doing quantum computing. I’m still going to wait five minutes for the build to finish. Five minutes of sitting there and doing nothing.
It doesn’t matter that in production the server will get the code to run 5x faster, I’m still going to wait a few minutes between checking a change and seeing the code crash, so I can try to narrow down on the bug, repeated several times over the next hour.
And it doesn’t matter that Java can calculate that big number 10x faster than Ruby if it’s going to take me five minutes to write that program in Java, where all I need to do is:
ruby -e 'puts 2**2**2**2**2'
There’s a reason why Java became such a hard language to work with, why the development cycle is so painfully slow, and why it’s all Big Design Up Front. It lives and dies by the JIT. Everything is measured and optimized for the JIT. Not the user, not the developer.
So from now on, I’m going back to my trusty time. No more warm ups, no more waiting. I’m measuring from the second I start waiting until it’s done.
PS: I’m not complaining about the benefit of a JIT that can speed up critical section code: that’s one of the better features of Java, and hopefully will translate well to JRuby. I’m criticizing the methodology of discounting real wait time to get more impressive performance numbers, and any design mistakes the follow from measuring the wrong thing.
Photo by lukasd2009