Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
SBCL Lisp, Ruby, Io, PHP, Python, Lua, Java, Perl, Applescript, TCL, ELisp, Javascript, OCaml, Ghostscript, and C Fractal Benchmark (timestretch.com)
10 points by gibsonf1 on June 3, 2007 | hide | past | favorite | 9 comments


I've tested this under LispWorks, and it's pretty fast, although you I had to add this:

(defun mandelbrot (x y) (declare (optimize (speed 3) (safety 0) (space 0) (compilation-speed 0) (float 0)))

Also the benchmark is flawed somehow, as some of the examples are using double, other float.

Also the lisp (SBCL) example the printing of the stream was also in the equation. You should compute the result in array, then print it.


I found more "bugs" in the LISP version:

+BAILOUT+ constant needs to be 16.0, not 16, as it's used in floating-point comparison:

(defconstant +BAILOUT+ 16.0)

The "i" variable was declared fixnum in the incorrect place, it should be right after the "do" block:

(do ((i 0 (incf i))) (nil) (declare (type fixnum i))

Also I've commented the printing, printing is slow, especially doing format for each character:

(declaim (optimize (speed 3))) (defconstant +BAILOUT+ 16.0)

(defconstant +MAX-ITERATIONS+ 1000)

(defun mandelbrot (x y)

(declare (optimize (speed 3) (safety 0) (space 0) (compilation-speed 0)

#+lispworks (float 0)))

(declare (type single-float x y))

(let ((cr (- y 0.5))

(ci x)

(zi 0.0)

(zr 0.0))

(declare (type single-float cr ci zi zr))

(do ((i 0 (incf i)))

(nil)

(declare (type fixnum i))

(let ((temp (the single-float ( zr zi)))

(zr2 (the single-float ( zr zr)))

(zi2 (the single-float ( zi zi))))

(declare (type single-float temp zr2 zi2))

(setq zr (the single-float (+ (- zr2 zi2) cr)))

(setq zi (the single-float (+ temp temp ci)))

(when ( (the single-float (+ zi2 zr2)) +BAILOUT+)

(return-from mandelbrot i))

(when ( i +MAX-ITERATIONS+)

(return-from mandelbrot 0))))))


Here is the disassembled version (LispWorks 5.02)

CL-USER 14 (disassemble 'mandelbrot)

200B2732:

0: 55 push ebp

1: 89E5 move ebp, esp

3: 83EC20 sub esp, 20

6: C7042486200000 move [esp], 2086

13: 8B7D08 move edi, [ebp+8]

16: D94701 flds [edi+1]

19: D95DE8 fstps [ebp-18]

22: D94001 flds [eax+1]

25: D9053C7B0820 flds [20087B3C] ; 0.5

31: DEE9 fsubp st(1), st

33: D95DE4 fstps [ebp-1C]

36: D905447B0820 flds [20087B44] ; 0.0

42: D95DFC fstps [ebp-4]

45: D905447B0820 flds [20087B44] ; 0.0

51: D95DF8 fstps [ebp-8]

54: 33FF xor edi, edi

L1: 56: D945F8 flds [ebp-8]

59: D95DF4 fstps [ebp-C]

62: D945FC flds [ebp-4]

65: D84DF4 fmuls [ebp-C]

68: D95DF4 fstps [ebp-C]

71: D945F8 flds [ebp-8]

74: D95DF0 fstps [ebp-10]

77: D945F8 flds [ebp-8]

80: D84DF0 fmuls [ebp-10]

83: D95DF0 fstps [ebp-10]

86: D945FC flds [ebp-4]

89: D95DEC fstps [ebp-14]

92: D945FC flds [ebp-4]

95: D84DEC fmuls [ebp-14]

98: D955EC fsts [ebp-14]

101: D86DF0 fsubrs [ebp-10]

104: D845E4 fadds [ebp-1C]

107: D95DF8 fstps [ebp-8]

110: D945F4 flds [ebp-C]

113: D845F4 fadds [ebp-C]

116: D845E8 fadds [ebp-18]

119: D95DFC fstps [ebp-4]

122: D945EC flds [ebp-14]

125: D845F0 fadds [ebp-10]

128: D905347A0820 flds [20087A34] ; 16.0

134: DED9 fcompp

136: DFE0 fnstsw ax

138: 9E sahf

139: 7A09 jp L3

141: 7307 jnb L3

143: 89F8 move eax, edi

145: FD std

L2: 146: C9 leave

147: C20400 ret 4

L3: 150: 81FFA00F0000 cmp edi, FA0

156: 7E05 jle L4

158: 33C0 xor eax, eax

160: FD std

161: EBEF jmp L2

L4: 163: 83C704 add edi, 4

166: EB90 jmp L1

168: 90 nop

169: 90 nop

NIL


Impressive, SBCL (Common Lisp) is at the top of the heap :), tying with C for top speed. We've been experiencing incredible speed with SBCL on our streamfocus.com app.


I haven't checked the other examples, but the Python one doesn't use scipy, which makes a huge difference (50X for one example, see below). So I'm skeptical of the whole exercise.

http://www.scipy.org/PerformancePython


Yes, but the Java code is shorter than the Lisp code. I'll take the slight performance hit to avoid the boilerplate.

I wonder if his test doesn't have one obvious flaw though. I ran it three times and got:

.46, .28, .28

...I took out the System.out.println statements and got:

.032, .047, .032

So I think he might have been testing the wrong thing.


This is just a single example. The CL code might be a few lines longer in this example, but in the vast majority of code, Java will be the one with boilerplate and a lot more code. Lisp more than any other language removes boilerplate.


I never realised how much Ghostscript (PS?) looks like Lisp.


still not faster than fortran :/




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: