Re: Clojure vs Java speed



Oxide Scrubber wrote:
Jon Harrop wrote:
fft1976 wrote:
On Jul 28, 9:46 pm, Oxide Scrubber <jharri...@xxxxxxxxx> wrote:
fft1976 wrote:
Java: 1.5x slower than C as a rule of thumb.
I think it can achieve parity.
I disagree. I don't think the JIT can do much about the memory layout
of the data structures. Compare a vector of complex numbers or of 3D
vectors (NOT of pointers to them) in C/C++ and Java. Run some tests. I
did and I looked at others'.

Right. Writing such algorithms generically incurs huge performance
degradation in Java and Clojure.

The JIT can't, but the coder can. If you want a vector of N
double-precision complex numbers in Java that is contiguous in memory,
for example, you could use a Java array of 2xN doubles and index into it
appropriately.

That is not generic.

Look at my F# code here, for example:

http://flyingfrogblog.blogspot.com/2009/07/ocaml-vs-f-burrows-wheeler.html

Particularly the following abstraction-free parallelized sort:

let inline sort cmp (a: _ array) =
let inline swap i j =
let t = a.[i]
a.[i] <- a.[j]
a.[j] <- t
let rec qsort l u =
if l < u then
swap l ((l + u) / 2)
let mutable m = l
for i=l+1 to u do
if cmp a.[i] a.[l] < 0 then
m <- m + 1
swap m i
swap l m
if u-l > 1000 then
let m = m
let f = Tasks.Future.Create(fun () -> qsort l (m-1))
qsort (m+1) u
f.Value
else
qsort l (m-1)
qsort (m+1) u
qsort 0 (a.Length-1)

You cannot write code that is both that short and that efficient in Clojure.

Also, note that this same sort function can be used to sort value types such
as (unboxed) complex numbers with no alterations whatsoever. There is no
need to use syntactic abstractions to workaround any deficiencies, no need
to write custom index functions than handle special indexing for custom
types to work around the lack of value types.

For me, 1.5x is a good trade-off for safety though.
The JIT can't, but the coder can. If you want a vector of N
double-precision complex numbers in Java that is contiguous in memory,
for example, you could use a Java array of 2xN doubles and index into
it appropriately.

That workaround sucks because you've either lost polymorphism

With a language lacking syntactic abstractions like Java, perhaps.

You are on the JVM to interoperate with Java. Syntactic abstraction in
Clojure might help by allowing you to work around these fundamental
deficiencies in the JVM and Java but it is no panacea: the deficiencies
already damaged most of the code you are trying to interoperate with.

or, if you rewrite the entire compiler to use whole program optimizations
and change the calling convention globally, you've lost incremental
compilation and dynamic loading.

Such optimizations and dynamic loading are mutually exclusive in
languages without "eval" or similar capabilities available at run-time,
yes.

i.e. not Java.

This is fanboy fantasy, not reality.

Yes.

Stop attacking me.

I am not attacking you.

Clojure has some nice features but its most serious deficiencies are
inherited from the JVM and there is nothing Clojure can do about it, e.g.
value types and TCO. Moreover, according to Sun employees on the JVM
languages group this is never likely to be fixed.

Clojure has TCO; you just have to make your use of it explicit (and then
the compiler alerts you if it's not really in tail position).

Clojure's recur is only a special case, as I described here:

http://flyingfrogblog.blogspot.com/2009/04/when-celebrity-programmers-attack-guido.html

Clojure offers trampolines to cover more general cases of indirect tail
calls between different functions but it is much slower than real tail call
elimination.

I'm not sure what you mean by "value types".

http://msdn.microsoft.com/en-us/library/s1ax56ch.aspx

If you mean non-pointer types, Clojure has access to the full range of
Java non-pointer types: boolean, byte, short, int, long, float, double,
and char.

The ability to define custom value types is extremely valuable, most notably
in the context of technical computing where you want 32- and 64-bit complex
numbers, 2d vectors, 3d vectors in homogeneous coordinates, quaternions and
dozens of other types to be representable without the overhead of boxing,
heap allocating, stressing the garbage collector and so on.

It can't currently pass them across function call boundaries without
boxing and unboxing, but a) if the function call is consistent, the JIT
can inline it and optimize away the boxing and unboxing, and b) Clojure
has macros, so it's possible to inline a function not being itself
passed across function calls without losing the function-call syntax.

Only if your code is written entirely in Clojure which will not be the case:
you are on the JVM to reuse existing Java libraries but those libraries
expose these deficiencies of the VM by providing non-generic interfaces.

As an aside, the JVM even screwed up generics by using type erasure instead
of monomorphization and per-type instantiation at JIT => when the JVM fails
to optimize, generics are extremely slow.

Just make a macro version of the function, or even a macro that can take
a function's source code and spit out a macro version of that function.

That only works if the entire source is written in Clojure.

Anyway, the upshot of all this is that "Clojure has some nice features
but its most serious deficiencies are inherited from the JVM and there
is nothing Clojure can do about it" is simply false, because Clojure has
syntactic abstraction and definline and features like that which enable
a user to create seamless workarounds for those so-called "serious
deficiencies". (I especially like the ability to write macros that write
macros!)

Sure. Macros can be nice. But it is not feasible to work around deficiencies
in the VM that have already infected the Java code that you are trying to
interoperate with.

Perhaps the best solution for technical users would be
for languages like Scala and Clojure to target MLVM instead of the JVM

What is MLVM?

http://openjdk.java.net/projects/mlvm/

I suggest you read up on functional programming as well.

I am the author of the world's most profitable book on functional
programming.

If Scheme can be used for heavy number crunching, and it can, then
Clojure can too.

Scheme is not at all common for number crunching. Dynamic typing makes
performance too unpredictable and makes optimization too tedious. The vast
majority of number crunching applications are written in statically typed
languages because they are predictably fast.

--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
.



Relevant Pages

  • Re: Making Lisp popular - can it be done?
    ... Common Lisp could do the same as well in principle, ... to Java libraries. ... tons of libs available in the JVM (I think more than for anything ... can mix Clojure code with pure Java which can compete with and often ...
    (comp.lang.lisp)
  • Re: Road to Clojure Survey
    ... I am several orders of magnitude more productive with Lisp than with Java for the kinds of things I am interested in. ... When we ported all our code to Clojure, ... Neither does a profiler for Sun's JVM work with the Kaffe Virtual Machine, ... The first Java core API (and actually also the first public version of the Java language) was implemented in a rush, and some of the bad design decisions in the beginning are still hurting, because of "backwards compatibility" (which is sometimes used as a reason to block progress in some regards -- see genric types and type erasure --, but sometimes ...
    (comp.lang.lisp)
  • Re: Making Lisp popular - can it be done?
    ... Lisp conference/meeting. ... My Clojure program took around 105 msecs and the Java code did the job ... I have seen the JVM outperforming two different native Lisp compilers. ...
    (comp.lang.lisp)
  • Re: Road to Clojure Survey
    ... I am also occasionally following the progress of the Java platform, and there seem to be no serious efforts to overcome its weaknesses. ... but your productivity can still be hundreds of times greater if you do ... When we ported all our code to Clojure, ... The JVM has a nice performance. ...
    (comp.lang.lisp)
  • Re: Road to Clojure Survey
    ... The list of arguments that speak against the JVM and favour a CL ... A typical problem in the Java world, for example, is that you have to address different incompatible versions of Java itself. ... But how would it help here if Clojure were done in CL? ... you're making the assumption that the situation with regard to libraries in Common Lisp is much worse than it actually is. ...
    (comp.lang.lisp)

Quantcast