loop [#^Integer c 0] vs. loop [c (int 0)] and optimization question...

7 views
Skip to first unread message

Dimiter "malkia" Stanev

unread,
Feb 12, 2009, 5:35:30 PM2/12/09
to Clojure
Hi guys,

I'm optimizing a little benchmark called pnpoly, and I was wondering
what is the proper way of hinting the compiler for types. In certain
cases Clojure accepts for example loop [#^Integer c 0] and in others
loop [c (int 0)] - I'm really trying to hint the compiler as best as I
can.

I'm synced to the latest SVN version (1162), and in the same source
code, it seems like loop[#^Integer c 0] works for some cases, and not
for others.

Here is the code in question:

http://paste.lisp.org/display/75370

Also please note, what I'm doing wrong in it, what could be achieved
more. My next step is to parallelize it, and compare again.

So on my machine Clojure gives this result: (-600000 is okay, I was
testing which one is better bit-not or subtracting 1 from the number).
; SLIME 2009-02-07
user> (time (pnpoly/pnpolytest))
"Elapsed time: 16075.309949 msecs"
-6000000

C version is about 0.8s, Lispworks 1.3s, other Common Lisps (SBCL,
CMUCL) about 2.0s ABCL: 6sec (using Java 1.6_10 -server, much like
what I'm using for clojure).

16seconds it's not really that bad, considering I won't be using
Clojure for heavy math code, but still wanted to see what I can do
more with it.

For example the same example in Python, Ruby or Perl runs at least for
200s (same with CLISP, haven't tried ECL or GCL).

Thanks,
Dimiter "malkia" Stanev.

Laurent PETIT

unread,
Feb 13, 2009, 8:34:06 AM2/13/09
to clo...@googlegroups.com
Hello,

I can't manage to get the code from the URL (server timeout)

2009/2/12 Dimiter malkia Stanev <mal...@gmail.com>

Vincent Foley

unread,
Feb 13, 2009, 8:35:35 AM2/13/09
to Clojure
Dimiter,

The latest revision of Clojure is r1278; are you using the Google code
trunk?

Vincent

On Feb 12, 5:35 pm, "Dimiter \"malkia\" Stanev" <mal...@gmail.com>
wrote:

Rich Hickey

unread,
Feb 13, 2009, 8:41:11 AM2/13/09
to clo...@googlegroups.com

Try this:

http://paste.lisp.org/display/75370#3

A few things to note:

- All arguments are passed to Clojure fns as objects, so there's no
point to putting non-array primitive type hints on fn args. Instead,
use the let technique shown to place args in primitive locals if they
need to participate in primitive arithmetic in the body.

- (let [foo (int bar)] ...) is the correct way to get a primitive
local. Do not use #^Integer etc.

- Don't rush to unchecked math unless you want truncating operations.
HotSpot does a good job at optimizing the overflow check, which will
yield an exception instead of silent truncation. On this example, that
has about a 5% difference in speed - well worth it. Also, people
reading your code don't know if you are using unchecked for truncation
or perf - best to reserve it for the former and comment if the latter.

- There's usually no point in trying to optimize an outer loop, in
fact it can hurt you as you'll be representing things as primitives
which just have to be re-boxed in order to become args to the inner
call. The only exception is reflection warnings - you must get rid of
them in any code that gets called frequently.

Rich

Rich Hickey

unread,
Feb 13, 2009, 8:58:05 AM2/13/09
to Clojure
Some more general points:

Almost every time someone presents something they are trying to
optimize with hints, the faster version has far fewer hints than the
original. If a hint doesn't improve things in the end - take it out.

Many people seem to presume only the unchecked- ops do primitive
arithmetic - not so. When the args are primitive locals, regular + and
* etc do primitive math with an overflow check - fast *and* safe.

So, the simplest route to fast math is to leave the operators alone
and just make sure the source literals and locals are primitive.
Arithmetic on primitives yields primitives. If you've got a loop
(which you probably do if you need to optimize) make sure the loop
locals are primitives first - then if you accidentally are producing a
boxed intermediate result you'll get an error on recur. Don't solve
that error by coercing your intermediate result, instead, figure out
what argument or local is not primitive.

Rich

Dimiter "malkia" Stanev

unread,
Feb 13, 2009, 10:15:13 AM2/13/09
to Clojure
On Feb 13, 5:35 am, Vincent Foley <vfo...@gmail.com> wrote:
> Dimiter,
>
> The latest revision of Clojure is r1278; are you using the Google code
> trunk?
>
> Vincent

Thanks, Vincent! I kept wondering why I don't see any more versions, I
was till on the sourceforge one.
Reply all
Reply to author
Forward
0 new messages