Clojure vs Java speed (was: Alternatives to C)

F

fft1976

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.

This is fanboy fantasy, not reality. If I have a library for dealing
with 3D vectors, I'm not going to lay out my data in flat arrays and
copy the vectors back and forth. Also, this trick won't work with non-
homogeneous records.
True. If you want a deep copy you will have to implement it yourself.

That's what I wrote. What was the point of your comment?

Or
you can make a deepCopy static utility method that exploits
"Serializable" to deep copy anything that's serializable simply by
serializing and deserializing it (which can use memory, or a temp file,
and not much memory if you make an auxiliary class implement both
InputStream and OutputStream, with its OutputStream methods writing to a
growable buffer and its InputStream methods consuming (possibly blocking
if necessary) from same. Closing the OutputStream aspect EOFs the
InputStream aspect. Then wrap in ObjectInput/OutputStream. You can use a
BlockingQueue of byte arrays of length 8192 (or whatever), serialize to
one end and deserialize from the other in concurrent threads, and it
will tend to not use much memory. Limit the BlockingQueue length to 1
item and it will never use much more than 8Kbyte (the OutputStream
aspect will block until the InputStream aspect consumes from the queue).
Ouch...

If the bulk of the time is spent performing arithmetic operations on
just a few values,

We are talking number crunching here, not useless pissing contests,
like calculating the digits of Pi.
If the arithmetic is bignum, the bulk of your time will be spent
performing individual bignum operations.

Contrary to what the term sounds like, number crunching is rarely
about bignums.
If the arithmetic is on smallnums in arrays and the computations are
mostly mutations, then you may want to use Java arrays,

That's what I said.
In practice,
Clojure access to Java arrays, even primitive arrays, seems to
be slow. This may be addressed in a future version.

Yeah, yeah...

I noticed that you decided to delete this, by the way:

In practice, experts seem to
agree that Clojure is 5-10 times slower than Java:

http://groups.google.com/group/clojure/msg/92b33476c0507478

(relevant follow-up set)
 
S

SG

This is fanboy fantasy, not reality. If I have a library for dealing
with 3D vectors, I'm not going to lay out my data in flat arrays and
copy the vectors back and forth. Also, this trick won't work with non-
homogeneous records.

Agreed. I can confirm that C++ is much better for my kind of number
chrunching tasks. I have to solve big nonlinear optimization problems
and switched from Java to C++ two years ago. I'm not looking back. The
ability to write user-defined types that are handled like builtin
types (no indirection, no heap allocations) combined with "true
genericity" is key.

Are we talking about the language "Clojure" (lisp dialect) or the
cloSure proposal for Java 7?

Cheers!
SG
 
O

Oxide Scrubber

fft1976 failed for the second time to respect the Followup-To header:
This is fanboy fantasy, not reality.

Stop attacking me. I have done nothing to deserve your repeated flamage.
You must have the wrong target. Recheck and then go flame the correct
target.
If I have a library for dealing with 3D vectors, I'm not going to lay
out my data in flat arrays and copy the vectors back and forth.

If you have a library for dealing with X, in any language, you'll use
the data as laid out by that library.

A performant Java library for numerics should lay out its data in an
appropriate manner so as to achieve performance, of course.
Also, this trick won't work with non-homogeneous records.

It will work for records of a primitive type, such as double. It won't
work if for some odd reason you want to mix ints and doubles in the same
vector, no. In that unusual case you may be better off either using
multiple separate arrays, but allocated one right after the other so
probably close together, one with all the ints and one with all the
doubles, or else resorting to JNI to implement some things.

No ouch. You'd only have to do this once, and then deepCopy would work
on every serializable type in Java, including ones that didn't exist
when you wrote deepCopy.
We are talking number crunching here

Yes, I know.
Contrary to what the term sounds like, number crunching is rarely
about bignums.

I never said otherwise.
That's what I said.

Now that the debate is over, please respect the followup-to header.

It would have been better, of course, had you chose to end it *before*
demonstrating to the entire world that you're unimaginative and
ignorant. Ignorant of numerous performance tricks for Java and other JVM
languages, ignorant of performant functional algorithms for various
things, and ignorant of the actual facts from timing operations, which
show all three languages capable of achieving the same top speed in
numeric calculations. And unimaginative enough not only to be unable to
think up any of these things, but also unable to think up arguments that
aren't laced heavily with ad hominems and other rhetoric. "This is
fanboy fantasy, not reality," "What was the point of your comment?,"
"Ouch...," "We are talking number crunching here, not useless pissing
contests," "Yeah, yeah...," and so forth do not constitute rational
arguments.
 
O

Oxide Scrubber

SG said:
Agreed. I can confirm that C++ is much better for my kind of number
chrunching tasks. I have to solve big nonlinear optimization problems
and switched from Java to C++ two years ago. I'm not looking back. The
ability to write user-defined types that are handled like builtin
types (no indirection, no heap allocations) combined with "true
genericity" is key.


Are we talking about the language "Clojure" (lisp dialect) or the
cloSure proposal for Java 7?

The former.

And since you clearly didn't even know what "Clojure" was referring to,
your claims that C++ is necessarily "much better" ring hollow.

In fact, Clojure, having macros and access to Java arrays, is capable of
working with contiguous blocks of doubles or similarly and treating
them as structured into discrete complex numbers, vectors, or
what-have-you, and is capable of "true genericity". Lisps in general are
much more capable of "true genericity" than C++ is.

Even Java can be made to perform at C-like speeds with suitable
structuring of your data; it's just that you can't always encapsulate
that data into discrete Java objects and keep that performance.
Although, objects allocated sequentially tend to be allocated at
close-together memory locations in Java, and the new G-1 garbage
collector should help further with keeping objects that are used
together close together in memory, improving locality of memory access
patterns.

Regardless, actual benchmark numbers show all three languages achieving
comparable speeds at comparable numerical tasks, IF the code in each
language is performance-tuned by someone reasonably expert in the use of
that language. Of course, when an ignoramus such as either of the
preceding posters, who clearly know only the bare bones about Java and
nothing at all about Clojure, attempt to write performant code in those
languages, they can expect to do poorly.

And of course, the savings from using a smart algorithm beat a
few-percent or even a few-tens-of-percent difference in raw execution
speed anyday.

(defn fib[n]
(nth (map second (iterate (fn [[a b]] [b (+ a b)]) [0 1])) n))

in clojure will be hugely faster than

int fib (int n) {
if (n == 0 || n == 1) return 1;
return fib(n - 1) + fib(n - 2);
}

anyday. (And won't wrap after 1836311903, or, worse, after 28657, either.)
 
F

fft1976

fft1976 failed for the second time to respect the Followup-To header:

Everyone who decides to reply to this joker, watch out: he's silently
adding "Followup-To: alt.olympics" to his messages, trying to trick
you into not posting here, so he would have the last word.

Is this what Clojure fanboys must resort to when they lose an
argument? I thought Haskell and Common Lisp had the worst fanboys till
today.
 
O

Oxide Scrubber

fft1976 said:
Everyone who decides to reply to this joker, watch out: he's silently
adding "Followup-To: alt.olympics" to his messages

No, I am not. I am adding a followup-to for atl.olympics. (Note spelling.)

It's currently an empty newsgroup, so it seemed appropriate as a place
to redirect your useless and illogical flamage.
Is this what Clojure fanboys must resort to when they lose an
argument?

I wouldn't know, since that's never happened to me.
 
L

Lew

fft1976 said:
Everyone who decides to reply to this joker, watch out: he's silently
adding "Followup-To: alt.olympics" to his messages, trying to trick
you into not posting here, so he would have the last word.

Is this what Clojure fanboys must resort to when they lose an
argument? I thought Haskell and Common Lisp had the worst fanboys till
today.

fft1976 is the one who "silently" decided to drag this flamewar into
clj.programmer. We were doing just fine without it.

f/u set to comp.programming and please keep your flamewar out of clj groups.
 
F

fft1976

Yes. 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.

Not as far as speed is concerned, in practice. If you give up 1.5x
speed by going from C++ to Java, and 5-10 by going from Java to
Clojure [1], than the latter is much more relevant.

I actually think 1.5x is a good trade for memory safety, as I stated.
It's beyond me why this "(e-mail address removed)" fella decided to argue
about it, when he obviously knows nothing about number crunching. What
a nut case.

[1] http://groups.google.com/group/clojure/msg/92b33476c0507478
 
L

Lew

fft1976 said:
I actually think 1.5x is a good trade for memory safety, as I stated.
It's beyond me why this "(e-mail address removed)" fella decided to argue
about it, when he obviously knows nothing about number crunching. What
a nut case.

Flame war, flame war, flame war. Go on to comp.programming and have a great time.
 
K

Keith H Duggar

Agreed. I can confirm that C++ is much better for my kind of number
chrunching tasks. I have to solve big nonlinear optimization problems
and switched from Java to C++ two years ago. I'm not looking back. The
ability to write user-defined types that are handled like builtin
types (no indirection, no heap allocations) combined with "true
genericity" is key.

I second this opinion. Statically typed UDT + templates and also
operator and function overloading are big wins for C++ numerical
work. Despite its faults, C++ provides an interesting and useful
mix of capabilities in my opinion and C++0x makes it even better.

KHD
 
O

Oxide Scrubber

Jon said:
fft1976 said:
This is fanboy fantasy, not reality.
Yes. 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.
Not as far as speed is concerned, in practice. If you give up 1.5x
speed by going from C++ to Java, and 5-10 by going from Java to
Clojure [1], than the latter is much more relevant.

Lack of value types can cost you a lot more than 1.5x though. Try writing an
FFT over boxed complexes and Java and compare with unboxed in C99, for
example.

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).

I'm not sure what you mean by "value types". If you mean immutable types
with value-equality semantics remaining consistent over time, then
Clojure is chock full of them, even its collection types can be used as
value types, so as keys in maps for instance.

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.

It can't currently pass them across function call boundaries without
boxing and unboxing, but you can work around that using definline or a
macro.
This goes way beyond number crunching though. Lots of applications benefit
enormously from value types. They are used extensively in the .NET
framework.

The JVM has several non-pointer types too, and does not have the
Microsoft taint.
 
O

Oxide Scrubber

Jon said:
Look at vertices in XNA for a simple example where value types on .NET
facilitate efficient direct interop with the graphics hardware.

If you want to do direct interop with the graphics hardware on the JVM,
you use Java2D/Java3D.
Ad hominem means personal attack.

Actually, "argumentum ad hominem" means "argument against the man",
which means instead of arguing against a point someone made you argued
that the identity or nature of the person making it somehow invalidates
it. The identity or nature of the person is, however, irrelevant, so
such arguments are fallacies.

Besides, calling me a "fanboy" whilst implying I'm delusional IS a
personal attack.
Balderdash.

[argues some more]

Listen up, fuckface. I have personally written number-crunching Clojure
code and measured its performance. You are asking me to disbelieve the
evidence of my own eyes, just because your faith asserts that I can't
possibly have seen what I've seen.

I think we're done here. Not only are you clearly irrational, but you've
managed to frustrate me enough for me to use a cuss word. :p
Please familiarize yourself with the basic terminology

Please do not condescend to me. I've been working with, and programming,
computers for a quarter-century, and I've been doing number crunching
for almost as long. And I, unlike you, base my beliefs upon evidence
instead of faith.
No, this is impossible to do

But I've done it.

This is it. You basically just called me a liar there. I think I'm done
trying to reason with you. I judge that your reputation as a troll is
well-deserved. (Note that I had ignored that until now, choosing to base
my opinion upon evidence rather than hearsay. That is the difference
between us. But now that enough evidence is in, I find myself agreeing
with the hearsay. Funny, that.)
array of structs that contain both ints and floats, for example. There is
no way to represent that on the JVM because you only have an array of ints
or an array of floats but not an array of structs composed of both ints and
floats.

I don't suppose the concept of keeping separate-but-parallel arrays of
ints and floats (and wrapping this structure in a data abstraction
layer) occurred to you?
But the complex numbers and vectors do
So?

which incurs massive performance degradation.

Codswallop.

I've debunked that argument enough times already; I won't bother to
repeat myself again here.

Yes.

Until you have learned something about the performance characteristics
of *modern* garbage collectors, you are not qualified to continue this
argument.
Because you will be calling library functions.

To do the numerics? Perhaps not. And if so, they shall be functions in a
high-performance numerics library. Either way, you lose.
Or it might be JLAPACK

Or it might be Santa Claus. You can throw all kinds of "might be"s out
there, and as long as it also "might not be", you still lose.
or it might be OpenGL which has had its performance degraded

That's news to me. I'm sure it'll be news to id Software too when they
hear it.
The JVM is also extremely slow to invoke external code (an order of
magnitude slower than the CLR, for example) so those libraries also suffer
from limitations of the JVM.

That would be a problem if you were stupid enough to call into JNI for
every single add, subtract, or multiply. Normally, you'd have larger,
longer-running tasks (perhaps entire number-crunching loops) called via
JNI, if you were using JNI. Not that you have to to get performance on a
*modern* JVM.
Absolutely.

Ah, you're finally starting to see reason.
Clojure code is either short and slow or long and fast

You have just capitulated by admitting that Clojure code can be fast.
but not short and fast like the F# example I already posted.

Well, actually, if you tuck those support macros and functions away, the
same algorithm can be expressed just as concisely and run just as fast;
though it will call those macros and functions. Macros and functions
that can be reused in many such algorithms, or even made available as a
library. Using them is no more "cheating" or "bloating" than using GMP
from your C code would be.
Not if you want to compare with languages like F# that inherit
well-implemented generics from their VM.

Compare them regarding what? Not speed. It looks like you're on about
static typing now, which is a completely different flamewar. And one
this newsgroup has already had recently, if I'm not mistaken.
You cannot write "a macro that can take a function's source code and spit
out a macro version of that function" unless all of those functions are in
Clojure.

Only the function to be macro-ized and the functions calling it have to
be written in Clojure. Furthermore, your objection is begging the
question. It assumes what you'd set out to prove, namely that "written
in Clojure = bad".

Irrelevant. We are discussing Clojure and other JVM languages.

Microsoft associated and therefore evil.

Yes.

You have lost.

Have a nice day.
 
O

Oxide Scrubber

Jon said:
Oxide said:
Jon said:
fft1976 wrote:
This is fanboy fantasy, not reality.
Yes. 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.
Not as far as speed is concerned, in practice. If you give up 1.5x
speed by going from C++ to Java, and 5-10 by going from Java to
Clojure [1], than the latter is much more relevant.
Lack of value types can cost you a lot more than 1.5x though. Try writing
an FFT over boxed complexes and Java and compare with unboxed in C99, for
example.
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 has recur and trampolines, both of which are workarounds for the
lack of TCO.

They are means of implementing TCO.

I'm sorry, but I prefer people to actually discuss something rather than
try to send me off to some web site. Especially some Microsoft web site.
Value types are user-defined non-pointer types, i.e. structs.

There are several different uses of the phrase "value types". Why did it
take you this long to disambiguate?
For example, you can define a complex type as a struct of two doubles
or a Vertex type as a struct of three floats and three int16s.
Fascinating.

In Clojure, you can workaround the lack of arrays of complex numbers using
arrays of floats and syntactic abstraction to fudge the difference
(Greenspunning instantiation-per-type generics which the JVM also lacks)
but you cannot work around the general case.

Sure you can. For instance, for an array of your oddball Vertex type
above, use an array of 3N floats and a separate array of 3N int16s.
Allocate them one right after the other and you'll still have good
memory access locality, and you won't have much unboxing overhead (two
"boxes" means not much more unboxing than one and far less than N).
This incurs huge performance degradation for programs on the JVM
Hogwash.

