[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Allegro CL Floating Point



Your message:

    We need to do fast floating point in Lisp. We have benchmarked
    a C program and a Lisp program. Both programs call an exponential
    function and a trig function 250,000 times.

    The C program runs in under 10 seconds. The Lisp program takes
    at least 50 seconds. We can't understand why there should be
    such a discrepancy. Can anyone replicate this and explain the
    discrepancy? We are using the following version of Allegro 

                3.1.beta.22 [Sun4] (6/8/89)
    ...
--------

  First of all, as someone on this list already pointed out, a smart compiler
can totally eliminate the loop in the example you gave, resulting in a
artificially low result.  Here is a slightly better example:

C:
#include <math.h>
#define cnt 500

main()
{	
    int i,j;
    double b = 0.1;
    
    for (i=0; i<cnt; i++)
      for (j=0; j<cnt; j++) {
	  b = exp(b);
	  b = cos(b);
      }
}

CL:
(defun speed ()
   (declare (optimize (speed 3) (safety 0)))
   (let ((b 0.0d0))
     (declare (double-float b))
     (dotimes (i 500)
       (dotimes (j 500)
         (setf b (exp b))
         (setf b (cos b))))))


  After some experimentation, it turns out the major reason that lisp does
not perform in the same magnitude as C here is because Allegro CL uses a
machine independent version of the math library.  We do this because we
want to guarantee getting the same result from the same value on different
machines.  Also we know that the math library we use works correctly for
the boundary cases, whereas Sun's, for example, barfs on some boundary
conditions.

  Also note that I have re-written your example so that both C and Lisp are
using double precision floating point numbers.  Your previous example had
C using double and Lisp using single.  Cos() and Exp() both take double
precision arguments and return double precision results, so to use these
with singles requires two conversions.  Unfortunately our implementation
of this is not optimal in the current product.  However, after some
experimentation we have found a way to improve this double conversion
greatly.  I have added this RFE to our RFE list and it should appear in
a future release of Allegro CL.  In the mean time, if you really need to
use single floats rather than double floats, I suggest converting them at
the beginning and end of the speed-dependent code, and using doubles inside
that code.

  Now, on to solving your problem.  Since the slowness is in our math
library, if you can use Sun's library you'll get a large speedup.  Of course,
you have to guarantee not to pass bad arguments, since these routines are not
as safe as our routines.  Allegro CL 3.1 final (which you should receive in a
few weeks) has a special direct calling foreign function system for the sun4.
This allows a much faster than normal call to foreign code.  (Note that the
below example will work in 3.1.beta.28, but you won't get the numbers I
get since the fast foreign function code was done between 3.1.beta.28 and 3.1.)

  Here is the above example rewritten to use this fast foreign function hook
to call into Sun's math library.  (Note that this code is rather ugly)

;; These get rid of duplicate symbols already in the Lisp.
(remove-entry-point "_exp")
(remove-entry-point "_cos")
(remove-entry-point "_sin")
(remove-entry-point "_tan")
(remove-entry-point "_sincos")
;; This loads in Sun's implementations of exp() and cos().
(load "" :unreferenced-lib-names '("_exp" "_cos")
      :system-libraries '("m"))

(defforeign 'c-exp :entry-point "_exp" :arguments '(double-float)
	    :arg-checking nil
	    :call-direct t
	    :callback nil
	    :allow-other-keys t
	    :return-type :double-float)

(defforeign 'c-cos :entry-point "_cos" :arguments '(double-float)
	    :arg-checking nil
	    :call-direct t
	    :callback nil
	    :allow-other-keys t
	    :return-type :double-float)

(defun speed ()
  (declare (optimize (speed 3) (safety 0)))
  (let ((b 0.0d0))
    (declare (double-float b))
    (dotimes (i 500)
      (dotimes (j 500)
	(setf b (c-exp b))
	(setf b (c-cos b))))))


  Here are the numbers I get for the above examples on a 4/260 with
Allegro CL 3.1.4.  Units are user time, Lisp times include gc time.

PRECISION	C	STD LISP	LISP WITH FAST SUN MATH
double		11	48		20


  In addition, we plan to further improve the fast foreign function calling
mechanism, which should speed up this last example considerably, probably to
the point where it is equivalent to C.  We hope to make this improvement 
available as a patch to 3.1, otherwise it will be available in a future
release.

  If you have any questions or feel this approach will not solve your problem
please contact us for assistance.

	-- John Irwin
	   Franz Inc.