Subject: Number crunching in CLISP.

From: "Harvey J. Stein" <[email-masked]>
Date: Tue, 9 Aug 1994 22:32:21 +0300

Bruno Haible writes:

I have to write some serious number crunching code, and I'd like to
write it in CLISP.  If my memory serves me correctly, Bruno once told
me that CLISP does all floating point operations by itself (i.e. -
doesn't use the FPU).  Is this correct?  If so, I won't be able to use
it.  If it does do floating point in software, how hard is it to
change this?  Are floating point numbers stored in system format (as a
C float)?  Is the numerical code well isolated?  If it doesn't use the
FPU & changing it would be difficult, then what about some other
common lisps - does anyone know about GCL & XLISP?  From the following
quick & simpleminded test, it seems that neither CLISP nor XLISP will
be suitable:

 ------------------ File test.lsp --------------------
(defvar i 1)
(time (dotimes (j 100000) (setq i (* i 1.00001))))
 ------------------End file test.lsp -----------------------

CLISP run (best of 3):

> (load "test.lsp")
;; Loading file test.lsp ...
Real time: 25.37575 sec.
Run time: 25.36 sec.
Space: 800456 Bytes
GC: 1, GC time: 0.28 sec.
;; Loading of file test.lsp is finished.
T

XLISPSTAT run (best of 3):

> (load "test.lsp")
; loading "test.lsp"
The evaluation took 19.40 seconds
T

CLISP run of compiled code (best of 3):
> (compile-file "test.lsp")

Compiling file /new/home/hjstein/test.lsp ...

Compilation of file /new/home/hjstein/test.lsp is finished.
0 errors, 0 warnings
T

   . . . 

> (load "test")
;; Loading file /new/home/hjstein/test.fas ...
Real time: 4.628368 sec.
Run time: 4.62 sec.
Space: 800000 Bytes
GC: 1, GC time: 0.28 sec.
;; Loading of file /new/home/hjstein/test.fas is finished.
T

I didn't run XLISPSTAT compiled because the compiler just came out & I
haven't picked it up yet.

Here's what I'd consider roughly equivalent C code, along with it's
runtime:

main()
{
  long j;
  double i;

  i = 1;
  for (j = 0; j < 1000000; j++) i = i * 1.00001;
}

hjstein:~$ time /home/hjstein/test
real        1.0
user        1.6
sys         0.0

All this is on a 486dx20 running Linux.

Since the C code is doing the loop 10x as many times as the lisp code
(I had to crank it up to measure it with the time command), it seems
that this C code is over 20 times faster than the compiled CLISP code.
If the CLISP was only twice as slow, or even only 5 times slower, I
could probably live with it for prototyping purposes (I have things
which run for hours on end).  So, how can I speed it up?

Thanks,

Harvey J. Stein
Berger Financial Research
[email-masked]

---

From: [email-masked] (Marcus Daniels)
Date: Tue, 9 Aug 94 13:26:31 PDT

>>>>> "Harvey" == Harvey J Stein <[email-masked]> writes:

Harvey> Bruno once told me that CLISP does
Harvey> all floating point operations by itself (i.e. - doesn't use
Harvey> the FPU).  Is this correct?  If so, I won't be able to use it.
Harvey> If it does do floating point in software, how hard is it to
Harvey> change this?  Are floating point numbers stored in system
Harvey> format (as a C float)?

Platforms like hppa, m88000, rs6000, and sparc can use floating point
hardware.  Look aridecl.d, arilev0.d, dfloat.d, intlog.d, and sfloat.d
for the dependencies.  Declare support in lispbibl.d.  FAST_DOUBLE and
FAST_FLOAT is what you are looking for.

Harvey> If it doesn't use the FPU & changing it would be difficult,
Harvey> then what about some other common lisps - does anyone know
Harvey> about GCL & XLISP? 

Harvey> From the following quick & simpleminded
Harvey> test, it seems that neither CLISP nor XLISP will be suitable:

Harvey>  ------------------ File test.lsp -------------------- 
Harvey> (defvar i 1)
Harvey> (time (dotimes (j 100000) (setq i (* i 1.00001))))
Harvey>  ------------------End file test.lsp -----------------------

The floating point isn't the bottleneck, CLISP's floating point
code is exceptional. The difference between CLISP and C is function
call (byte-code-interpreter) overhead.  For loops like this, there it
is always going to be noticeable difference.  Using integer arithmetic
such as (setq i (* i 1)) or (incf i) won't make it more than about
twice as fast.  With, GCL you will get results similar
to C [for(j=0;j<100000;j++) i*=1.0001;].  On the other hand, you will
be waiting and waiting and waiting for compiles.  XLISPSTAT (and its
new experimental compiler) will likely be tuned for the type of
vector-reducing operations that are common in the XLISPSTAT code.

Harvey> Since the C code is doing the loop 10x as many times as the
Harvey> lisp code (I had to crank it up to measure it with the time
Harvey> command), it seems that this C code is over 20 times faster
Harvey> than the compiled CLISP code.  If the CLISP was only twice as
Harvey> slow, or even only 5 times slower, I could probably live with
Harvey> it for prototyping purposes (I have things which run for hours
Harvey> on end).  So, how can I speed it up?

For this excruciatingly unrealistic code, I think it is the short answer is
"You can't".  Write portions of it in C.  Use the approach described
in foreign.txt (or ask me to point you to the alpha CLISP with FFI).

---

From: "Harvey J. Stein" <[email-masked]>
Date: Wed, 10 Aug 1994 01:21:01 +0300

Thank you, Bruno Haible & Marcus Daniels for pointing out that it's
easy to get CLISP to use the FPU, and how to do it.  Marcus raised

 > in foreign.txt (or ask me to point you to the alpha CLISP with FFI).

The kind of code I'm considering basically is solving recursive
functions.  I might have something like:

(defun value (level node)
  (cond ((= level *MAX_LEVEL*) 100)
	(t (let ((p1 (complicate-expression-involving-exponentials))
		 (p2 (complicate-expression-involving-exponentials))
		 (p3 (- 1 p1 p2)))
	     (* (exp (* (aref *RATE* level) (aref *DT* level)))
		(+ (* p1 (value (+1 level) (+1 node)))
		   (* p2 (value (+1 level) node))
		   (* p3 (value (+1 level) (-1 node)))))))))

where I need to compute (value 0 0) for various values of *RATE* and
*DT*.  This is very simplified & off the top of my head, but is
basically the kind of thing we're looking at.  The real thing would
have more conditionals embedded in & afew more array references.

We have some functions individually coded in FORTRAN which takes maybe
a couple of seconds to compute (on a 486dx-66).  Adding new functions
in FORTRAN is a mess, so I'd like to code a system for investigating
functions of this form in LISP.  Investigating these functions
involves plotting their value as a function of various input
parameters.  I usually use around 300 points, thus taking about 5
minutes per graph.  Then, varying a bunch of other input parameters, I
end up with maybe 60 graphs to look at, thus taking about 5 hours to
generate, which I spread around 5 machines so that I can look at them
in an hour.

My dream is to code this in LISP & get it to run comparably.  Then,
maybe I wouldn't even have to recode it.  If I can code this in LISP &
get even reasonable speed, then that will be good enough for general
testing & some comparative analysis.

Thanks,

Harvey J. Stein

---

From: [email-masked] (Marcus Daniels)
Date: Wed, 10 Aug 94 04:17:56 PDT

>>>>> "Harvey" == Harvey J Stein <[email-masked]> writes:
Harvey> The kind of code I'm considering basically is solving
Harvey> recursive functions.  I might have something like:

I'd say that would be at least 5* faster with CLISP than a waste-time loop.

If you are writing code from scratch you might do so with CLiCC in
mind (CL -> C compiler -- runs on CLISP).  If speed is the top
priority, and you have the right hardware try CMUCL.