Palindromes (Clojure vs. Common Lisp)
jng.imagine27.com
jng.imagine27.com
I had the big-test function run several times to actually show the real numbers (you need to prime the JVM to get a real indication of its speed):
~/Projects/palindromes % 〕bin/run-tests
1000 X ' amanaplanacanalpanama '
naive : (skipped)
fast : "Elapsed time: 449.397 msecs"
"Elapsed time: 182.432 msecs"
"Elapsed time: 149.721 msecs"
"Elapsed time: 162.804 msecs"
"Elapsed time: 159.086 msecs"
http://gist.github.com/264369 CPU SAMPLES BEGIN (total = 205) Sun Dec 27 10:52:27 2009
rank self accum count trace method
1 1.46% 1.46% 3 301336 clojure.template__init.load
2 1.46% 2.93% 3 300339 java.lang.Class.forName0
3 0.98% 3.90% 2 301445 clojure.lang.PersistentHashMap.containsKey
4 0.98% 4.88% 2 301456 clojure.lang.RestFn.invoke
5 0.98% 5.85% 2 301486 clojure.lang.PersistentVector$TransientVector.editableTail
6 0.98% 6.83% 2 301487 clojure.lang.PersistentVector$TransientVector.conj
7 0.98% 7.80% 2 301465 clojure.lang.PersistentVector.chunkedSeq
8 0.98% 8.78% 2 301489 palindromes$ext_centers__96$fn__101.invoke
9 0.98% 9.76% 2 301498 clojure.lang.PersistentList.first
10 0.98% 10.73% 2 301482 clojure.lang.PersistentVector$TransientVector.conj
I do see a lot of vector activity, but no smoking gun. As other people have pointed out in this thread, SBCL is notorious for being very good at recursing down big data structures. It's also notorious for being totally terrible with lots of other common tasks. I suspect this is just a case where the algorithm runs in such a way that languages that compile down all the way have a big advantage.I've asked some more experienced hands in #clojure on freenode to take a stab at it. There are a lot of recent optimization developments in the clojure-1.1.0 release that I don't know how to use well yet. Hopefully someone there can tackle it.
user=> (#'i27.palindromes/big-test)
1000 X ' amanaplanacanalpanama '
fast : "Elapsed time: 183.748 msecs"[1] LuaJIT 2
Neither would improve Clojure's performance.
Edit: Not that they would, necessarily, improve the speed of this benchmark that much.
There are many more compilers for dynamic languages that people usually don't know. I would be careful to claim 'fastest', given that only few advanced compilers in that area are known to people.
time sbcl --noinform --load palindromes.lisp --eval "(progn (big-test) (quit))"
30000 X ' amanaplanacanalpanama '
fast :
Evaluation took:
0.197 seconds of real time
0.191206 seconds of total run time (0.186952 user, 0.004254 system)
[ Run times consist of 0.006 seconds GC time, and 0.186 seconds non-GC time. ]
96.95% CPU
471,342,768 processor cycles
13,802,832 bytes consed
real 1m55.551s
user 1m51.954s
sys 0m0.778sLispWorks has no performance problem with both forms, though.
The reason is the SBCL pretty printer. If
*pretty-print*
is NIL, then both forms run fast in SBCL...Edit: Well, the last bit is a lie, it did the moment i set
*PRINT-PRETTY*. *print-pretty*
set to T, LispWorks runs fine."triton:palindromes jgrant$ sbcl --noinform --load [...]"