neat.
sounds like one must remember to use "-server" mode (to make sure one
is getting the HotSpot VM and its benefits over time) when starting up
the JVM for Closure, presumably the Closure scripts do that now?
sincerely.
The client-mode JVM most assuredly is HotSpot and does basically the
same optimizations, it just has different parameters for when to
JIT-compile and in-line, etc.
Client mode typically gives better start-up time (launch to first Java
code execution) and is more reluctant about deciding to JIT any given
block of bytecodes and / or to in-line any given set of instructions.
I don't think that server mode is generally a good idea. It's really
meant for and only really good for long-running programs (like
servers...).
> sincerely.
Randall Schulz
"JIT Compiler / What's the difference between the -client and -server
systems? / These two systems are different binaries. They are
essentially two different compilers (JITs) interfacing to the same
runtime system. The client system is optimal for applications which
need fast startup times or small footprints, the server system is
optimal for applications where the overall performance is most
important. In general the client system is better suited for
interactive applications such as GUIs. Some of the other differences
include the compilation policy,heap defaults, and inlining policy."
If you have something like GKrellM on your system and configure it to
display CPU utilization graphs (and if you have multiple CPUs or
cores), it can be interesting to run a given single-threaded, CPU-bound
program that runs for at least the better part of a minute using first
the client and then the server VMs. The client will have much more flat
utilization curve very close to 100% (of a single CPU / core) while the
server mode will show significantly higher and "spikier" utilization
curve, at least early on.
There's a little more information here:
<http://java.sun.com/products/hotspot/docs/whitepaper/Java_HotSpot_WP_Final_4_30_01.html>
An excerpt:
-==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-
Java HotSpot Client Compiler
The client compiler is tuned for the performance profile of typical
client applications. The Java HotSpot Client Compiler is a simple and
fast two-phased compiler. In the first phase, a platform-independent
front end constructs an intermediate representation (IR) from the
bytecodes. In the second phase, the platform-specific background
generates machine code from the IR. Emphasis is placed on extracting
and preserving as much information as possible from the bytecode level
(for example, locality information, initial control flow graph), which
directly translates into reduced compilation time. Note that the client
VM does only minimal inlining and no deoptimization.
Java HotSpot Server Compiler
The server compiler is tuned for the performance profile of typical
server applications. The Java HotSpot Server Compiler is a high-end
fully-optimizing compiler. It uses an advanced static single assignment
(SSA)-based IR for optimizations. The optimizer performs all the
classic optimizations, including dead code elimination, loop invariant
hoisting, common subexpression elimination, and constant propagation.
It also features optimizations more specific to Java technology, such
as null-check and range-check elimination. The register allocator is a
global graph coloring allocator and makes full use of large register
sets commonly found in RISC microprocessors. The compiler is highly
portable, relying on a machine description file to describe all aspects
of the target hardware. While the compiler is slow by JIT standards, it
is still much faster than conventional optimizing compilers. And the
improved code quality "pays back" the compile time by reducing
execution times of compiled code. The server compiler performs full
inlining and full deoptimization.
-==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==-
Randall Schulz
Dismayed by a recent request to embed Java code in Clojure code
(yuck), I've tried over the past week to address the only area in
which such an endeavor might be reasonable: to attain the arithmetic
performance of the Java primitives, and I'm happy to report much
success in making that possible directly in Clojure.
--
Albert Cardona
http://www.mcdb.ucla.edu/Research/Hartenstein/acardona
Never mind, I'm blind today. I see now that double is fully supported.
Primitive support is awesome:
>>> (load-file "/home/albert/Programming/fiji/plugins/Examples/embeded_java_compiler.clj")
In Clojure lists:
"Elapsed time: 60.273874 msecs"
"Elapsed time: 18.692337 msecs"
"Elapsed time: 12.910268 msecs"
"Elapsed time: 12.157825 msecs"
"Elapsed time: 11.790928 msecs"
nil
In janino java-compiled code:
"Elapsed time: 5.542431 msecs"
"Elapsed time: 8.884038 msecs"
"Elapsed time: 1.356255 msecs"
"Elapsed time: 1.276561 msecs"
"Elapsed time: 1.247018 msecs"
nil
In Clojure with primitives:
"Elapsed time: 21.794794 msecs"
"Elapsed time: 4.948466 msecs"
"Elapsed time: 1.01541 msecs"
"Elapsed time: 0.820752 msecs"
"Elapsed time: 0.792814 msecs"
nil
Code attached, depends on janino.jar
Albert
; Janino wrapper code from Fred Nicolier, as shared in the Clojure
googlegroups mailing list
; 2008-05-27
;
; Depends on janino.jar being present in the classpath
(import '(org.codehaus.janino ExpressionEvaluator
ClassBodyEvaluator
Scanner))
; Create a java class and single static method on the fly,
; with the given arguments and body
(defn jfun
[args body] (let [cl (new ClassBodyEvaluator)]
(.cook cl (str "static public Object f(" args ") {"
body
"}"))
(let [meth (first (.. cl
getClazz
getDeclaredMethods))]
(fn [& args]
(.invoke meth nil (into-array args))))))
; A benchmark: test the sum of a list of numbers
; in both pure Clojure and janino-compiled java bytecode
(defn bench []
; 1 - Pure Clojure
(defn sum1 [a] (reduce + a))
; 2 - Janino-compiled java code
(def sum2 (jfun "double[] a"
(str "double s = 0.0;"
"int N = a.length;"
"for (int k = 0; k<N; k++) {"
" s = s + a[k];"
"}"
"return s;")))
; 3 - Clojure with primitives declared
(defn sum3 [#^doubles a]
(areduce a i ret (double 0)
(+ ret (aget a i))))
;
(let [s (double-array 500000)
end 5]
(prn (dotimes x end (time (sum1 s))))
(prn)
(prn (dotimes x end (time (sum2 s))))
(prn)
(prn (dotimes x end (time (sum3 s))))))
(bench)