PDA

View Full Version : Time to run a LISP Routine?



stusic
2013-01-09, 04:53 PM
Is there a subroutine I can use to record how long a lisp routine takes to run? Just print it on the command line when it done? I haven't been able to find anything along those lines, just general Autocad benchmark type things.

Thanks,

BlackBox
2013-01-09, 06:42 PM
I use Bench.lsp, by RobertB... I cannot seem to find a link online, so I hesitate to post his code here, as he has a line about obtaining written permission. I'll PM him now.

rkmcswain
2013-01-09, 06:56 PM
Is there a subroutine I can use to record how long a lisp routine takes to run? Just print it on the command line when it done? I haven't been able to find anything along those lines, just general Autocad benchmark type things.

Thanks,

Pseudo code....
Record the time just before you start
Record the time when it ends.
Do the math and the conversion to seconds.

See the "date->sec" function and the other code here: http://www.cadtutor.net/forum/showthread.php?44768-Entmake-Functions&p=308808&viewfull=1#post308808

BlackBox
2013-01-09, 06:59 PM
I use Bench.lsp, by RobertB... I cannot seem to find a link online, so I hesitate to post his code here, as he has a line about obtaining written permission. I'll PM him now.

Robert was kind enough to grant permission to post here:



;|

Bench.lsp

Version history
2.2 2002/11/18 Moved the (read) statement outside the repeat loop for
slightly move accurate results (to avoid unneeded reads).
Note that (apply) is still more accurate than to (cons) and (eval).
Added a 1 second delay after (gc) to attempt to even multiple tests.
2.1 2001/03/20 Permit defun-q or defun functions and actual variables.
2.0 2000/08/28 Changed to use Setvar Millisecs, and permit any number
of functions & arguments.
1.1 2000/01/25 Report only average time, to reduce getvar calls.
1.0 1989/04/03 Initial release.

This routine finds the elapsed average time for any number of functions.
NOTE: The routines cannot be a command (c:whatever).
This code was based on an algorithm written by Jadranko Stjepanovic.

