## `prog::trace` -- observe functions

#### Introduction

`prog::trace(`obj`)` manipulates the MuPAD function `obj` to observe entering and leaving of this function.

#### Call(s)

`prog::trace(obj <, option>)`
`prog::trace(obj_set <, option>)`
`prog::trace(dom, meth_set <, option>)`

#### Parameters

`obj` | - | a MuPAD function, domain or domain method, or function environment to observe
`obj_set` | - | a set of MuPAD functions to observe
`dom` | - | a MuPAD domain to observe
`meth_set` | - | a set of methods of the domain `dom` to observe, given by their name as strings
`option` | - | one of the described options or a set with one or several options

#### Options

`Backup` | - | The option Backup can be used to trace a function, that is already traced. The function will be restored (by `prog::untrace`) and then traced again. This option can be used, if a function should be traced with another options.
`Depth = level` | - | `level` is a positive integer. If this option is given, nested function calls will only be displayed, if the recursion depth is less or equal to `level`.
`Force` | - | The option Force can be used to trace a function, that is already traced. The function will traced again and the backup of the original function will be overwritten. This option can be useful, if a function is newly defined and `prog::trace` refuse a newly trace. The option Backup would replace the new definition by the old backup (see example 2).
`Mem` | - | The option Mem can be used to show the change of memory usage between entering and leaving of an observed function.
`NoArgs` | - | With a view to greater clarity the option NoArgs hides the arguments when entering and leaving of an observed function.
`Plain` | - | With the option Plain the messages are aligned left and not indented to illustrate the dependencies between function calls.

#### Returns

`prog::trace` returns the void object `null()`.

#### Related Functions

`prog::untrace`, `prog::traced`, `setuserinfo`, `debug`, `prog::profile`, `prog::calltree`

#### Details

- `prog::trace` is a very helpful function to observe functions to debug or for information. While tracing functions, the inter-relations between calls to these traced functions can be viewed.
- `prog::trace` will be called with the function `obj` to observe. After that, every call of this function `obj` prints a message, when the function is entered and leaved. The arguments and the return value of the function call will also be printed.

  Every message is indented when entering a function and released when leaving the function (to illustrate the dependencies between function calls). The option Plain can be used to suppress this behaviour.

- If a set of functions is given, all functions in this set are traced.
- `obj` can be a domain or a function environment, too. Then all methods of the domain or the function environment will be observed.

  If the second argument `meth_set` is a set of method names of the domain or function environment `dom`, then all given methods are traced.

  The method `meth` of the domain or function environment `dom` can also be traced directly by `prog::trace(`dom::meth`)`.

- The function `prog::untrace` terminates the observation of a function. The function `prog::traced` detects, whether the function is traced.

#### Example 1

Define a short function, that calls itself recursively, and the calls are observed:

    >> fib:= proc(n)
             begin
               if n < 2 then
                 n
               else
                 fib(n - 1) + fib(n - 2)
               end_if
             end_proc:
       prog::trace(fib):
       fib(3)

          enter 'fib'                            with args   : 3
            enter 'fib'                            with args   : 2
              enter 'fib'                            with args   : 1
              leave 'fib'                            with result : 1
              enter 'fib'                            with args   : 0
              leave 'fib'                            with result : 0
            leave 'fib'                            with result : 1
            enter 'fib'                            with args   : 1
            leave 'fib'                            with result : 1
          leave 'fib'                            with result : 2

                                         2

First restore the function, and then use the option Plain:

    >> prog::untrace(fib):
       prog::trace(fib, Plain):
       fib(3)

          enter 'fib'                            with args   : 3
          enter 'fib'                            with args   : 2
          enter 'fib'                            with args   : 1
          leave 'fib'                            with result : 1
          enter 'fib'                            with args   : 0
          leave 'fib'                            with result : 0
          leave 'fib'                            with result : 1
          enter 'fib'                            with args   : 1
          leave 'fib'                            with result : 1
          leave 'fib'                            with result : 2

                                         2

The option Depth limits the displaying, Backup restores the original code of `fib` before tracing with new options:

    >> prog::trace(fib, {Depth = 2, Backup}):
       fib(12)

          Warning: backup of object 'fib' will be traced [prog::trace]
          enter 'fib'                            with args   : 12
            enter 'fib'                            with args   : 11
            leave 'fib'                            with result : 89
            enter 'fib'                            with args   : 10
            leave 'fib'                            with result : 55
          leave 'fib'                            with result : 144

                                        144

#### Example 2

Define a short function `f` and observe this function:

    >> f := x -> if x > 0 then x else -f(-x) end:
       prog::trace(f):
       f(-2)

          enter 'f'                              with args   : -2
            enter 'f'                              with args   : 2
            leave 'f'                              with result : 2
          leave 'f'                              with result : -2

                                        -2

Now the function is slightly changed and reassigned to `f`. But the trace mechanism does not know the change of the function `f` and denies the newly observation:

    >> f := x -> if x > 0 then x else f(-x) end:
       prog::trace(f):

          Warning: object 'f' is already traced [prog::trace]

In this situation the option Force can be used to force the tracing. The warning means, a possibly existing backup of the function `f` is overwritten:

    >> prog::trace(f, Force):
       f(-2)

          Warning: backup of object 'f' will be replaced [prog::trace]
          enter 'f'                              with args   : -2
            enter 'f'                              with args   : 2
            leave 'f'                              with result : 2
          leave 'f'                              with result : 2

                                         2

Inattentive usage of option Force has following results (the function call prints out multiple messages):

    >> prog::trace(f, Force):
       f(-2)

          Warning: backup of object 'f' will be replaced [prog::trace]
          enter 'f'                              with args   : -2
            enter 'f'                              with args   : -2
              enter 'f'                              with args   : 2
                enter 'f'                              with args   : 2
                leave 'f'                              with result : 2
              leave 'f'                              with result : 2
            leave 'f'                              with result : 2
          leave 'f'                              with result : 2

                                         2

#### Example 3

With the option Mem the memory usage is printed:

    >> prog::trace(sin, Mem):
       sin(x)

          enter 'sin'                            with args   : x
          leave 'sin'                            with result [1327 kB]: sin(x)

                                      sin(x)

The function `sin` takes such a lot of memory...? This happens, when this function call is the first in the session or after a `reset`, because a lot of libraries are loaded, e.g., `property` to preserve properties of identifiers in `sin`.

#### Background

- When calling `prog::trace` with a function `obj` as argument, the function `obj` will be manipulated.

  At beginning of the function a statement will inserted to print a message and the function arguments when entering the function.

  At every location that the function could be leaved a statement will be placed to print a message and the return value of the function.

- The function `prog::untrace` rebuilds the original state of the function. Therefore the function will be saved in an internal table.

#### Changes

- used to be called `sharelib::trace`
- all options are new implemented

Do you have questions or comments?
Copyright © SciFace Software GmbH & Co. KG 2000