Subject: Re: Function tracing in CMUCL
From: rpw3@rpw3.org (Rob Warnock)
Date: Tue, 15 Feb 2005 05:34:50 -0600
Newsgroups: comp.lang.lisp
Message-ID: <CrOdnTbaYY3HQ4zfRVn-jQ@speakeasy.net>
Jan Gregor  <gregor.jan@NOSPAMquick.cz> wrote:
+---------------
| I tried all advices but none help. Does somebody have tested solution ?
+---------------

Oddly enough, a combination of compiling and rewriting (FAC arg)
as (FUNCALL 'FAC arg) seemed to do the trick, though neither one
alone did:

    > (lisp-implementation-type)

    "CMU Common Lisp"
    > (lisp-implementation-version)

    "19a"
    > (defun fac (n)
      (if (<= n 1)
	1
	(* n (funcall 'fac (1- n)))))

    FAC
    > (compile 'fac)
    ; Compiling LAMBDA (N): 
    ; Compiling Top-Level Form: 

    FAC
    NIL
    NIL
    > (trace fac)

    (FAC)
    > (fac 5)

      0: (FAC 5)
	1: (FAC 4)
	  2: (FAC 3)
	    3: (FAC 2)
	      4: (FAC 1)
	      4: FAC returned 1
	    3: FAC returned 2
	  2: FAC returned 6
	1: FAC returned 24
      0: FAC returned 120
    120
    > 

But you don't want to have to rewrite everything all time, so
thankfully there's a better way. Look in the "CMUCL User's Manual",
Chapter 5 "Advanced Compiler Use and Efficiency Hints", section
5.6.1 "Self-Recursive Calls", and you'll find this little note:

    Local call is used when a function defined by defun calls itself.
    For example: 

	  (defun fact (n)
	    (if (zerop n)
		1
		(* n (fact (1- n)))))

    This use of local call speeds recursion, but can also complicate
    debugging, since trace will only show the first call to fact,
    and not the recursive calls. This is because the recursive calls
    directly jump to the start of the function, and don't indirect
    through the symbol-function. Self-recursive local call is inhibited
    when the :block-compile argument to compile-file is nil (see section
    5.7.3.)

And, indeed:

    $ cat fac.lisp
    (defun fac (n) 
      (if (<= n 1)
	1
	(* n (fac (1- n)))))
    $ cmu
    > (load "fac.lisp")                     

    ; Loading #p"/usr/u/rpw3/fac.lisp".
    T
    > (trace fac) 

    (FAC)
    > (fac 5)

      0: (FAC 5)
      0: FAC returned 120
    120
    > (untrace)
    > (compile-file "fac" :block-compile nil)

    ; Python version 1.1, VM version Intel x86 on 15 FEB 05 03:30:22 am.
    ; Compiling: /usr/u/rpw3/fac.lisp 15 FEB 05 03:21:00 am

    ; Converted FAC.
    ; Compiling DEFUN FAC: 
    ; Byte Compiling Top-Level Form: 

    ; fac.x86f written.
    ; Compilation finished in 0:00:00.

    #p"/usr/u/rpw3/fac.x86f"
    NIL
    NIL
    > (load *)

    ; Loading #p"/usr/u/rpw3/fac.x86f".
    T
    > (trace fac)

    (FAC)
    > (fac 5)

      0: (FAC 5)
	1: (FAC 4)
	  2: (FAC 3)
	    3: (FAC 2)
	      4: (FAC 1)
	      4: FAC returned 1
	    3: FAC returned 2
	  2: FAC returned 6
	1: FAC returned 24
      0: FAC returned 120
    120
    > 

Hope that helps,


-Rob

p.s. Note that there is a significant performance penalty to turning
off block-compilation, though if it helps debugging...

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