381 views
Skip to first unread message

Joel Dice

unread,
Jul 15, 2011, 2:59:47 PM7/15/11
to clo...@googlegroups.com
Hi all,

I thought I'd share the results of a fun little excercise I did this
morning: running Clojure on a VM with native support for tail call
optimization and first class continuations. Any Schemers on this list
will probably appreciate it.

The VM in question is Avian (http://oss.readytalk.com/avian/), built with
optional tail call and continuation features enabled and using the OpenJDK
class library. It's not nearly as fast or sophisticated as e.g. Hotspot,
but it has some features that make it interesting for running non-Java
languages. I'm using the latest commit from the Git repository.

For example, here's what happens if you recurse too deeply using Hotspot:

$ java -cp clojure.jar clojure.main
Clojure 1.2.1
user=> ((fn this [n] (if (= n 1000000) n (this (+ n 1)))) 0)
java.lang.StackOverflowError (NO_SOURCE_FILE:0)
user=>

With Avian, there is no overflow, and we also get to play with
continuations:

$ ../avian/build/linux-x86_64-tails-continuations-openjdk-src/avian -Xmx512m -cp clojure.jar clojure.main
Clojure 1.2.1
user=> ((fn this [n] (if (= n 1000000) n (this (+ n 1)))) 0)
1000000
user=> (defn call-cc [function]
(avian.Continuations/callWithCurrentContinuation
(reify avian.CallbackReceiver
(receive [_ continuation]
(function (fn [result] (.handleResult continuation result)))))))
#'user/call-cc
user=> (call-cc (fn [continuation] (continuation "hello, world!")))
"hello, world!"
user=>

For more information about how continuations work in Avian, please see
http://oss.readytalk.com/avian/javadoc/avian/Continuations.html.

Anyway, I think this is an interesting experiment since it shows that
if/when tail call and continuation support are integrated into the JVM
officially (http://openjdk.java.net/projects/mlvm/), Clojure could benefit
with few or no modifications.

George Jahad

unread,
Jul 15, 2011, 3:49:53 PM7/15/11
to Clojure
very cool Joel! I'd also be interested in start up time of avian vs.
hotspot, i.e. does avian make it viable to use clojure for short,
quick scripts?
> For more information about how continuations work in Avian, please seehttp://oss.readytalk.com/avian/javadoc/avian/Continuations.html.

Joel Dice

unread,
Jul 15, 2011, 4:21:01 PM7/15/11
to Clojure
(sorry about the lack of subject in my original post; I've added one to
this email)

On Fri, 15 Jul 2011, George Jahad wrote:

> very cool Joel! I'd also be interested in start up time of avian vs.
> hotspot, i.e. does avian make it viable to use clojure for short,
> quick scripts?

Possibly. By default, Avian is noticeably slower to start up than
Hotspot, at least when using OpenJDK's class library. The boot process
for that library touches a lot of code in a lot of classes, and Hotspot
has several performance advantages to make quick work of it. On the other
hand, Avian can also be built to use its own class library, which allows
much faster startup. Unfortunately, it doesn't currently have all the
classes needed to support Clojure, and I haven't checked to see how much
would need to be added to make it work.

Avian also supports ahead-of-time compilation from Java bytecode to native
machine code, so it would be possible to create an executable with all the
OpenJDK and Clojure classes precompiled, thereby bypassing the need for
JIT compilation at runtime except for dynamically-loaded classes. That
would be faster, but I'm not sure by how much.

The ideal approach in terms of startup time would be to add whatever
classes needed to Avian's class library to support Clojure, use ProGuard
to shrink and optimize the combination of clojure.jar and the system class
library, and precompile the result into native code. I might take a stab
at that if I have time.

> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

Brent Millare

unread,
Jul 16, 2011, 12:02:05 AM7/16/11
to Clojure
That's really cool. I'm glad someone got it to work and with little
modification!
> >> optimization and first class continuations. �Any Schemers on this list
> >> will probably appreciate it.
>
> >> The VM in question is Avian (http://oss.readytalk.com/avian/), built with
> >> optional tail call and continuation features enabled and using the OpenJDK
> >> class library. �It's not nearly as fast or sophisticated as e.g. Hotspot,
> >> but it has some features that make it interesting for running non-Java
> >> languages. I'm using the latest commit from the Git repository.
>
> >> For example, here's what happens if you recurse too deeply using Hotspot:
>
> >> � $ java -cp clojure.jar clojure.main
> >> Clojure 1.2.1
> >> user=> ((fn this [n] (if (= n 1000000) n (this (+ n 1)))) 0)
> >> java.lang.StackOverflowError (NO_SOURCE_FILE:0)
> >> user=>
>
> >> With Avian, there is no overflow, and we also get to play with
> >> continuations:
>
> >> � $ ../avian/build/linux-x86_64-tails-continuations-openjdk-src/avian -Xmx512m -cp clojure.jar clojure.main
> >> Clojure 1.2.1
> >> user=> ((fn this [n] (if (= n 1000000) n (this (+ n 1)))) 0)
> >> 1000000
> >> user=> (defn call-cc [function]
> >> � � (avian.Continuations/callWithCurrentContinuation
> >> � � � (reify avian.CallbackReceiver
> >> � � � � (receive [_ continuation]
> >> � � � � �(function (fn [result] (.handleResult continuation result)))))))

Marek Kubica

unread,
Jul 16, 2011, 3:11:42 AM7/16/11
to clo...@googlegroups.com
On Fri, 15 Jul 2011 12:59:47 -0600 (MDT)
Joel Dice <joel...@gmail.com> wrote:

> The VM in question is Avian (http://oss.readytalk.com/avian/), built
> with optional tail call and continuation features enabled and using
> the OpenJDK class library. It's not nearly as fast or sophisticated
> as e.g. Hotspot, but it has some features that make it interesting
> for running non-Java languages.

Wow, didn't know that there is such a VM. Looks impressive, I should
keep it in mind.

regards,
Marek

Joel Dice

unread,
Jul 17, 2011, 10:24:25 PM7/17/11
to Clojure
On Fri, 15 Jul 2011, Joel Dice wrote:

> On Fri, 15 Jul 2011, George Jahad wrote:
>
>> very cool Joel! I'd also be interested in start up time of avian vs.
>> hotspot, i.e. does avian make it viable to use clojure for short,
>> quick scripts?
>
> Possibly. By default, Avian is noticeably slower to start up than Hotspot,
> at least when using OpenJDK's class library. The boot process for that
> library touches a lot of code in a lot of classes, and Hotspot has several
> performance advantages to make quick work of it. On the other hand, Avian
> can also be built to use its own class library, which allows much faster
> startup. Unfortunately, it doesn't currently have all the classes needed to
> support Clojure, and I haven't checked to see how much would need to be added
> to make it work.
>
> Avian also supports ahead-of-time compilation from Java bytecode to native
> machine code, so it would be possible to create an executable with all the
> OpenJDK and Clojure classes precompiled, thereby bypassing the need for JIT
> compilation at runtime except for dynamically-loaded classes. That would be
> faster, but I'm not sure by how much.
>
> The ideal approach in terms of startup time would be to add whatever classes
> needed to Avian's class library to support Clojure, use ProGuard to shrink
> and optimize the combination of clojure.jar and the system class library, and
> precompile the result into native code. I might take a stab at that if I
> have time.

I went ahead and pursued this. The upshot is that I can get Avian to run
a minimal Clojure script (containing just (println "hello, world!")) over
twice as fast as Hotspot by precompiling clojure.jar to native code.
These are the results on my 2.2GHz Xeon:

$ time java -jar ~/p/clojure-1.2.1/clojure.jar hello.clj
hello, world!

real 0m0.858s
user 0m1.004s
sys 0m0.040s
$ time ./build/clojure hello.clj
hello, world!

real 0m0.303s
user 0m0.264s
sys 0m0.036s

It turned out using OpenJDK's class library was not really the bottleneck,
which is good because Avian's built-in library would need to be augmented
significantly to run Clojure itself.

The main challenge is that Clojure touches a lot of code on startup, which
works the JIT compiler hard. Hotspot is better at this because it uses a
high-performance interpreter by default and doesn't JIT compile methods
until/unless it's deemed a win. Avian's not so smart; it has to compile
each method before it can be run. This makes Clojure a good test case for
profiling Avian's compiler, though, and I was able to cut startup time for
the JIT build by about 60% with a few judicious optimizations. Then I
moved on to an ahead-of-time (AOT) compiled build, which further reduced
startup time to to result above.

Ultimately, though, I don't think this is enough of an improvement to make
Clojure viable for short, quick scripts. 300ms is a long time for
printing "hello, world". I wonder how feasible it would be to make
Clojure rely more heavily on lazy initialization so there isn't as much
code to be run at startup for simple scripts. That's what I suspect needs
to be done to improve startup time on any VM.

Phil Hagelberg

unread,
Jul 17, 2011, 11:35:31 PM7/17/11
to clo...@googlegroups.com
On Sun, Jul 17, 2011 at 7:24 PM, Joel Dice <joel...@gmail.com> wrote:
> I went ahead and pursued this.  The upshot is that I can get Avian to run a
> minimal Clojure script (containing just (println "hello, world!")) over
> twice as fast as Hotspot by precompiling clojure.jar to native code. These
> are the results on my 2.2GHz Xeon:

This is fascinating. I never would have guessed that a JVM capable of running
Clojure could be implemented in 50kLOC.

> Ultimately, though, I don't think this is enough of an improvement to make
> Clojure viable for short, quick scripts.  300ms is a long time for printing
> "hello, world".  I wonder how feasible it would be to make Clojure rely more
> heavily on lazy initialization so there isn't as much code to be run at
> startup for simple scripts.

For what it's worth, I believe work in this direction has been done in
1.3 with the
goal of improving Android performance, though it's unclear how thorough it
was and if there's much remaining that could be done.

I tried Leiningen on Avian and it caused Maven's dependency injection framework
to choke, which is not terribly surprising. Perhaps once we've ported it over
to Aether it will fare better.

-Phil

Joel Dice

unread,
Jul 18, 2011, 12:10:09 AM7/18/11
to clo...@googlegroups.com
On Sun, 17 Jul 2011, Phil Hagelberg wrote:

> I tried Leiningen on Avian and it caused Maven's dependency injection framework
> to choke, which is not terribly surprising. Perhaps once we've ported it over
> to Aether it will fare better.

My goal is for Avian to be able to run anything HotSpot can when using
OpenJDK's class library, so I'll investigate this and fix it if I can.
FWIW, it handles Spring's dependency injection just fine, at least as far
as I've tested it.

Phil Hagelberg

unread,
Jul 18, 2011, 12:22:31 AM7/18/11
to clo...@googlegroups.com
On Sun, Jul 17, 2011 at 9:10 PM, Joel Dice <joel...@gmail.com> wrote:
> My goal is for Avian to be able to run anything HotSpot can when using
> OpenJDK's class library, so I'll investigate this and fix it if I can. FWIW,
> it handles Spring's dependency injection just fine, at least as far as I've
> tested it.

If you need any help getting it going I can point you in the right
direction, but
for what it's worth the problem seems to be orthogonal to Clojure.

-Phil

Reply all
Reply to author
Forward
0 new messages