On Tuesday 22 April 2008 12:49:16 Antonio Cuni wrote:
> Jon Harrop wrote:
> > You generated code that turned out to be less efficient on the CLR in
> > this particular case but you cannot validly generalize that to all
> > "non-standard code".
>
> right, I can't generalize to all non-standard code, but it's surely true
> for the kind of non standard code pypy generates :-).
Sure. Generating exceptions unless absolutely necessary will be a very bad
idea on the CLR but it will also be a bad idea on the JVM because its
exception handling is slow.
> The exception inlining was only an example, there are other areas where
> the CLR jit was worse, like code that makes an heavy use of temp
> variables instead of leaving the values on the stack.
That's interesting.
> > Why didn't you use tail calls instead?
>
> I honestly don't see how tail calls could help here; could you show me
> an example please?
Sure. Consider the loop:
void run() {
for (int i=0; i<3; ++i)
if (foo(i) == 0) break;
bar();
baz();
}
Sounds like you were translating that into something like (F# code):
exception StopIteration
let run() =
try
for i=0 to 2 do
if foo i=0 then raise StopIteration
with StopIteration ->
()
bar()
baz()
But you could have translated it into:
let rec run_1 i =
if foo i=0 then run_2() else
if i<3 then run_1 (i + 1) else run_2()
and run_2() =
bar()
baz()
let run() =
run_1 0
Where both calls to the continuation "run_2" inside the body of the "run_1"
function are tail calls.
Tail calls have lots of advantages here. The JIT is likely to generate a
simple branch but it may well spot that the code blocks can be rearraged to
avoid even the branch! For example, it might rewrite the code into:
let rec run_1 i =
if foo i<>0 && i<3 then run_1 (i + 1) else
bar()
baz()
You can pass as many values as arguments to a continuation as you like and
they are highly likely to be kept in registers wherever your control flow
takes you (what were the exceptional and non-exceptional routes are now
symmetric) for the best possible performance. This facilitates lots of
subsequent optimizations by the JIT.
Doing a quick benchmark on this code, I find that 10^6 iterations using your
exception-based technique gives:
CLR: 24s
JVM: 1.3s
Holy smokes, the JVM is 18x faster!
Now try the tail calls (only available on the CLR):
CLR: 0.025s
Holy smokes, the CLR is 52x faster!
Optimizing exception handling in the JVM before implementing tail calls was
premature optimization, IMHO.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/products/?e
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "JVM
Languages" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/jvm-languages?hl=en
-~----------~----~----~----~------~----~------~--~---