It is generally only worth profiling code which has been compiled. If you profile interpreted code, the interpreter itself is profiled, and this skews the results for the actual Lisp program.
Macros cannot be profiled because they are expanded during the compilation process.
Always bear in mind that the numbers produced are from random samples, so you should be careful when interpreting their meaning. The rate of sampling is always coarse in comparison to the function call rate, so it is possible for strange effects to occur and significant events to be missed. For example, resonance may occur when an event always occurs between regular sampling times. In practice, however, this is not usually a problem.
Recursive functions need special attention. A recursive function may well be found on the stack in more than one place during one interrupt. The profiler counts each occurrence of the function, and so the total number of times a function is found on the stack may be greater than the number of times the stack is examined.
You must take care when profiling structure accessors. These compile down into a call to a closure, of which there is one for all structure setters and one for all structure getters. Therefore it is not possible to profile individual structure setters or getters by name.
Even if you configure the Profiler to profile all the known functions of an application, it is possible that less than 100% of the time is spent monitoring the top function. This is because an internal system function could be on the top of the stack at the time of the interrupt.
If you configure the Profiler to omit certain functions then these will not be displayed in the Results area, and so the display may not match what you expect from your source code.
With certain compiler settings code can be optimized such that the Profiler data does not appear to match your source code. For example when a tail call is optimized, the tail-called function appears in the call tree as a child of the parent of the caller, rather than as a child of its caller (just as in the debugger stack). Similarly code using funcall
or apply
may yield confusing results. To prevent tail-call optimization, use compiler setting debug 3
.
The compiler may transform some functions such that they are present in the source code but not in the compiled code.
For example, the compiler transforms this source expression:
(member 'x '(x y z) :test #'eq)
into this compiled expression:
(memq 'x '(x y z))
Therefore function memq
will appear instead of member
in the profile results.
LispWorks IDE User Guide (Windows version) - 13 Sep 2017