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.

Reply via email to