Dependencies: none
Example: (Bench '(func1 func2) '(arg1 arg2) 1000), or:
(Bench '("func1" "func2") "arg1 arg2" 1000)
Usage: (Bench Funcs Args Count)
Arguments: Funcs list of functions
Args list of arguments, or string of variables
Returns: print of average times

Copyright © 1989-2002 by R. Robert Bell.

Written permission must be obtained to distribute this software.
Permission to use this software for any purpose and without fee is hereby granted,
provided that the above copyright notice appears in all copies and that both
the copyright notice and the limited warranty and restricted rights notice below
appear in all supporting documentation.

R. ROBERT BELL PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
R. ROBERT BELL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.
R. ROBERT BELL DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM
WILL BE UNINTERRUPTED OR ERROR FREE.

RobertB@acadx.com

|;

(defun Timer (Func ; function to time
Args ; arguments for function
Count ; # of times to repeat
/
FuncArgs ; read string of function & arguments
Start) ; start time
(gc) ; perform garbage collection
(setq Start (getvar "Millisecs"))
(while (< (getvar "Millisecs") (+ Start 1000))) ; wait for 1 second before entering loop

(if (= (type Args) 'STR) ; if looking at (defun) functions
;; Below code is time sensitive, not written to be algorithm optimized
(progn ; then...
(setq FuncArgs (read (strcat "(" Func " " Args ")")) ; create function to eval
Start (getvar "Millisecs")) ; turn on timer
(repeat Count (eval FuncArgs))
(- (getvar "Millisecs") Start)) ; return elapsed time
(progn ; else...
(setq Start (getvar "Millisecs")) ; turn on timer
(repeat Count (apply Func Args)) ; put arguments to function
(- (getvar "Millisecs") Start)))) ; return elapsed time

(defun Bench (Funcs ; list of functions
Args ; list of arguments
Count ; # of times to repeat
/
Time)
(foreach Func Funcs ; for each function in list
(terpri) ; print blank line
(princ Func) ; print function name
(princ
(strcat "\nElapsed: " (itoa (setq Time (timer Func Args Count)))))
(princ (strcat "\nAverage: " (rtos (/ (float Time) Count) 2 4)))
(terpri))
(princ))

(princ
(strcat "\nUsage: (Bench '(func1 func2) '(arg1 arg2) 1000) for \"hard\" arguments,"
"\nor (Bench '(\"func1\" \"func2\") \"arg1 arg2\" 1000) for actual bound variables."))

stusic
2013-01-09, 07:28 PM
Thank you both. This will work much better than using the stopwatch on my phone and *vigilantly* watching the command line. :)

irneb
2013-01-10, 12:16 PM
Uhmm ... from your OP it seems you simply want to know how long it takes to run a single code. Usually it's not too easy to do that, since most codes would only take fractions of seconds. Anyhow, here's a variant of mine:
(defun bench1 (statement count / time)
(setq time (getvar "MilliSecs"))
(repeat count (eval statement))
(- (getvar "MilliSecs") time))Notice I can't just have it run once
_$ (bench1 '(expt 567.0 (/ 4356.86 45.3)) 10)
0
_$ (bench1 '(expt 567.0 (/ 4356.86 45.3)) 1000)
31
_$ (bench1 '(expt 567.0 (/ 4356.86 45.3)) 10000)
203That's 0.203 seconds to run 10,000 times.

Anyhow, I tend to use a comparison benchmarking to test one function in comparison to another (or even more than 2):
(defun quickbench (statements / maxinc _printformat _rtodec)
;; By: Irné Barnard
(princ "Benchmarking ")
(setq statements (mapcar '(lambda (statement / inc inc2 time start stop)
(princ ".")
(setq inc 1
time 0.)
(while (< time 1000)
(gc)
(setq inc2 inc
inc (* inc 2)
start (getvar "MilliSecs"))
(repeat inc2 (eval statement))
(setq stop (getvar "MilliSecs"))
(setq time (+ time (- stop start))))
(list statement inc2 time))
statements)
maxinc (cadar statements))
(foreach statement (cdr statements)
(if (< maxinc (cadr statement))
(setq maxinc (cadr statement))))
(setq statements
(vl-sort (mapcar '(lambda (statement /)
(append statement (list (* (last statement) (/ maxinc (cadr statement))))))
statements)
'(lambda (a b) (< (last a) (last b)))))
(princ (strcat " done for "
(rtos (float maxinc) 2 0)
" iterations. Sorted from fastest.\n"
"Statement Increment Time(ms) Normalize Relative\n"
"--------------------------------------------------------------------------------\n"))
(setq maxinc (float (last (last statements))))
(defun _rtodec (val d / p)
(setq val (rtos val 2 d))
(cond ((> d 0)
(if (not (setq p (vl-string-search "." val)))
(setq p (strlen val)
val (strcat val ".")))
(repeat (- d (- (strlen val) p) -1) (setq val (strcat val "0")))))
val)
(defun _printformat (statement / a v p)
(princ (if (> (strlen (setq a (vl-princ-to-string (car statement)))) 40)
(setq a (strcat (substr a 1 36) "...)"))
a))
(repeat (- 40 (strlen a)) (princ " "))
(setq a (rtos (float (cadr statement)) 2 0))
(repeat (- 10 (strlen a)) (princ " "))
(princ a)
(setq a (rtos (float (caddr statement)) 2 0))
(repeat (- 10 (strlen a)) (princ " "))
(princ a)
(setq a (rtos (setq v (float (last statement))) 2 0))
(repeat (- 10 (strlen a)) (princ " "))
(princ a)
(setq a (_rtodec (/ maxinc v) 2))
(repeat (- 10 (strlen a)) (princ " "))
(princ a)
(princ "\n"))
(foreach statement statements (_printformat statement))
(princ "--------------------------------------------------------------------------------")
(princ))It runs each statement until it's taken at least 1 sec, then adjusts the results for each of the statements to be comparable to each other. Then prints the results out to textscr.

Most of the others I've found have an issue: If one of the statements tested is a lot less efficient than the others the test becomes exorbitantly long, since they all repeat such that the fastest takes 1 sec - then all are repeated the same number of times. In mine it rarely takes more than 2 seconds per statement to do the comparison test. So there's no need to wait several minutes as per some of the other benchmarks.