Annotation of 43BSDReno/pgrm/lisp/lisplib/prof.l, revision 1.1

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*))))

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.