Sorry, I neglected to include a link to the ticket: http://dev.clojure.org/jira/browse/CLJ-1296
On Sun, Nov 17, 2013 at 2:11 PM, Andy Fingerhut <andy.finger...@gmail.com>wrote: > I have just created a ticket linking to this discussion, with a copy of > one of Michal's earlier messages in the thread as a description of what > might be the problem. > > I would not say that this is the same as movement on this issue. Movement > in the form that would lead to a change in the Clojure compiler will > require one or more volunteers to carefully diagnose the root cause of the > problem, develop one or more patches, respond to comments from screeners > and/or Rich Hickey, etc. If people want to raise more attention to this > issue, one way to do it is to vote on the ticket in JIRA. If you do not > already have an account, you can create one here: > > http://dev.clojure.org/jira/secure/Signup!default.jspa > > Andy > > > On Sun, Nov 17, 2013 at 10:14 AM, Michael Blume <blume.m...@gmail.com>wrote: > >> Sorry to be a bother, but any movement on this? This looks like a real >> performance bug and I don't yet have the internals knowledge to chase it >> down myself. >> >> >> On Sun, Nov 3, 2013 at 12:10 PM, Michał Marczyk <michal.marc...@gmail.com >> > wrote: >> >>> Well, that is interesting. >>> >>> The difference between the compiled versions of >>> >>> (defn foo [x] >>> (if (> x 0) >>> (inc x) >>> (locking o >>> (dec x)))) >>> >>> and >>> >>> (defn bar [x] >>> (if (> x 0) >>> (inc x) >>> (let [res (locking o >>> (dec x))] >>> res))) >>> >>> is quite significant. foo gets compiled to a single class, with >>> invocations handled by a single invoke method; bar gets compiled to a >>> class for bar + an extra class for an inner function which handles the >>> (locking o (dec x)) part -- probably very similar to the output for >>> the version with the hand-coded locking-part (although I haven't >>> really looked at that yet). The inner function is a closure, so >>> calling it involves an allocation of a closure object; its ctor >>> receives the closed-over locals as arguments and stores them in two >>> fields (lockee and x). Then they get loaded from the fields in the >>> body of the closure's invoke method etc. >>> >>> I guess I'll have to play around with Java equivalents too... >>> >>> Cheers, >>> Michał >>> >>> >>> On 3 November 2013 20:46, Michael Blume <blume.m...@gmail.com> wrote: >>> > 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. >>> >>> -- >>> -- >>> 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. >> > > -- -- 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.