Compiling Chicken code (part II)
One of the cool features of Chicken is that you may choose to compile parts of your Scheme program to C, in order to get better performance.
Let’s write a (naive) implementation of the factorial function. Store it in fac.scm:
;; fac.scm (define (fac n) (if (<= n 1) 1 (* n (fac (- n 1)))))
Now, write a second file main.scm that uses our fac function. Normally this would be as simple as
(load "fac") (print (fac 30))
But I’d like to include some simple benchmark code, to see how well fac performs, interpreted vs compiled. I’m using the following code to call (fac 30) 100,000 times, and time the results.
;; main.scm (load "fac") (define *max-iterations* 100000) (define t1 (current-milliseconds)) (let loop ((i 0)) (unless (= i *max-iterations*) (fac 30) (loop (+ i 1)))) (define t2 (current-milliseconds)) (define seconds (/ (- t2 t1) 1000)) (printf "~a iterations in ~a seconds.~n" *max-iterations* seconds)
Interpreted, it takes a little more than two seconds on my machine:
$ csi -s main.scm 100000 iterations in 2.191 seconds.
We can do better than that. Let’s compile fac.scm and see if it makes a difference.
$ csc -s fac.scm # produces fac.so $ csi -s main.scm 100000 iterations in 0.326 seconds.
That’s right — we still run main.scm interpreted, but it now uses the *compiled* fac.scm, which makes execution much faster. ^_^
We could do a lot more with this, e.g. compile main.scm to an executable, etc, but I just wanted to demonstrate how easy it is to precompile libraries, with no change in code. (At least, not for simple cases like this… but that’s a different story.)