Saturday, April 18, 2009

Clojure optimization of constants

(I actually read about this trick on the clojure user group, but I can't remember where.)

This is a neat trick that eliminates boxing/unboxing overhead when you are using Integer and all you need is int.
(This of course works for the other java primitives)

Let's do something stupid like summing up two Integers ten million times.


(def times 10000000)

(def w 640)
(def h 480)

(time (dotimes [i times]
(+ w h)))


This little test took around 950ms on my machine.
The w,h values are unboxed from and boxed into Integer classes in order to be used.

Now consider this:



(defmacro w [] `(int 640))
(defmacro h [] `(int 480))

(time (dotimes [i times]
(+ (w) (h))))


This is a very smart macro trick that I read on the Clojure user group. What it does is it substitutes (w) with a java primitive at compile time.
On my machine, the benchmark took around 430ms.
The problem is that it is ugly, but that can be fixed easily.



(defmacro const-int [name val]
`(defmacro ~name [] (list 'int ~val)))

(const-int w 640)
(const-int h 480)

(time (dotimes [i times]
(+ (w) (h))))



Still around 430ms. There is no performace cost because of the way macros are evaluated.
const-int is a macro that creates a macro so our definition looks prettier. The only caveat is you still have to use (w) instead of w.

Sunday, April 5, 2009

pyCave: Porting to mac.

So for the past couple of days I have been porting pyCave to my mac. Yesterday was the day I thought the work was pretty much finished (It's not).

I did it by starting with a GL demo written from scratch, and I went up from there adding features until I had a working copy of pyCave. Obviously, there was a lot of copy-pasting, but the overall writing involved a lot of redesign that ended up touching the whole program. The diff file was huge.

This wasn't the original plan. The 'project' was called 'glui'. It was only a module to build GL user interfaces. It eventually morphed into a new version of pycave =). There was only a single commit. Bad idea. But the code is the product of an intense non-stop coding session.

One of the first changes was adding an opengl extension checking mechanism. I found a nifty thing that pyOpenGL had. Every extension module has a member called EXTENSION_NAME. I used that to check for extensions in a very concise manner.
Little did I know that the nifty feature is actually only featured in the latest releases of pyOpenGL 3 (ubuntu beta releases don 't have it).

So i'm thinking that I'll include a subset of the latest pyOpenGL (3.0.0) so that I won't get emails from ubuntu users with Nvidia cards saying that the game doesn't run.

The game runs almost perfectly on my Macbook with Python2.6. I was going to write about the hell I went through compiling pygame for Python2.6 on a mac (it's practically impossible), but it's a long story. I had to do it because I had screwed up the default Leopard python instalation thanks to a very stupid bash command.
Today I fixed my pretty apple-provided Python and tried to run pyCave (practically all my users will do the same).

It actually crashes.

The 2.5 and 2.6 versions have the same PyOpengl (release candidate 1). It is a very strange bug and I think my frankenstein python2.5 instalation is to blame. I am not sure.
A friend of mine just got a brand new Macbook (lower-end) and I would love for him to let me borrow it for a half hour to do some testing.

I am very optimistic that my 6 year old laptop will be able to run the game. It already does, but there is an odd bug in which all the edges are highlighted. It looks awesome with the proceduraly generated tunnel =) It also has the extension-checking bug, which should be fixed by adding the OpenGL module inside the pyCave distribution.