;;; -*- Mode: LISP; Package: USER; Base: 10; Syntax: Common-lisp -*- ;;; LaHaShem HaAretz U'Mloah ;;; This file contains a program profiling utility routine. ;;; It is used to determine where the processing time is spent in user ;;; programs. It is similar in intent to the PC metering tools provided ;;; by Symbolics. The Symbolics tools however, only gather info on the ;;; lowest level function which is running when a meter sample is taken. ;;; As most of the samples indicate system functions such as CAR, this ;;; gives little information about the running characteristics of the users ;;; code. These tools instead trace up the stack giving a metering "point" ;;; to every nested function at each sample tick. The tick rate is given ;;; by the variable *profile-sample-rate* which is how many seconds between ;;; samples. Various reporting mechanisms then return the amount of time ;;; spent in each function. Clearly each percentages lies between 0% and 100% ;;; though their sum will total more than 100%. For example if function A ;;; calls B and C, B calls D and E, and C calles F and G then the following ;;; might be a reasonable profiling result: ;;; 100% A ;;; 60% B ;;; 40% C ;;; 20% D ;;; 40% E ;;; 30% F ;;; 5% G ;;; Note that the sum of F and G is less than E as some time was spent ;;; directly in E and not its decendents. If a function's decedents each ;;; have only one caller than the sum of the decendent percentages should ;;; be less than or equal to the parent percentage. This may not be the ;;; case when a function has more than one caller. Also a recursive call ;;; to a function is only counted once per sample tick. ;;; ;;; Sampling is accomplished by the macro profile. To sample the execution ;;; of some lisp form
issue: ;;; (profile ) ;;; or ;;; :Profile ;;; which runs and returns the results of (just like eval) ;;; but which gathers profiling statistics as a side effect. ;;; Profiling terminates either when returns, or when is aborted. ;;; As the profiler runs in a background process which accesses global ;;; variables, only one process may be profiled at a time. In order to ;;; achieve the greatest accuracy, the process to be profiled should run ;;; at priority 0 and no other process of priority greater than or equal to 0 ;;; should be doing significant work. ;;; ;;; Gathering of sample ticks is cummulative. It is possible to do several ;;; calls to profile and print the cummulative results together. Clearing ;;; of the sample data base is accomplished by issuing: ;;; (initialize-profiler) ;;; or ;;; :Initialize Profiler ;;; ;;; By issuing the function: ;;; (profiler-graph) ;;; or ;;; :Show Profiler Graph ;;; a graph window is displayed which represents the calling structure ;;; of user functions. Root functions appear at the left margin while the ;;; caller-callee relationship progresses to the right. Recursive calls ;;; are pruned. A root function is defined to be any user function which ;;; is not called by any other user function. Functions which have been ;;; sampled are annotated with with their sampling percentages. Scrolling ;;; can be accomplished either with the scroll bars or by the following ;;; key-strokes: Scroll - down ;;; m-Scroll - up ;;; c-Scroll - right ;;; c-m-Scroll - left ;;; The profiler graph window is running in a separate process so it is ;;; possible to go back and forth between it and other windows including ;;; the window which issued the call to profiler-graph. It is possible to ;;; select the profiler graph window by issuing a