Huh, interesting. I have:
(defn foo' [x] (if (> x 0) (inc x) (let [res (locking o (dec x))] res))) (defn foo'' [x] (if (> x 0) (inc x) (locking o (dec x)))) foo' is fast, but foo'' is slow. So something about wrapping the locking clause in a let makes it fast. Still no idea why. On Sunday, November 3, 2013 9:30:45 AM UTC-8, Michał Marczyk wrote: > > 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...@gmail.com <javascript:>> > 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 clo...@googlegroups.com<javascript:> > > Note that posts from new members are moderated - please be patient with > your > > first post. > > To unsubscribe from this group, send email to > > clojure+u...@googlegroups.com <javascript:> > > 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+u...@googlegroups.com <javascript:>. > > 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.