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.

Reply via email to