and can make direct interop impossible (e.g. the JVM cannot express
XNA).

Why do you think the JVM should have to "express XNA", whatever that
means? It can probably either use something else at least as good, or
else do it with one extra layer of indirection, a layer that becomes
very cheap after JIT optimization and hardware branch prediction and
caching.

Regardless, it becomes apparent (from all your mentions of F# and
microsoft.com URLs) that you are a Microsoft fanboi and therefore
religiously opposed to the JVM because, like Linux, it's one of the
things that Microsoft hates most: a competitor that just won't roll over
and die (DR-DOS), or be bought out (Yahoo), or be sued into submission
(TomTom); indeed, Sun had the gall to actually sue Microsoft and win once!

Well, either that or you're just a hypocrite and perhaps even a liar.
How else to explain your posts to the Clojure mailing list, some of them
directly contradicting things you've said here (including asserting, at
least twice, that Clojure numeric code can run at native-code speeds).
 
L

Lew

Oxide said:
I'm sorry,

Are you? Are you really?
but I prefer people to actually discuss something rather than
try to send me off to some web site. Especially some Microsoft web site.

Get off your high horse. Referencing a link is a perfectly legitimate
way to provide basic information such as that for which you ask. You
asked a question, he provided the information. That you for some
inexplicable reason want him to paraphrase a link that clearly and
succinctly answers your question is not his problem. How about you
accept his perfectly valid and comprehensive answer?
There are several different uses of the phrase "value types". Why did it
take you this long to disambiguate?

