From: James A Landay
Subject: Math functions using too much space?
Date: 
Message-ID: <1992Feb06.172754.83811@cs.cmu.edu>
I am having problems with math functions in Allegro CL on Sun Sparcs.
It seems they are allocating way too much space.  For instance, the
following function just takes the sqrt of 0 for 100 times:

(defun foo () (let ((x 10)) (dotimes (n 100) (sqrt x))))

When you compile it (compile 'foo) then run it as (time (foo)) you get:

	cpu time (non-gc) 0 msec user, 16 msec system
	cpu time (gc)     0 msec user, 0 msec system
	cpu time (total)  0 msec user, 16 msec system
	real time  90 msec
	space allocation:
	 1 cons cell, 0 symbols, 6400 other bytes,
							 ^^^^
							 ^^^^

That amounts to 64 BYTES of "other bytes" per computation of SQRT!!!!

And I have had similar problems with acos, atan, etc!

What gives?!?!?!?  (Is this number even meaningful?!?  What are "other
bytes"?)

Now, I have done some homework, and declaring types does not seem to help
matters.  Also, it is important that the "let" be left in there -- if you
use a constant instead of "x", as in:
	(defun foo () (dotimes (n 100) (sqrt 10)))
The compiled code actually contains the constant for the square root of
10 (that is, 3.1622777).

[ Digression:  This actually is even a BUG if you think about
it, since if you rebind the symbol-function of 'sqrt, you lose!!!  A cursory
investigation shows this is true only for built-in functions.  So...  Does
the CommmonLisp definition prohibit the rebinding of these, or is this
a bug? ]

-- 

James A. Landay
······@cs.cmu.edu
From: Barry Margolin
Subject: Re: Math functions using too much space?
Date: 
Message-ID: <kp36vjINN430@early-bird.think.com>
In article <······················@cs.cmu.edu> ·······@cs.cmu.edu (James A Landay) writes:
>(defun foo () (let ((x 10)) (dotimes (n 100) (sqrt x))))

>When you compile it (compile 'foo) then run it as (time (foo)) you get:

>	cpu time (non-gc) 0 msec user, 16 msec system
>	cpu time (gc)     0 msec user, 0 msec system
>	cpu time (total)  0 msec user, 16 msec system
>	real time  90 msec
>	space allocation:
>	 1 cons cell, 0 symbols, 6400 other bytes,

>That amounts to 64 BYTES of "other bytes" per computation of SQRT!!!!
>What gives?!?!?!?  (Is this number even meaningful?!?  What are "other
>bytes"?)

I suspect they implemented their math functions in Lisp, and weren't very
careful about use of temporary variables and intermediate values.  In some
Lisp implementation, floating point intermediates require consing.

I tried your example in Lucid CL 4.0 and it consed 32 bytes per call to
SQRT.

Note that both these Lisp implementations have a generational GC, and all
of this consing should be ephemeral and be reclaimed pretty quickly.

>Now, I have done some homework, and declaring types does not seem to help
>matters.  Also, it is important that the "let" be left in there -- if you
>use a constant instead of "x", as in:
>	(defun foo () (dotimes (n 100) (sqrt 10)))
>The compiled code actually contains the constant for the square root of
>10 (that is, 3.1622777).

I had to do even more work to get it to call SQRT 100 times in Lucid.  It
knows that SQRT has no side effects, and the value was being ignored, so it
optimized out the calls to SQRT.  So I did:

(defun my-ignore (x) (declare (ignore x)) nil)

(defun foo () (let ((x 10)) (dotimes (n 100) (my-ignore (sqrt x)))))

However, the optimizer noticed that X was never being modified, so it
treated it as a constant and folded the (sqrt x) into 3.1622777....

So I turned X into an argument to FOO.  I'm surprised it didn't realize
that it could move the (sqrt x) computation out of the loop.

>[ Digression:  This actually is even a BUG if you think about
>it, since if you rebind the symbol-function of 'sqrt, you lose!!!  A cursory
>investigation shows this is true only for built-in functions.  So...  Does
>the CommmonLisp definition prohibit the rebinding of these, or is this
>a bug? ]

I thought CLtL said somewhere that an implementation is permitted to treat
any of the standard functions as if they were proclaimed INLINE.  Certainly
you don't expect every call to CAR, CDR, and + to go through the function
cell.  If you wanted to redefine a standard function you would have to
proclaim it NOTINLINE prior to compiling any use that you expect to go
through the function cell.

I can't find the original statement of this inlinability (information like
this is sometimes buried in pretty obscure places in CLtL), but X3J13 has
further clarified that it is not permitted to redefine any of the standard
functions (see p.260 of CLtL2).  In addition to permitting the
implementation to open-code calls, this permits the implementation to
implement some of its functions in Lisp, calling these functions and
depending on their behavior (including any implementation-dependent
aspects).  For instance, the implementation of SQRT can contain (EXPT X
.5), and if you were to change EXPT it would have an effect on SQRT.
-- 
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar