I mean, I'm probably being naive, but this suggests that one could write

(defmacro locking' [& forms]
  `(let [res# (locking ~@forms)] res#))

and use locking' in place of locking for improved performance. Is this
wrong? If it's right, does that suggest the macro in clojure.core should be
changed?


On Sun, Nov 3, 2013 at 11:09 AM, Michael Blume <blume.m...@gmail.com> wrote:

> 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> 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
>> > 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
>> > 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.
>> > 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 a topic in the
> Google Groups "Clojure" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/d/topic/clojure/x86VygZYf4Y/unsubscribe.
> To unsubscribe from this group and all its topics, 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