[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