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

Efficiency of local fns and closures



   Date: Sat, 21 Oct 89 22:45 EDT
   From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>

   For things this fast you can usually get more accurate results by using
   METERING:DEFINE-METERING-FUNCTION.  

It would have taken longer to load the metering system than I spent on the
whole thing.

				       It runs the test case as many times
   as necessary to get a statistically valid result, and filters out
   various sources of inaccuracy.  Try clicking middle on the average it
   presents.  We probably should make TIME filter out the EVAL overhead,
   but I don't think Common Lisp will let us make TIME run the test case
   multiple times and do statistical processing, so unfortunately TIME
   can never be as accurate as METERING:DEFINE-METERING-FUNCTION.

I always use time by writing and compiling little test functions that
contain (without-interrupts (time (loop repeat N do <operation>))).  I
filter out loop overhead by writing a control case that calls an empty
function (if I want to factor out function call overhead) or has an empty
loop body (if I want function call overhead included).  Perhaps this is
what METERING:DEFINE-METERING-FUNCTION does; old habits die hard.

       A quick
       test I just tried seemed to indicate that it takes about 4 microseconds
       longer to access a lexical variable than a parameter variable; 5
       microseconds rather than 1 microsecond per access.

   Those numbers seem quite a lot higher than I expected.  Actual
   measurement (admittedly in a prototype of Genera 8.0, but for this
   particular operation 7.2 should be the same speed) on a 3640 shows
   accessing a parent's lexical variable is 1.3 microseconds slower than
   accessing a local lexical variable.  The time to access a local
   lexical variable on a 3640 is about 200 ns, which is small enough
   to make it difficult to measure accurately.  All the numbers are
   faster on Ivory-based machines.

I was doing loops of 100,000 and 1,000,000 repetitions, ran them a couple
of times and saw consistent results.  My functions were pretty simple, but
it's possible that I wasn't factoring everything out.  This is similar to
what I used to determine speed of accessing various types of variable in a
local function:

(defun test (x n)
  (flet ((test1 (x) (declare (ignore x))) ; access no variable
	 (test2 (x) x) ; access local variable
	 (test3 () x)) ; access lexical variable
    (without-interrupts (time (loop repeat n do (test1 1))))
    (without-interrupts (time (loop repeat n do (test2 1))))
    (without-interrupts (time (loop repeat n do (test3))))))

I guess comparing TEST1 to either of the others includes the difference
between RETURN-NIL and RETURN-STACK.  But I think it should give an
accurate measurement when comparing TEST2 and TEST3.

       For compiling to core, I can't think of a hard technical problem, and I
       think the ANSI CL draft requires this to work.  

   Do you mean, does (LET ((X 1)) (COMPILE NIL #'(LAMBDA () X))) have a
   defined meaning in ANSI Common Lisp?  The answer is that it does not.
   This was considered and rejected.  See COMPILE-ARGUMENT-PROBLEMS:CLARIFY.

I remembered that it was considered, but I forgot how that particular one
came out, and didn't have access to my X3J13 documents at the time.

						barmar