Timing utilities for clojure.contrib?

23 views
Skip to first unread message

Jason Wolfe

unread,
Feb 25, 2009, 9:28:51 PM2/25/09
to Clojure
I wrote a small set of functions for executing code while measuring
and/or limiting its time and/or memory consumption. I did this both
to run timing experiments, and to let me run things at the REPL
without risking an infinite loop (and having to restart Clojure from
scratch).

Would anyone else find these useful?

Some snippets:

user> (defn work [] (reduce + (doall (map identity (range 500000)))))
#'user/work
user> (work)
124999750000

; A simple function that does some work


user> (time (do (dotimes [_ 10] (work)) "done"))
"Elapsed time: 6929.528 msecs"
"done"

; The usual time macro


user> (get-time (do (dotimes [_ 10] (work)) "done"))
6754.874

; get-time returns the amount of time taken (in ms), and throws away
the value returned


user> (get-time-pair (do (dotimes [_ 10] (work)) "done"))
["done" 6729.438]

; get-time-pair returns both the value and the time taken


user> (time-limit (do (dotimes [_ 10] (timeout) (work)) "done") 10)
["done" 6808.941]

user> (time-limit (do (dotimes [_ 10] (timeout) (work)) "done") 5)
:timeout

; time-limit runs the first form for at most x seconds, returning the
result of get-time-pair
; if the run completed, and otherwise kills the execution of the form
and returns :timeout.
; This is implemented by running your form in a separate Future
thread.
; If your worker doesn't do any blocking IO, it should call "timeout"
periodically as you see here
; (which is fairly low-overhead). It seems impossible to get around
this limitation.


user> (time-and-memory-limit (do (dotimes [_ 10] (timeout) (work))
"done") 10 100)
["done" 6283.163]
user> (time-and-memory-limit (do (dotimes [_ 10] (timeout) (work))
"done") 10 5)
:memout
user> (time-and-memory-limit (do (dotimes [_ 10] (timeout) (work))
"done") 5 100)
:timeout

; time-and-memory-limit is like time-limit, but also imposes a heap
growth limitation (in MB).
; Memory instrumenting is tricky; the method I use is not perfect, but
should give reasonable
; numbers as long as you're not getting close to the limit (in which
case forced GCs will slow
; things down).


user> (time-and-memory-instrument (do (dotimes [_ 10] (timeout)
(work)) "done") 10 100)
["done" 6379.433 8.624679565429688]

; time-and-memory-instrument is like time-and-memory-limit, but it
also returns the max
; heap size growth (in MB). This may affect timing in a somewhat
unpredictable fashion,
; and the numbers are somewhat questionable, but it at least gives you
an idea how much
; memory your code is using.

My current code is posted here, if you're interested how it works.

http://paste.lisp.org/display/76181

Comments and suggestions welcome.

Cheers,
Jason
Reply all
Reply to author
Forward
0 new messages