Others had no trouble whatsoever with the term. The moment you asked,
a couple of people responded with answers. Any faster and they'd've
answered before you asked.
Regardless, it becomes apparent (from all your mentions of F# and
microsoft.com URLs) that you are a Microsoft fanboi [sic] and therefore
religiously opposed to the JVM because, like Linux, it's one of the

Straw-man and ad hominem arguments.
things that Microsoft hates most: a competitor that just won't roll over
and die (DR-DOS), or be bought out (Yahoo), or be sued into submission
(TomTom); indeed, Sun had the gall to actually sue Microsoft and win once!

Your answer is somewhat off from the discussion, but taking point by
point:

Microsoft doesn't seem to show any emotion whatsoever, let alone hate,
with respect to the incidents you cited. DR-DOS killed itself; it
wasn't good enough to sustain itself in the market. Microsoft didn't
show any problem when Yahoo resisted the buyout; it simply started
another search-engine effort. Sun got very palsy-walsy with Microsoft
a couple of years ago, dropped the suit, and offered a joint
announcement with Microsoft that they were happy with each other.
Hardly evidence of hate.

Businesses compete. That's inherent to the capitalist system.
Businesses that compete effectively get to stay in business. That's
nothing for which to be angry with Microsoft. Indeed, you seem to be
showing a stronger interest in bashing Microsoft than addressing the
logic of Dr. Jon's posts.

