Timing Comparison?
"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]>
| Newsgroups | gmane.lisp.lispworks.general |
|---|---|
| Message-ID | <[email protected]> |
I just happened to notice that things on SBCL 2.5.10 on my M1 iMac were running considerably faster than the same code running on LWM 8.1.1.
For arcane reasons*, I have a Forth system written in Lisp, in which I have the Forth interpreter running the output of a Scheme compiler whose intermediate language is Forth. So Scheme compiled to intermediate Forth, Forth machine in Lisp.
[*Arcane reasons: Back in 2011 we were waiting for USPTO Review of an audio processing system. So to allow people to evaluate the algorithm in live settings, we needed to implement an obfuscated version of the audio processing algorithm.
We obfuscated by constructing a Forth Metacompiler in LW, and target compiled a Forth implementation of the audio processing algorithm, using a token threaded Forth interpreter in the embedded C code of the test application. The tokens were randomly assigned, and different for every production of the headless Forth dictionary image.
This produces a totally gibberish appearing blob of memory in the middle of the C application, but which can be executed by an extremely tiny collection of Forth primitives coded in C alongside the dictionary blob.
We were eventually awarded the US Patents on our processing methods.]
I compiled the following Scheme code for a “fast” version of Fibonacci numbers:
(define (fast-fib n)
(if (< n 2)
1
(let f ((ix 2)
(f1 1)
(f2 1))
(if (< ix n)
(f (+ ix 1) f2 (+ f1 f2))
f2))
))
This compiles down to the following intermediate code:
new-vars | fast-fib |
#{
1 chkargs
0 @shallow
2
<
if
1
else
NIL
1 +env
#{
3 chkargs
0 @shallow
0 2 @deep
<=
if
0 @shallow
1
+
2 @shallow
1 @shallow
2 @shallow
+
0 1 @deep
3 jmp invoke
else
2 @shallow
then
}#
0 !shallow
drop
2
1
1
0 @shallow
3 jmp invoke
then
}#
FAST-FIB scheme-!
drop
All of these items in the compiled output are Forth verbs in my ForthRPL system. All of the Forth verbs have native compiled behavior codes which either run Code definitions, or which interpret trees of Forth symbols in higher level Forth colon-definitions.
Never mind the details. All of the Lisp code consists essentially of natively compiled Thunks in the Forth system. And this is true for both LWM and SBCL.
To test the speed of execution, I perform 3 duration measurements, and report the median time. To get to meaningful timings, I run FastFib on 10_000, and measure using my Lisp interface to the system gettimeofday() routine. This interface differs between the LWM version and the SBCL version.
So to test that both Lisp’s are measuring the same kind of duration, we first test the gettimeofday() interface to produce the following result:
;; Measure what we measure with USEC:GET-TIME-USEC
(vm:median
(coerce
(loop repeat 3 collect
(let ((start (usec:get-time-usec)))
(sleep 1)
(- (usec:get-time-usec) start)))
'vector))
;; => 1_002_853 SBCL 2.5.10 on M1 iMac
;; => 1_004_157 LWM 8.1.1 on M1 iMac
This seems close enough between them, to better than 3 significant figures.
So now here are the results of taking the median of 3 duration timings of:
10_000 fast-fib
;; 10_000 med3 => 1_412_582 (LWM 8.1.1 on M1 iMac)
;; 10_000 med3 => 52_201 (SBCL 2.5.10 on M1 iMac)
SBCL appears to be running 27x faster on this arcane exercise. Both LWM and SBCL are running the exact same Lisp code, AFAIK, except for the USEC:GET-TIME-USEC function.
How can the difference between these two Lisp implementations be that great??