;;;;;;; --- Profile Your Functions --- ;;;;;;;;; ;; by (C.) Vladimir Nesterovsky, December 1998. ;; vnestr@netvision.net.il, http://vnestr.tripod.com ;; Free for *non-commercial* personal use only ;; with this notice unchanged. ;; ;; Here's an AutoLISP profiler for measuring the execution ;; speed of your functions. Good for r12-r14; to use it under ;; r2000, change all your DEFUN's to DEFUN-Q's. ;; Unfortunately, we don't have access to a function's ;; lambda-list anymore in r2000's VisualLISP. :-( ;; ;; Happy profiling! ;; ;; ;; usage: (profile-func 'your-function), then ;; call it or a program that's calling it, ;; then use (show-timers). ;; When finished, call (profile-stop). ;; ;; potential problems: ;; slows down the execution while profiling many functions; ;; time is measured by (getvar "date") that might not have ;; fine enough resolution, depending on platform, ;; so timings for fast routines might be not so reliable. ;; but you can measure the execution of many repetitions of the ;; same code with (defun test()(repeat 10000 (yourfunction))) ;; and profiling it instead, with (profile-func 'test). ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; global variables ;; vpn__profiled_funcs *symbol-names* ;; various "vpn__*" vars during the execution (DEFUN PROFILE-FUNC( FSYM / f fname arg-list formals ) (if (not (atom fsym)) (mapcar 'profile-func fsym) (cond ((or (/= 'SYM (type FSYM)) (not (ufuncp (SETQ F (EVAL FSYM)))) ) (mapcar 'princ '( " must be quoted symbol of" " user-defined function to be profiled. ")) (princ) ) ((member fsym vpn__profiled_funcs) (princ " ") (princ (sym2str fsym)) (princ " is being profiled already. ") (princ) ) (T ;; profile this function (setq fname (sym2str fsym)) (IF (= 'PAGETB (TYPE(CAR F))) ;; r12 stuff :-))) (SETQ F (CDR F)) ) (SET (READ (STRCAT "vpn__orig_func_" FNAME)) F) (SETQ ARG-LIST (CAR F) FORMALS (if (MEMBER '/ ARG-LIST) (REVERSE (CDR (MEMBER '/ (REVERSE ARG-LIST)))) arg-list ) ) (princ (EVAL (LIST 'DEFUN Fsym (append formals (list '/ 'result 'strtm 'endtm )) '(setq strtm (getvar "date")) (LIST 'SETQ 'RESULT (CONS (READ (STRCAT "vpn__orig_func_" FNAME)) FORMALS)) '(setq endtm (getvar "date")) (list '+= (list 'quote (READ (STRCAT "VPN__TIMER_FOR_" FNAME))) '(* 86400 (- endtm strtm)) ) (list '+= (list 'quote (read (strcat "vpn__calls_for_" FNAME))) 1) 'RESULT ))) (setq vpn__profiled_funcs (cons fsym vpn__profiled_funcs)) (princ " ") (princ) ) ) )) (defun profile-stop() (restore-funcs) (foreach x (atoms "vpn__timer_for_*,vpn__calls_for_*") (set (read x) nil) ) (setq vpn__profiled_funcs nil) ) (DEFUN RESTART-TIMERS() (foreach x (atoms "vpn__timer_for_*,vpn__calls_for_*") (set (read x) 0) ) ) (defun show-timers( / as nn tm ) (cond ((setq as (atoms "vpn__timer_for_*")) (foreach x (acad_strlsort as) (princ "\n") (princ (substr x 6))(princ ": n=") (princ (setq nn (eval (read (strcat "vpn__calls_for_" (substr x 16)))))) (princ ", t=") (princ (setq tm (eval (read x)))) (princ ", t/call=")(princ (if (zerop nn) "N/A" (/ (float tm) nn))) (princ ".") )) ((princ "\n No timers are being maintained.")) ) (princ "\n") (princ) ) (defun restore-funcs() (foreach x (atoms "vpn__orig_func_*") (set (read (substr x 16)) (eval (read x))) (set (read x) nil) ) ) (defun restore-func(s / q2) (if (strp s) (if (eval (setq q2 (read (strcat "vpn__orig_func_" s)))) (progn (set (read s) (eval q2)) (set q2 nil) (setq vpn__profiled_funcs (minuslist vpn__profiled_funcs (list (read s)))) (foreach x (atoms (strcat "vpn__timer_for_" s ",vpn__calls_for_" s)) (set (read x) nil) ) )) (if s (restore-func (sym2str s))) )) (defun show-funcs() (foreach x (atoms "vpn__orig_func_*") (print (list (setq x (substr x 16)) (eval(read x))))) (princ) ) (defun sym2str (sym ) (if (null *symbol-names*) ;; cache list empty (setq *symbol-names* ;; build it (mapcar 'cons (atoms-family 0) (atoms-family 1)))) (cond ((cdr(assoc sym *symbol-names*))) ((cdar ;; update cache list using SYMSTR (setq *symbol-names* (cons (cons sym (symstr sym)) *symbol-names*)))) )) ;;convert symbol to string; found on Internet. (defun symstr (sym) (if (= (type sym) 'SYM) ( (list (if (boundp sym) (cons '/ (atoms-family 0)) (cons '/ (cons sym (atoms-family 0))) ) (list setq sym 1) (list car (list atoms-family 1)) ) ) ) ) (defun ufuncp(f) ;; User FUNCtion Predicate (and f (listp f) (or (null (car f)) ;; no args (= (type (car f)) 'PAGETB) ;; VMON (and ;; args list (listp (car f)) (null (cdr (last* (car f)))) ;; not dotted list (apply '= (cons 'SYM (mapcar 'type (car f)))) ) ) ) ) ;; last cons cell of a list (defun last* (lst) (while (not (atom (cdr lst))) (setq lst (cdr lst))) lst) (defun += (symbolvariable incrementvalue) (if (numberp (eval symbolvariable)) (set symbolvariable (+ incrementvalue (eval symbolvariable))) (set symbolvariable incrementvalue) )) (defun atoms (pattern / lst) (setq pattern (strcase pattern)) (foreach atomstring (atoms-family 1) (if (wcmatch atomstring pattern) (setq lst (cons atomstring lst)))) (reverse lst)) (defun minuslist ( fromlist elementslist / tmplst ) (foreach element fromlist (if (not (member element elementslist)) (setq tmplst (cons element tmplst)))) (reverse tmplst) ) (defun profile-usage() (mapcar 'princ '( "\n ---= Profile AutoLISP functions =--- " "\n by Vladimir Nesterovsky, vnestr@netvision.net.il" " 1998.\n\nUse (PROFILE-FUNC 'fsym), (RESTORE-FUNCS)," " (SHOW-FUNCS), (SHOW-TIMERS), " "\n (RESTART-TIMERS), (PROFILE-USAGE) " "and (PROFILE-STOP) to stop profiling." )) (princ) ) (profile-usage) ;;;;;;;;;; PROFILE ends ;;;;;;;;;;;