A Clojure library for profiling.
Latest commit d133364 Nov 18, 2014 @edw edw fix var stats table printout
Failed to load latest commit information.
LICENSE initial commit Nov 6, 2014
README.md fix markdown syntax Nov 18, 2014



A Clojure library for profiling.


This library is available on Clojars; here is the Leiningen dependency for the most recently released version:

Clojars Project

If you use CIDER in Emacs, check out nrepl-profile, a project that provides nREPL middleware that takes advantage of this project. (The Emacs portions of the nrepl-profile are available in MELPA as cider-profile.


The goal of this project is to work toward integration into CIDER, the Clojure IDE for Emacs. The stats collected are the as follows:

  • :n Number of samples.
  • :sum Aggregate time spent in fn.
  • :q1 First quartile i.e. twenty-fifth percentile.
  • :med Median i.e. fiftieth percentile.
  • :q3 Third quartile i.e. seventy-fifth percentile.
  • :sd Standard deviation i.e. the square root of the sum of squares of differences from the mean.
  • :mad Mean average deviation, I don't feel like looking up the definition just now.

Full API documentation is available.

After writing profile, I was puttering around CrossClj, I came across Stuart Sierra's circa 2009 core.contrib.profile library. He made some different decisions than I did in his implementation, notably:

  • Sierra's library is written to reduce to a nop unless an earmuffed var evaluates to true. This library always incurs profiling overhead for any profiled var.

  • Sierra's library does not keep sample data but instead reduces the incoming sample data with each traced invocation. This library does, so that it can compute mean average deviation on an optionally rolling sample of the most recent invocations for a given var.

  • Sierra's library allows arbitrary bodies of code to be profiled. This library only profiles functions bound to vars.

These differences are due in large part because thunknyc/profile is intended to be used interactively in an IDE. Also, its API is modelled on clojure.org/tools.trace, which focuses on tracing (and un-tracing) vars.

People have mentioned Criterium. Criterium looks great! Definitely use it if it works for you. That said, it doesn't work well for non-idempotent, non-referentially transparent profiling. I wrote this library primarily to assist in understanding the performance characteristics of code that is highly dependent on interactions outside the JVM, for example due to HTTP requests, database queries, sending pub-sub messages, things like those.


(require '[profile.core :refer :all])
(defn my-add [a b] (+ a b))
(defn my-mult [a b] (* a b))

(profile-vars my-add my-mult)

(profile {}
 (my-add (my-mult (rand-int 100000) (rand-int 1000000))
         (my-mult (rand-int 100000) (rand-int 1000000))))

profile prints output to *err* using pprint/print-table; it looks like this:

|          :name | :n | :sum | :q1 | :med | :q3 | :sd | :mad |
|  #'user/my-add |  1 |  2µs | 2µs |  2µs | 2µs | 0µs |  0µs |
| #'user/my-mult |  2 | 11µs | 3µs |  8µs | 3µs | 3µs |  5µs |

|    :stat | :value |
| :agg-sum |   13µs |


Copyright © 2014 Edwin Watkeys

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.