recently, I sad down to make a very little performance comparison between Groovy 2.0 with @CompileStatic and Java. See this article. Here are the measurements for Kotlin 0.1.2580:
I know, a lot of people to a lot of very difficult work in a very smart and clever way and then someone comes along with performance and security ans stuff ... But I just wanted to drop this as a note since I was interested in the figures.
Below find the code. Note, that there is no measurement for the “ternary if” case since not meaningful in Kotlin.
open class Fib() {
class object {
fun fibStaticIf(n: Int) : Int {
if(n >= 2)
return fibStaticIf(n - 1) + fibStaticIf(n - 2)
else
return 1
}
}
fun fibIf(n: Int) : Int {
if (n >= 2)
return fibIf(n - 1) + fibIf(n - 2);
else
return 1;
}
}
fun main(args : Array<String>)
{
var start = System.currentTimeMillis();
Fib.fibStaticIf(40);
System.out.println("Kotlin(static if): " + (System.currentTimeMillis() - start) + “ms”);
At least the IDE shows some red lines. So I thought I cannot be done at all in Kotlin. Somebody might not have formatted the code that way to begin with. Only some former Smalltalk developers would have had the idea to format the code that way ;-). When playing with the code a bit in order to prepare a post to ask why the code above does not work in Kotlin I figured out that this here does compile, though:
Thanks a lot for your work. It seems that we must be doing something suboptimal in the byte code, as, ideally, Kotlin should be exactly as fast as Java.
We'll look into it
- The Kotlin static version is slower than plain Java. Of course, Kotlin isn't using invokestatic, but rather invokevirtual on the class object.
Putting this code into a class object is rather strange. To correspont to Java's "static" case, it should be a plain package-level function. Then the invokevirtual problem will be gone, I think.
- The Kotlin static version becomes faster if we prefix the recursive calls with "this.". Doing so will basically remove the bytecode instructions that fetch the static class object field and the execution speed matches the instanced version. The Kotlin compiler could probably do this automatically.
Good point.
- Decompiling the Kotlin code reveals a lot of extra bytecode instructions, compared to plain Java. These are mostly lots of "nop" and some "athrow"s. Not sure what's going on here, but more bytecode instructions do affect JIT effectiveness (negatively), even if they don't do anything.
I can confirm performance is now the same between Kotlin and Java (instanced versions), without using this. on the class object calls. I can also confirm that moving the class object methods to the package level matches the performance of the static Java versions.
The redundant bytecodes remain on some of the compiled methods, but I think you didn’t make any changes regarding those. They don’t seem to affect performance in this particular case anyway.
That's interesting.
Seems to be something new introduced in ASM4 probably (part of their compute frame algorithm) - never saw it before.
Unlikely to effect performance but still ugly.