Mercurial > lasercutter
diff src/clojure/contrib/profile.clj @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/profile.clj Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,110 @@ 1.4 +;;; profile.clj: simple code profiling & timing 1.5 + 1.6 +;; by Stuart Sierra, http://stuartsierra.com/ 1.7 +;; May 9, 2009 1.8 + 1.9 +;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use 1.10 +;; and distribution terms for this software are covered by the Eclipse 1.11 +;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.12 +;; which can be found in the file epl-v10.html at the root of this 1.13 +;; distribution. By using this software in any fashion, you are 1.14 +;; agreeing to be bound by the terms of this license. You must not 1.15 +;; remove this notice, or any other, from this software. 1.16 + 1.17 + 1.18 +(ns ^{:author "Stuart Sierra" 1.19 + :doc "Simple code profiling & timing measurement. 1.20 + 1.21 +Wrap any section of code in the prof macro, giving it a name, like this: 1.22 + 1.23 + (defn my-function [x y] 1.24 + (let [sum (prof :addition (+ x y)) 1.25 + product (prof :multiplication (* x y))] 1.26 + [sum product])) 1.27 + 1.28 +The run your code in the profile macro, like this: 1.29 + 1.30 + (profile (dotimes [i 10000] (my-function 3 4))) 1.31 + 1.32 +Which prints a report for each named section of code: 1.33 + 1.34 + Name mean min max count sum 1.35 + addition 265 0 37000 10000 2655000 1.36 +multiplication 274 0 53000 10000 2747000 1.37 + 1.38 +Times are measured in nanoseconds, to the maximum precision available 1.39 +under the JVM. See the function documentation for more details. 1.40 +"} 1.41 + clojure.contrib.profile) 1.42 + 1.43 +(def *profile-data* nil) 1.44 + 1.45 +(def ^{:doc "Set this to false before loading/compiling to omit 1.46 +profiling code."} *enable-profiling* true) 1.47 + 1.48 +(defmacro prof 1.49 + "If *enable-profiling* is true, wraps body in profiling code. 1.50 + Returns the result of body. Profile timings will be stored in 1.51 + *profile-data* using name, which must be a keyword, as the key. 1.52 + Timings are measured with System/nanoTime." 1.53 + [name & body] 1.54 + (assert (keyword? name)) 1.55 + (if *enable-profiling* 1.56 + `(if *profile-data* 1.57 + (let [start-time# (System/nanoTime) 1.58 + value# (do ~@body) 1.59 + elapsed# (- (System/nanoTime) start-time#)] 1.60 + (swap! *profile-data* assoc ~name 1.61 + (conj (get @*profile-data* ~name) elapsed#)) 1.62 + value#) 1.63 + ~@body) 1.64 + `(do ~@body))) 1.65 + 1.66 +(defmacro with-profile-data 1.67 + "Executes body with *profile-data* bound to an atom of a new map. 1.68 + Returns the raw profile data as a map. Keys in the map are profile 1.69 + names (keywords), and values are lists of elapsed time, in 1.70 + nanoseconds." 1.71 + [& body] 1.72 + `(binding [*profile-data* (atom {})] 1.73 + ~@body 1.74 + @*profile-data*)) 1.75 + 1.76 +(defn summarize 1.77 + "Takes the raw data returned by with-profile-data and returns a map 1.78 + from names to summary statistics. Each value in the map will look 1.79 + like: 1.80 + 1.81 + {:mean ..., :min ..., :max ..., :count ..., :sum ...} 1.82 + 1.83 + :mean, :min, and :max are how long the profiled section took to run, 1.84 + in nanoseconds. :count is the total number of times the profiled 1.85 + section was executed. :sum is the total amount of time spent in the 1.86 + profiled section, in nanoseconds." 1.87 + [profile-data] 1.88 + (reduce (fn [m [k v]] 1.89 + (let [cnt (count v) 1.90 + sum (reduce + v)] 1.91 + (assoc m k {:mean (int (/ sum cnt)) 1.92 + :min (apply min v) 1.93 + :max (apply max v) 1.94 + :count cnt 1.95 + :sum sum}))) 1.96 + {} profile-data)) 1.97 + 1.98 +(defn print-summary 1.99 + "Prints a table of the results returned by summarize." 1.100 + [profile-summary] 1.101 + (let [name-width (apply max 1 (map (comp count name) (keys profile-summary))) 1.102 + fmt-string (str "%" name-width "s %8d %8d %8d %8d %8d%n")] 1.103 + (printf (.replace fmt-string \d \s) 1.104 + "Name" "mean" "min" "max" "count" "sum") 1.105 + (doseq [k (sort (keys profile-summary))] 1.106 + (let [v (get profile-summary k)] 1.107 + (printf fmt-string (name k) (:mean v) (:min v) (:max v) (:count v) (:sum v)))))) 1.108 + 1.109 +(defmacro profile 1.110 + "Runs body with profiling enabled, then prints a summary of 1.111 + results. Returns nil." 1.112 + [& body] 1.113 + `(print-summary (summarize (with-profile-data (do ~@body)))))