While the program executes under the profiler, the system builds a dynamic call-tree. It does this using three hooks from the kernel: one that starts a new goal (profCall), one that tells the system which goal is resumed after an exit (profExit) and one that tells the system which goal is resumed after a fail (i.e., which goal is used to retry (profRedo)). The profCall() function finds or creates the subnode for the argument predicate below the current node, increments the call-count of this link and returns the sub-node which is recorded in the Prolog stack-frame. Choice-points are marked with the current profiling node. profExit() and profRedo() pass the profiling node where execution resumes.
Just using the above algorithm would create a much too big tree due to recursion. For this reason the system performs detection of recursion. In the simplest case, recursive procedures increment the `recursive' count on the current node. Mutual recursion, however, is not easily detected. For example, call/1 can call a predicate that uses call/1 itself. This can be viewed as a recursive invocation, but this is generally not desirable. Recursion is currently assumed if the same predicate with the same parent appears higher in the call-graph. Early experience with some non-trivial programs are promising.
The last part of the profiler collects statistics on the CPU time
used in each node. On systems providing setitimer() with
SIGPROF, it `ticks' the current node of the call-tree each
time the timer fires. On Windows, a MM-timer in a separate thread checks
100 times per second how much time is spent in the profiled thread and
adds this to the current node. See section
18.104.22.168 for details.
Profiling in the Windows version is similar, but as profiling is a statistical process it is good to be aware of the implementation133We hereby acknowledge Lionel Fourquaux, who suggested the design described here after a newsnet enquiry. for proper interpretation of the results.
Windows does not provide timers that fire asynchronously, frequent and proportional to the CPU time used by the process. Windows does provide multi-media timers that can run at high frequency. Such timers, however, run in a separate thread of execution and they are fired on the wall clock rather than the amount of CPU time used. The profiler installs such a timer running, for saving CPU time, rather inaccurately at about 100 Hz. Each time it is fired, it determines the CPU time in milliseconds used by Prolog since the last time it was fired. If this value is non-zero, active predicates are incremented with this value.