|
|
1.1 ! root 1: (setq rcs-prof- ! 2: "$Header: /usr/lib/lisp/RCS/prof.l,v 1.2 83/03/27 18:09:22 jkf Exp $") ! 3: ! 4: ;; prof ! 5: ;; dynamic profiler for lisp -[Tue Mar 8 08:15:47 1983 by jkf]- ! 6: ;; ! 7: ;; use: ! 8: ;; -> (load 'prof) ;may not be necessary if autoloading is set up ! 9: ;; -> (prof-start) ; start the profiling ! 10: ;; ... do what ever you want here, but don't do a (reset) since ! 11: ;; that turns off profiling ! 12: ;; -> (prof-end) ; type this when you are finished ! 13: ;; -> (prof-report) ; then type this, it will list each funtion ! 14: ;; ; that was called, who called this function ! 15: ;; ; and who this function calls. ! 16: ;; ! 17: ;; prof uses the evalhook/funcallhook mechanism to get control everytime ! 18: ;; a function is called. When it gets control, it knows what function ! 19: ;; is doing the calling (via the Pcaller special variable) and what ! 20: ;; function is being called. It maintains a running count for each ! 21: ;; function of the functions which call it and the number of time they ! 22: ;; do the calling. ! 23: ;; ! 24: ;; When prof-end is called, the profiling is turned off and the ! 25: ;; records kept are inverted, that is for each function it is calculated ! 26: ;; how many times it calls other functions. A list describing the results ! 27: ;; is created and assigned to Profreport . When prof-report is called, ! 28: ;; this record (value of Profreport) is printed in a nice human ! 29: ;; readable way. ! 30: ;; ! 31: ;; multiple profiling runs can be made one after the other and all ! 32: ;; counts will revert to zero. ! 33: ;; ! 34: ! 35: ! 36: (declare (special Pcalledby Pcalls Pfcns Pcaller evalhook funcallhook ! 37: Profreport Ptotcalls Pcallcnt Profile-in-progress)) ! 38: ! 39: ;--- prof-start :: start profiling ! 40: ; ! 41: ; ! 42: (defun prof-start nil ! 43: (setq Pcalledby (gensym) ; plist tag for who calls us ! 44: Pcalls (gensym) ; plist tag for who we call ! 45: Pfcns (list '<top-lev>) ; list of all functions encountered ! 46: Pcaller '<top-lev> ; function being evaluated ! 47: Pcallcnt (gensym) ; plist tag for tot number of times called ! 48: Ptotcalls 0 ; total number of function calls ! 49: Profile-in-progress t) ; indicate we are begin done ! 50: (sstatus translink nil) ! 51: (setq evalhook 'Pevalhook* funcallhook 'Pfuncallhook*) ! 52: (*rset t) ! 53: (msg "profiling beginning" N) ! 54: (sstatus evalhook t) ! 55: t) ! 56: ! 57: ;--- prof-end :: turn off profiling and generate result list. ! 58: ; ! 59: (defun prof-end nil ! 60: ; turn off profiling ! 61: (sstatus evalhook nil) ! 62: (setq evalhook nil funcallhook nil) ! 63: (*rset nil) ! 64: (setq Profile-in-progress nil) ! 65: (msg (length Pfcns) " different functions called" N) ! 66: ; generate a profile report ! 67: ; we already know for each function, who calls that function, now ! 68: ; we want to figure out who each function calls ! 69: (do ((xx Pfcns (cdr xx)) ! 70: (fcn)) ! 71: ((null xx)) ! 72: (setq fcn (car xx)) ! 73: (do ((called (get fcn Pcalledby) (cdr called)) ! 74: (callcnt 0)) ! 75: ((null called) ! 76: ; save total number of times this function was called ! 77: (putprop fcn callcnt Pcallcnt) ! 78: (setq Ptotcalls (+ callcnt Ptotcalls))) ! 79: ; keep count of the number of time we've been called ! 80: (setq callcnt (+ (cdar called) callcnt)) ! 81: ; update data on caller. ! 82: (putprop (caar called) ! 83: (cons (cons fcn (cdar called)) ! 84: (get (caar called) Pcalls)) ! 85: Pcalls))) ! 86: ! 87: (msg Ptotcalls " function calls made" N) ! 88: ! 89: ; sort by total calls to function ! 90: (setq Pfcns (sort Pfcns 'totcallsort)) ! 91: ! 92: ; generate report list, really a list of lists each one with this ! 93: ; form: ! 94: ; function-name info who-called-it number-of-times-called who-it-called ! 95: ; ! 96: ; the car of the report form is the total number of function calls made ! 97: (do ((rep nil) ! 98: (xx Pfcns (cdr xx))) ! 99: ((null xx)(setq Profreport (cons Ptotcalls rep))) ! 100: (setq rep (cons (list (car xx) ! 101: (get (car xx) 'fcn-info) ! 102: (get (car xx) Pcalledby) ! 103: (get (car xx) Pcallcnt) ! 104: (get (car xx) Pcalls)) ! 105: rep))) ! 106: 'done) ! 107: ! 108: (declare (special poport)) ! 109: ! 110: ;--- prof-report :: generate a human readable version of prof report ! 111: ; input: Profreport (global) : variable set by (prof-end) ! 112: ; ! 113: (defun prof-report (&optional (filename nil file-p)) ! 114: (if Profile-in-progress ! 115: then (msg "[prof-end]" N) ! 116: (prof-end)) ! 117: (let ((totcalls (car Profreport)) ! 118: (poport poport)) ! 119: (cond (file-p (setq poport (outfile filename)))) ! 120: (do ((xx (cdr Profreport) (cdr xx)) ! 121: (name ) (info) (calledby) (calls) (callcnt)) ! 122: ((null xx)) ! 123: (setq name (caar xx) ! 124: info (cadar xx) ! 125: calledby (caddar xx) ! 126: callcnt (cadddar xx) ! 127: calls (caddddar xx)) ! 128: (msg ":: " name " ") ! 129: (pctprint callcnt totcalls) ! 130: (If info then (msg " - " (cutatblank (cadr info)))) ! 131: (msg N) ! 132: (If calledby ! 133: then (msg "Called by:" N) ! 134: (do ((yy (sort calledby 'lesscdr) (cdr yy))) ! 135: ((null yy)) ! 136: (msg " " (cdar yy) " :: " (caar yy) N))) ! 137: (If calls ! 138: then (msg " Calls: " N) ! 139: (do ((yy (sort calls 'lesscdr) (cdr yy))) ! 140: ((null yy)) ! 141: (msg " " (cdar yy) " :: " (caar yy) N))) ! 142: (msg N N)) ! 143: (cond (file-p (close poport))) ! 144: nil)) ! 145: ! 146: ! 147: ;--- totcallsort :: sort by number of calls and then alphabetically ! 148: ; ! 149: ; this is the predicate used when sorting the list of functions ! 150: ; called during the profiling run. ! 151: ; ! 152: (defun totcallsort (x y) ! 153: (let ((xc (get x Pcallcnt)) ! 154: (yc (get y Pcallcnt))) ! 155: (If (< xc yc) ! 156: thenret ! 157: elseif (= xc yc) ! 158: then (alphalessp x y) ! 159: else nil))) ! 160: ! 161: ;--- lesscdr :: sort by decreasing cdr's ! 162: ; ! 163: (defun lesscdr (x y) ! 164: (> (cdr x) (cdr y))) ! 165: ! 166: ;--- pctprint :: print fraction and then percentage ! 167: ; ! 168: (defun pctprint (this tot) ! 169: (msg this "/" tot " " (quotient (* this 100) tot) "% ")) ! 170: ! 171: ;--- cutatblank :: cut off a string at the first blank ! 172: ; ! 173: (defun cutatblank (str) ! 174: (do ((i 1 (1+ i))) ! 175: ((> i 50) str) ! 176: (If (= (substringn str i 0) #\sp) ! 177: then (return (substring str 1 i))))) ! 178: ! 179: ! 180: ;--- Pfuncall-evalhook* :: common code to execute when function called. ! 181: ; ! 182: ; this function is called whenever a funcallhook or evalhook is taken. ! 183: ; arguments are the form being evaluated and the type of the form ! 184: ; which is either eval or funcall. The difference is that a funcall's ! 185: ; arguments are already evaluated. This makes no difference to us ! 186: ; but it will effect how the instruction is restarted. ! 187: ; ! 188: (defun Pfuncall-evalhook* (form type) ! 189: (let (name rcd (Pcaller Pcaller)) ! 190: (If (and (dtpr form) (symbolp (setq name (car form)))) ! 191: then (If (setq rcd (get name Pcalledby)) ! 192: then (let ((rent (assq Pcaller rcd))) ! 193: (If rent ! 194: then (rplacd rent (1+ (cdr rent))) ! 195: else (putprop name ! 196: (cons (cons Pcaller 1) ! 197: rcd) ! 198: Pcalledby))) ! 199: else ; function hasn't been called before, set up a ! 200: ; record and add its name to the function list ! 201: (putprop name (ncons (cons Pcaller 1)) Pcalledby) ! 202: (setq Pfcns (cons name Pfcns))) ! 203: (setq Pcaller name)) ! 204: ; now continue executing the function ! 205: (Pcontinue-evaluation form type))) ! 206: ! 207: ! 208: ! 209: ! 210: ;; the functions below are taken from /usr/lib/lisp/step.l and modified ! 211: ; slightly (addition of P to name) ! 212: ! 213: ;--- Pfuncallhook* ! 214: ; ! 215: ; automatically called when a funcall is done and funcallhook*'s ! 216: ; value is the name of this function (Pfuncallhook*). When this is ! 217: ; called, a function with n-1 args is being funcalled, the args ! 218: ; to the function are (arg 1) through (arg (sub1 n)), the name of ! 219: ; the function is (arg n) ! 220: ; ! 221: (defun Pfuncallhook* n ! 222: (let ((name (arg n)) ! 223: (args (listify (sub1 n)))) ! 224: (Pfuncall-evalhook* (cons name args) 'funcall))) ! 225: ! 226: ;--- Pevalhook* ! 227: ; ! 228: ; called whenever an eval is done and evalhook*'s value is the ! 229: ; name of this function (Pevalhook*). arg is the thing being ! 230: ; evaluated. ! 231: ; ! 232: (defun Pevalhook* (arg) ! 233: (Pfuncall-evalhook* arg 'eval)) ! 234: ! 235: (defun Pcontinue-evaluation (form type) ! 236: (cond ((eq type 'eval) (evalhook form 'Pevalhook* 'Pfuncallhook*)) ! 237: (t (funcallhook form 'Pfuncallhook* 'Pevalhook*))))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.