I realize that it's fashionable to bash Microsoft, but it doesn't
prove anything.
Well, either that or you're just a hypocrite and perhaps even a liar.

Ad hominem name-calling and completely inappropriate. Also, you
provide no evidence of hypocrisy or lies; such accusations put the
burden of proof on you, otherwise they're just pointless flaming.
How else to explain your posts to the Clojure mailing list, some of them
directly contradicting things you've said here (including asserting, at
least twice, that Clojure numeric code can run at native-code speeds).

Perhaps he was discussing primitive numerics, for which the discussion
of value types would not apply. Such points would not apply to matrix
math, of course, and thus there would be no contradiction. Not being
a subscriber to those lists, I don't know. Perhaps you could quote
some of the allegedly contradictory posts verbatim for those of us who
follow in a different newsgroup?

Try to avoid flaming, and focus on presentation of evidence and logic.
 
K

Keith H Duggar

FWIW, "inline" in F# provides the same benefits in an easier to use form. It
really rocks. :)

Here is a toy C++ numerical example that uses templates, function
overloading, and operator overloading to provide a generic golden
section algorithm that will work for any UDT (and built-in types)
for which one provides the needed overloads and specializations.

template < class Vector >
Vector
golden_section (
Vector const & xa
, Vector const & xm
, Vector const & xb
) {
Vector const ma ( xa - xm ) ;
Vector const mb ( xb - xm ) ;

return mag(ma) > mag(mb) ?
xm + (ma * Constants< Scalar<Vector> >::goldenRatio()) :
xm + (mb * Constants< Scalar<Vector> >::goldenRatio()) ;
}

