Wednesday, January 28, 2009

Reflection can be costly

At least in Java.

A few days ago, I wanted to optimize a piece of code written in Kawa Scheme. You know how that works: you write something that seems to be good enough in most cases in terms of performance. Then you try it on a large input (a file several several megabytes long). And your code chokes. It does not crash, but takes way too much time to be usable in practice. But that's ok. Premature optimization is the root of all evil.

So I ran the profiler on my code to find out that it was using the Java reflection routines like hell. I was astonished, to say the least. My code was carefully written, with lots of type declarations (which are optional in Kawa) to prevent calls to the reflection API by the Kawa runtime. It seems that I was not careful enough. Or that I was expecting more from the Kawa compiler (I use a very old release, btw).

The problem was this. In a single static Kawa module, I was defining some classes and a few helper functions. Something along the lines of:

(module-name <mymodule>)
(module-static 'init-run)

(define-simple-class <ClassA> (<Object>)
(some-field))

(define (helper-function (an-a :: <ClassA>))
(do-something-with (field an-a 'some-field)))


Surprisingly, the reference to the some-field must be done through reflection! I'm not sure why, I don't master the inwards of the Kawa compiler.

Is there a solution to this problem? Yes. Put the class definitions in a module an the helper functions in a separate one. By doing this, the run time of my code dropped by 50% (a speedup of 2). There are many other possible improvements to speedup my code even further (data structures, algorithms, etc). But at least my code is now compiled the way I expect it to be.

0 comments: