Subject: Re: need help with lists
From: rpw3@rpw3.org (Rob Warnock)
Date: Wed, 24 Oct 2007 04:01:20 -0500
Newsgroups: comp.lang.lisp
Message-ID: <RumdnSnB9-l9lILanZ2dnUVZ_vumnZ2d@speakeasy.net>
Thomas A. Russ <tar@sevak.isi.edu> wrote:
+---------------
| Since this seems to come up over and over again, I wonder if it would be
| worthwhile to add some argument checking to the TIME macro that will
| print some sort of warning/complaint/note if it gets invoked with
| something other than a compiled function call?
+---------------

I'd rather not, since that prohibits typing simple examples at the
REPL. Rather, I think CMUCL [one of the CLs which does run stuff
in the REPL in an interpreter by default] does it the right way.
In CMUCL, TIME does automatically compile its arg:

    cmu> (time (dotimes (i 2000000000)))
    ; Compiling LAMBDA NIL: 
    ; Compiling Top-Level Form: 

    ; Evaluation took:
    ;   1.83f0 seconds of real time
    ;   1.811377f0 seconds of user run time
    ;   0.002219f0 seconds of system run time
    ;   4,037,066,749 CPU cycles
    ;   0 page faults and
    ;   0 bytes consed.
    ; 
    NIL
    cmu> 

Aside: Yes, that's only 2 CPU cycles/iteration.

But TIME *doesn't* try to recursively compile *everything*,
so if you call an "outside" function, the top-level call is
compiled, yes, but the called function runs in whatever mode
it already was -- interpreted, byte-compiled, or native machine-
code compiled:

    cmu> (defun foo () () (dotimes (i 1000000)))

    FOO                              ; An interpreted function.
    cmu> (time (foo))
    ; Compiling LAMBDA NIL:          ; Only the call was compiled.
    ; Compiling Top-Level Form: 
    ; [GC threshold exceeded with 13,261,344 bytes in use.  Commencing GC.]
    ; [GC completed with 1,319,360 bytes retained and 11,941,984 bytes freed.]
    ; [GC will next occur when at least 13,319,360 bytes are in use.]
    ; [GC threshold exceeded with 13,328,184 bytes in use.  Commencing GC.]
    ; [GC completed with 1,327,552 bytes retained and 12,000,632 bytes freed.]
    ; [GC will next occur when at least 13,327,552 bytes are in use.]
    ; [GC threshold exceeded with 13,337,016 bytes in use.  Commencing GC.]
    ; [GC completed with 1,345,808 bytes retained and 11,991,208 bytes freed.]
    ; [GC will next occur when at least 13,345,808 bytes are in use.]
    ; [GC threshold exceeded with 13,351,176 bytes in use.  Commencing GC.]
    ; [GC completed with 1,349,904 bytes retained and 12,001,272 bytes freed.]
    ; [GC will next occur when at least 13,349,904 bytes are in use.]

    ; Evaluation took:
    ;   3.09f0 seconds of real time
    ;   3.054258f0 seconds of user run time
    ;   0.0f0 seconds of system run time
    ;   6,832,567,756 CPU cycles
    ;   [Run times include 0.07f0 seconds GC run time]
    ;   0 page faults and
    ;   48,010,608 bytes consed.
    ; 
    NIL
    cmu> 

So that's ~6800 CPU cycles/iteration when run interpreted.
But CMUCL also has a byte-code compiler [though it's not
used by default, since it optimizes size over speed]:

    cmu> (let ((c::*byte-compile* t))
	   (compile 'foo))
    ; Byte Compiling LAMBDA NIL: 
    ; Byte Compiling Top-Level Form: 

    FOO
    NIL
    NIL
    cmu> (time (foo))
    ; Compiling LAMBDA NIL: 
    ; Compiling Top-Level Form: 

    ; Evaluation took:
    ;   0.36f0 seconds of real time
    ;   0.356608f0 seconds of user run time
    ;   1.3f-4 seconds of system run time
    ;   795,761,092 CPU cycles
    ;   0 page faults and
    ;   0 bytes consed.
    ; 
    NIL
    cmu> 

The byte-coded version runs at ~800 CPU cycles/iteration.

And we already know from above what we'll get from the next one...
[Note: CMUCL won't let you machine-compile a byte-code-compiled
function, so we have to redefine it first.]

    cmu> (defun foo () () (dotimes (i 1000000)))

    FOO
    cmu> (compile *)
    ; Compiling LAMBDA NIL: 
    ; Compiling Top-Level Form: 

    FOO
    NIL
    NIL
    cmu> (time (foo))
    ; Compiling LAMBDA NIL: 
    ; Compiling Top-Level Form: 

    ; Evaluation took:
    ;   0.0f0 seconds of real time
    ;   9.07f-4 seconds of user run time
    ;   6.f-6 seconds of system run time
    ;   2,010,596 CPU cycles
    ;   0 page faults and
    ;   0 bytes consed.
    ; 
    NIL
    cmu> 

Back to 2 CPU cycles/iteration, as with the open-coded
top-level call to TIME.

This is as it should be, IMHO. Simple REPL examples get compiled,
for convenience, but users still have a way to control what kind
of code is being timed if they want to.


-Rob

p.s. Another way to defeat the automatic compilation ny TIME
in CMUCL is to call TIME in a non-null lexical environment:

    cmu> (let ((n 1000000))
	   (time (dotimes (i n))))
    Warning:  TIME form in a non-null environment, forced to interpret.
    Compiling entire form will produce more accurate times.

    ; [GC threshold exceeded with 13,354,376 bytes in use.  Commencing GC.]
    ; [GC completed with 1,458,880 bytes retained and 11,895,496 bytes freed.]
    ; [GC will next occur when at least 13,458,880 bytes are in use.]
    ; [GC threshold exceeded with 13,468,072 bytes in use.  Commencing GC.]
    ; [GC completed with 1,464,848 bytes retained and 12,003,224 bytes freed.]
    ; [GC will next occur when at least 13,464,848 bytes are in use.]
    ; [GC threshold exceeded with 13,478,408 bytes in use.  Commencing GC.]
    ; [GC completed with 1,474,912 bytes retained and 12,003,496 bytes freed.]
    ; [GC will next occur when at least 13,474,912 bytes are in use.]
    ; [GC threshold exceeded with 13,488,472 bytes in use.  Commencing GC.]
    ; [GC completed with 1,484,976 bytes retained and 12,003,496 bytes freed.]
    ; [GC will next occur when at least 13,484,976 bytes are in use.]

    ; Evaluation took:
    ;   3.12f0 seconds of real time
    ;   3.081772f0 seconds of user run time
    ;   0.0f0 seconds of system run time
    ;   6,885,980,850 CPU cycles
    ;   [Run times include 0.06f0 seconds GC run time]
    ;   0 page faults and
    ;   48,010,624 bytes consed.
    ; 
    NIL
    cmu> 

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607