You have a typo in foo -- monitor-exit's argument is 0 (zero) rather than o (the sentinel object).
Besides that, in foo both monitor-enter and monitor-exit get their arguments from a Var. Rewriting to use locking, which first puts the object whose monitor will be used in a local (that is, (let [lockee o] ...), where ... performs the locking using the newly introduced local), gives timings identical to those of bar and baz: (defn foo' [x] (if (> x 0) (inc x) (let [res (locking o (dec x))] res))) So this is one reason not to use monitor-enter and monitor-exit directly. Another reason is that locking guarantees that the monitor will be released (by using try / finally, and of course by preventing situations where the matching monitor-enter & monitor-exit operate on different objects). In fact, both monitor-enter and monitor-exit carry docstrings which explicitly say that they should not be used in user code and point to locking as the user-facing equivalent to Java's synchronized. Cheers, Michał On 1 November 2013 19:34, Michael Blume <blume.m...@gmail.com> wrote: > https://github.com/MichaelBlume/perf-test > > (ns perf-test > (:use (criterium core)) > (:gen-class)) > > (def o (Object.)) > > (defn foo [x] > (if (> x 0) > (inc x) > (do > (monitor-enter o) > (let [res (dec x)] > (monitor-exit 0) > res)))) > > (defn bar [x] > (if (> x 0) > (inc x) > (dec x))) > > (defn locking-part [x l] > (monitor-enter l) > (let [res (dec x)] > (monitor-exit l) > res)) > > (defn baz [x] > (if (> x 0) > (inc x) > (locking-part x o))) > > (defn -main [] > (println "benching foo") > (bench (foo 5) :verbose) > (println "benching bar") > (bench (bar 5) :verbose) > (println "benching baz") > (bench (baz 5) :verbose) > (println "done benching")) > > > > I'm only ever calling these functions with positive values, so the > monitor-enter branch should never be entered. Nevertheless, the performance > of foo is much worse than bar or baz. > > The best guess I've got is that the fact that lock-taking is involved > somehow changes how the function is compiled, somehow making the function > slower. If the practical upshot is that I shouldn't write functions that > only sometimes lock -- that the locking part of a function should always be > its own function -- then I can do that, but I'm curious why. > > $ lein uberjar > Compiling perf-test > Created /Users/mike/perf-test/target/perf-test-0.1.0-SNAPSHOT.jar > Created /Users/mike/perf-test/target/perf-test-0.1.0-SNAPSHOT-standalone.jar > $ java -jar -server target/perf-test-0.1.0-SNAPSHOT-standalone.jar > benching foo > WARNING: Final GC required 1.5974571326266802 % of runtime > x86_64 Mac OS X 10.8.3 4 cpu(s) > Java HotSpot(TM) 64-Bit Server VM 24.0-b28 > Runtime arguments: > Evaluation count : 391582560 in 60 samples of 6526376 calls. > Execution time sample mean : 167.426696 ns > Execution time mean : 167.459429 ns > Execution time sample std-deviation : 4.079466 ns > Execution time std-deviation : 4.097819 ns > Execution time lower quantile : 160.742869 ns ( 2.5%) > Execution time upper quantile : 175.453376 ns (97.5%) > Overhead used : 1.634996 ns > > Found 2 outliers in 60 samples (3.3333 %) > low-severe 2 (3.3333 %) > Variance from outliers : 12.5602 % Variance is moderately inflated by > outliers > benching bar > x86_64 Mac OS X 10.8.3 4 cpu(s) > Java HotSpot(TM) 64-Bit Server VM 24.0-b28 > Runtime arguments: > Evaluation count : 2174037300 in 60 samples of 36233955 calls. > Execution time sample mean : 26.068923 ns > Execution time mean : 26.066422 ns > Execution time sample std-deviation : 0.887937 ns > Execution time std-deviation : 0.916861 ns > Execution time lower quantile : 23.996763 ns ( 2.5%) > Execution time upper quantile : 27.911936 ns (97.5%) > Overhead used : 1.634996 ns > > Found 3 outliers in 60 samples (5.0000 %) > low-severe 1 (1.6667 %) > low-mild 1 (1.6667 %) > high-mild 1 (1.6667 %) > Variance from outliers : 22.1874 % Variance is moderately inflated by > outliers > benching baz > x86_64 Mac OS X 10.8.3 4 cpu(s) > Java HotSpot(TM) 64-Bit Server VM 24.0-b28 > Runtime arguments: > Evaluation count : 2270676660 in 60 samples of 37844611 calls. > Execution time sample mean : 25.834142 ns > Execution time mean : 25.837429 ns > Execution time sample std-deviation : 0.718382 ns > Execution time std-deviation : 0.729431 ns > Execution time lower quantile : 24.837925 ns ( 2.5%) > Execution time upper quantile : 27.595781 ns (97.5%) > Overhead used : 1.634996 ns > > Found 4 outliers in 60 samples (6.6667 %) > low-severe 2 (3.3333 %) > low-mild 2 (3.3333 %) > Variance from outliers : 15.7591 % Variance is moderately inflated by > outliers > done benching > > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with your > first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.