I took a look at the bytecode of what was generated using no.disassemble (wrapping parts of the test code into defn's to disassemble it). I saw a couple of things going on, but I'm not sure exactly what it all means as I'm not super familiar with when Hotspot does method inlining. Maybe someone else with more experience can help here. :)
1. The first is that when you're calling vreset!/reset! and deref, you're actually doing two function calls to get and set values. (i.e. you call vreset! and vreset! calls .reset, vs. calling .reset directly as in the last example by Timothy). 2. The code when calling a function like reset! and vreset! generates invokeinterface calls. You can get invokevirtual calls to be generated using something like: (.invoke ^AFn vreset! v (.invoke ^AFn deref v)) which is pretty hideous, but works to get a call to AFn.invoke() instead of IFn.invoke(). However, that didn't change the speed of things here at all. I don't know if that affects method inlining by Hotspot. I would guess what's happening is that you're getting the overhead of the extra function call going through vreset! and reset!, rather than going directly to .reset (and again for @ and .deref; note the deref clojure function also has some extra logic for instance checking that would also add more processing). When running the 10000000 loop here (Macbook Pro 2011, Core i7), I get: (vreset! v @v) "Elapsed time: 2456.604192 msecs" (vreset! v (.deref v)) "Elapsed time: 1124.21792 msecs" (.reset v (.deref v)) "Elapsed time: 829.400429 msecs" The 2nd result above show a big difference, and I imagine that's probably due to not having to do the (instance? clojure.lang.IDeref ref) that's in the deref function. The 3rd one compared to the 2nd I think would be the difference from just the extra function call (assuming no method inlining has happened). On Wednesday, March 11, 2015 at 2:08:49 PM UTC-4, Brent Millare wrote: > > Good catch. With criterium, I can detect the small performance improvement. > > volatile: Evaluation count : 7550019420 in 60 samples of 125833657 calls. > Execution time mean : 6.345042 ns > Execution time std-deviation : 0.126086 ns > Execution time lower quantile : 6.223058 ns ( 2.5%) > Execution time upper quantile : 6.525868 ns (97.5%) > Overhead used : 1.651549 ns > AtomicLong: Evaluation count : 6925392540 in 60 samples of 115423209 calls. > Execution time mean : 7.156855 ns > Execution time std-deviation : 0.136142 ns > Execution time lower quantile : 7.010743 ns ( 2.5%) > Execution time upper quantile : 7.362120 ns (97.5%) > Overhead used : 1.651549 ns > AtomicReference: Evaluation count : 6014401080 in 60 samples of 100240018 > calls. > Execution time mean : 8.342217 ns > Execution time std-deviation : 0.126856 ns > Execution time lower quantile : 8.129171 ns ( 2.5%) > Execution time upper quantile : 8.511877 ns (97.5%) > Overhead used : 1.651549 ns > > > On Wednesday, March 11, 2015 at 1:50:37 PM UTC-4, tbc++ wrote: >> >> Actaully I think it comes down to the use of the rather generic Deref. I >> fired up a repl and ran the following >> >> (let [v (clojure.lang.Volatile. {})] >> (dotimes [x ...] >> (.reset v (.deref v)))) >> >> I'm seeing very similar times to the one for the AtomicReference. >> >> Timothy >> >> On Wed, Mar 11, 2015 at 11:08 AM, Brent Millare <brent....@gmail.com> >> wrote: >> >>> I find it hard to believe GC would be a factor since there is very >>> little being generated here. Also, while the outside loop is only 10 >>> iterations of timings, in the inside loops the code is called for 100 >>> million iterations. Anyways, running it with criterium didn't change the >>> ranking. >>> >>> Here is the output: >>> volatile: WARNING: Final GC required 1.149417308725186 % of runtime >>> Evaluation count : 4156079100 in 60 samples of 69267985 calls. >>> Execution time mean : 12.975339 ns >>> Execution time std-deviation : 0.188921 ns >>> Execution time lower quantile : 12.823222 ns ( 2.5%) >>> Execution time upper quantile : 13.272950 ns (97.5%) >>> Overhead used : 1.613416 ns >>> AtomicLong: Evaluation count : 6921767160 in 60 samples of 115362786 >>> calls. >>> Execution time mean : 7.155989 ns >>> Execution time std-deviation : 0.124147 ns >>> Execution time lower quantile : 7.048738 ns ( 2.5%) >>> Execution time upper quantile : 7.330448 ns (97.5%) >>> Overhead used : 1.613416 ns >>> AtomicReference: Evaluation count : 5814704460 in 60 samples of >>> 96911741 calls. >>> Execution time mean : 8.791224 ns >>> Execution time std-deviation : 0.185229 ns >>> Execution time lower quantile : 8.564921 ns ( 2.5%) >>> Execution time upper quantile : 9.340265 ns (97.5%) >>> Overhead used : 1.613416 ns >>> >>> Found 4 outliers in 60 samples (6.6667 %) >>> low-severe 2 (3.3333 %) >>> low-mild 2 (3.3333 %) >>> Variance from outliers : 9.4134 % Variance is slightly inflated by >>> outliers >>> atom: Evaluation count : 4038207840 in 60 samples of 67303464 calls. >>> Execution time mean : 13.007604 ns >>> Execution time std-deviation : 0.202285 ns >>> Execution time lower quantile : 12.819268 ns ( 2.5%) >>> Execution time upper quantile : 13.275983 ns (97.5%) >>> Overhead used : 1.613416 ns >>> >>> Note: I bench the get/set expression, not the creation of the >>> volatile/atomic*/atom >>> >>> eg. >>> (let [v (volatile! 1)] >>> (c/bench (vreset! v @v))) >>> >>> On Wednesday, March 11, 2015 at 12:30:06 PM UTC-4, tbc++ wrote: >>>> >>>> There's many other factors involved here though, GC, JIT warmup, etc. >>>> That's kindof what criterium helps out with, removing all the variables >>>> and >>>> running something until the JIT has warmed up enough (10 iterations >>>> probably isn't enough). >>>> >>>> Timothy >>>> >>>> >>>> -- >>> 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/d/optout. >>> >> >> >> >> -- >> “One of the main causes of the fall of the Roman Empire was that–lacking >> zero–they had no way to indicate successful termination of their C >> programs.” >> (Robert Firth) >> > -- 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/d/optout.