stack trace in newlisp for debugging?

Q&A's, tips, howto's
Locked
TedWalther
Posts: 608
Joined: Mon Feb 05, 2007 1:04 am
Location: Abbotsford, BC
Contact:

stack trace in newlisp for debugging?

Post by TedWalther »

Hi. I did some searching on Google and this forum for "newlisp stack trace" and "newlisp call stack" and "newlisp traceback".

When debugging, sometimes it is very helpful to introspect and see "what combination of function calls led to where we are right now". Especially inside of event and error handlers.

Lutz, does newlisp provide some standard way to walk the stack backwards and know how we got to where we are? I want to make a debug function to printf the call-chain and how it got us to where we are.

Also, such a "traceback" would be helpful in general when newlisp gives an error message and drops into the debugger.

And, if you had such a traceback call, what would make it doubly sweet and miles ahead of Common Lisp and Scheme, is that it would show macros the same as functions.

And finally, it would be nice if the traceback also had an option to show the arguments as they were passed to the function call, and as the function call received them. Ie, I might do (foo a b c) but foo sees itself being called as (foo 1 2 3).
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.

ralph.ronnquist
Posts: 228
Joined: Mon Jun 02, 2014 1:40 am
Location: Melbourne, Australia

Re: stack trace in newlisp for debugging?

Post by ralph.ronnquist »

I'm with you at the wishing well for this one, and mad as I am, I translated this into the attached patch, which modifies the execution procedure ever so slightly, and adds the primitive function (map-stack f) to map function f over the lambda call frames in reverse time order, and collate their results.

This makes use of the "lambda stack", but slightly revised so as to hold on to the "call frames" rather than just the functors, i.e., including the actual call parameters. There's a a bit of a memory management challenge in this, and I resorted to copying the arguments (again), rather than trying to track down how it really should be done.

Note that one can pick up the call chain in an error-event handler, which can be quite useful. Here's an example test code for illustration.

Code: Select all

(error-event
  (fn () (println (last-error)) (println (map-stack (fn (x) x)))))

(define (recursion x y)
  (amb (rickety bam bam)
       (recursion (- y x) (+ x 3))
       (recursion (+ y x) (+ x 4))
       (recursion (+ y x) (+ x 5)) ))

(recursion 1 1)
The patch is for 10.6.3 as of today, and maybe some weeks or months earlier.

Note that there is an obvious performance hit with this, but it could of course be opted in or out with a command line flag, as a debug mode. It doesn't affect the execution path in any way other than collecting the call frames.

TedWalther
Posts: 608
Joined: Mon Feb 05, 2007 1:04 am
Location: Abbotsford, BC
Contact:

Re: stack trace in newlisp for debugging?

Post by TedWalther »

Wow. Ralph, may I see your patch? My private email address will be in your inbox here on the forum momentarily. Somehow the patch didn't get attached to the forum. But the use case looks good.
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence. Nine months later, they left with a baby named newLISP. The women of the ivory towers wept and wailed. "Abomination!" they cried.

ralph.ronnquist
Posts: 228
Joined: Mon Jun 02, 2014 1:40 am
Location: Melbourne, Australia

Re: stack trace in newlisp for debugging?

Post by ralph.ronnquist »

Yes. I thought I had attached it to the post, but I wasn't observant enough to see that the "attach file" had taken issue with the file name.
Attachments
map-stack.txt.gz
(1.49 KiB) Downloaded 292 times

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: stack trace in newlisp for debugging?

Post by Lutz »

Here is my solution to this:

http://www.newlisp.org/downloads/develo ... nprogress/

New syntax: (trace device-no) prints an evaluation trace to device-no. Example:

Code: Select all

(trace (open "trace.txt" "w")) ; open trace file
 ... ; one or more expressions to evaluate
(trace nil) ; close trace file
The file trace.txt now contains the trace. You could use tail -f trace.txt to watch it in another window. Also nice when working from the REPL in another window.

Ps: the function call level is also shown.
Ps: now also writes error info to trace file when error is thrown.

ralph.ronnquist
Posts: 228
Joined: Mon Jun 02, 2014 1:40 am
Location: Melbourne, Australia

Re: stack trace in newlisp for debugging?

Post by ralph.ronnquist »

A map-stack patch variation, which 1) makes map-stack stop when the invoked function returns nil (i.e., similar to collect), and 2) makes the error-event be invoked before system reset also at the interactive prompt. The latter changes this event invocation to be the same as during file loading (which is to reset the system subsequent to the invocation), and I prefer this behaviour, since it allows for stack inspection in the error event handler.
Attachments
map-stack2.txt.gz
(1.65 KiB) Downloaded 273 times

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: stack trace in newlisp for debugging?

Post by Lutz »

Thanks Ralph, I incorporated some of your ideas in the code for better error reporting. So now we have a better error reporting with more information and we have the new (trace device-no) mode.

The following interactive session shows how things behave on 10.6.2:

Code: Select all

> (define (foo x) (bar x))
(lambda (x) (bar x))
> (define (bar x) (baz x))
(lambda (x) (baz x))
> (foo 123)

ERR: invalid function : (baz x)
called from user function bar
called from user function foo
> 
The following shows changes included from Ralph in 10.6.3:

Code: Select all

> (define (foo x) (bar x))
(lambda (x) (bar x))
> (define (bar x) (baz x))
(lambda (x) (baz x))
> (foo 123)

ERR: invalid function : (baz x)
called from user function (bar x)
called from user function (foo 123)
> 
An this shows the final 10.6.3 with the new trace mode:

Code: Select all

> (trace (open "trace.txt" "w"))
3
> (define (foo x) (bar x))
(lambda (x) (bar x))
> (define (bar x) (baz x))
(lambda (x) (baz x))
> (foo 123)

ERR: invalid function : (baz x)
called from user function (bar x)
called from user function (foo 123)
nil
we continue the same session showing the contents from the newLISP command-line using the ! :

Code: Select all

> !cat trace.txt
1 exit: 3
1 entry: (define (foo x) 
 (bar x))
1 exit: (lambda (x) (bar x))
1 entry: (define (bar x) 
 (baz x))
1 exit: (lambda (x) (baz x))
1 entry: (foo 123)
2 entry: (bar x)
3 entry: (baz x)
3 ERR: invalid function : (baz x)
called from user function (bar x)
called from user function (foo 123): 
3 exit: nil
2 exit: nil
1 exit: nil
> 
Ps: I still like Ted's idea to do it all using newLISP but the native implementation could be done with minimum additions in the code and without performance hit when not in trace mode.

Ps: Note that #define NO_DEBUG in newlisp.h will only exclude the debug mode but the new trace mode will still work.

rickyboy
Posts: 607
Joined: Fri Apr 08, 2005 7:13 pm
Location: Front Royal, Virginia

Re: stack trace in newlisp for debugging?

Post by rickyboy »

Just being a lurker from afar: thank you all -- Ralph, Ted and Lutz -- for your attention to this issue. Please know it's much appreciated by the rest of newlisperdom.
(λx. x x) (λx. x x)

xytroxon
Posts: 296
Joined: Tue Nov 06, 2007 3:59 pm
Contact:

Re: stack trace in newlisp for debugging?

Post by xytroxon »

rickyboy wrote:Just being a lurker from afar: thank you all -- Ralph, Ted and Lutz -- for your attention to this issue. Please know it's much appreciated by the rest of newlisperdom.
Ditto! ;p)

-- xytroxon
"Many computers can print only capital letters, so we shall not use lowercase letters."
-- Let's Talk Lisp (c) 1976

Locked