Can you please show how F#'s 'inline' provides the same benefits?
Ie how does F# with 'inline' support the above generic algorithm?

KHD
 
A

Arne Vajhøj

Keith said:
Here is a toy C++ numerical example that uses templates, function
overloading, and operator overloading to provide a generic golden
section algorithm that will work for any UDT (and built-in types)
for which one provides the needed overloads and specializations.

template < class Vector >
Vector
golden_section (
Vector const & xa
, Vector const & xm
, Vector const & xb
) {
Vector const ma ( xa - xm ) ;
Vector const mb ( xb - xm ) ;

return mag(ma) > mag(mb) ?
xm + (ma * Constants< Scalar<Vector> >::goldenRatio()) :
xm + (mb * Constants< Scalar<Vector> >::goldenRatio()) ;
}

Can you please show how F#'s 'inline' provides the same benefits?
Ie how does F# with 'inline' support the above generic algorithm?

Can you explain why you posted to comp.lang.java.programmer ?

Arne
 
K

Keith H Duggar

Can you explain why you posted to comp.lang.java.programmer ?

The thread has been cross-posted from the beginning. You will
need to ask either fft1976 or SG why it is so.

KHD
 
A

Arne Vajhøj

Keith said:
The thread has been cross-posted from the beginning. You will
need to ask either fft1976 or SG why it is so.

I assume that your newsreader have a little feature where you can
trim the groups being posted to.

A comparison between C++ and F# *may* be on topic in
comp.lang.functional, but it is utterly irrelevant in
comp.lang.java.programmer !

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top