Thanks Tim for leading me to this thread.

On Friday, August 26, 2016 at 11:06:33 AM UTC-3, Kevin Liu wrote:
>
> Nice video recommendation, Yichao. Thanks.
>
> On Saturday, April 2, 2016 at 1:16:07 PM UTC-3, Yichao Yu wrote:
>>
>> On Sat, Apr 2, 2016 at 10:26 AM, Cedric St-Jean <cedric...@gmail.com> 
>> wrote: 
>> > 
>> >> Therefore there's no way the compiler can rewrite the slow version to 
>> the 
>> >> fast version. 
>> > 
>> > 
>> > It knows that the element type is a Feature, so it could produce: 
>> > 
>> > if isa(features[i], A) 
>> >     retval += evaluate(features[i]::A) 
>> > elseif isa(features[i], B) 
>> >     retval += evaluate(features[i]::B) 
>> > else 
>> >     retval += evaluate(features[i]) 
>> > end 
>>
>> This is kind of the optimization I mentioned but no this will still be 
>> much slower than the other version. 
>> The compiler has no idea what the return type of the third one so this 
>> version is still type unstable and you get dynamic dispatch at every 
>> iteration for the floating point add. Of course there's more 
>> sophisticated transformation that can keep you in the fast path as 
>> long as possible and create extra code to check and handle the slow 
>> cases but it will still be slower. 
>>
>> I also recommand Jeff's talk[1] for a better explaination of the general 
>> idea. 
>>
>> [1] https://www.youtube.com/watch?v=cjzcYM9YhwA 
>>
>> > 
>> > and it would make sense for abstract types that have few subtypes. I 
>> didn't 
>> > realize that dispatch was an order of magnitude slower than type 
>> checking. 
>> > It's easy enough to write a macro generating this expansion, too. 
>> > 
>> > On Saturday, April 2, 2016 at 2:05:20 AM UTC-4, Yichao Yu wrote: 
>> >> 
>> >> On Fri, Apr 1, 2016 at 9:56 PM, Tim Wheeler <timwheel...@gmail.com> 
>> wrote: 
>> >> > Hello Julia Users. 
>> >> > 
>> >> > I ran into a weird slowdown issue and reproduced a minimal working 
>> >> > example. 
>> >> > Maybe someone can help shed some light. 
>> >> > 
>> >> > abstract Feature 
>> >> > 
>> >> > type A <: Feature end 
>> >> > evaluate(f::A) = 1.0 
>> >> > 
>> >> > type B <: Feature end 
>> >> > evaluate(f::B) = 0.0 
>> >> > 
>> >> > function slow(features::Vector{Feature}) 
>> >> >     retval = 0.0 
>> >> >     for i in 1 : length(features) 
>> >> >         retval += evaluate(features[i]) 
>> >> >     end 
>> >> >     retval 
>> >> > end 
>> >> > 
>> >> > function fast(features::Vector{Feature}) 
>> >> >     retval = 0.0 
>> >> >     for i in 1 : length(features) 
>> >> >         if isa(features[i], A) 
>> >> >             retval += evaluate(features[i]::A) 
>> >> >         else 
>> >> >             retval += evaluate(features[i]::B) 
>> >> >         end 
>> >> >     end 
>> >> >     retval 
>> >> > end 
>> >> > 
>> >> > using ProfileView 
>> >> > 
>> >> > features = Feature[] 
>> >> > for i in 1 : 10000 
>> >> >     push!(features, A()) 
>> >> > end 
>> >> > 
>> >> > slow(features) 
>> >> > @time slow(features) 
>> >> > fast(features) 
>> >> > @time fast(features) 
>> >> > 
>> >> > The output is: 
>> >> > 
>> >> > 0.000136 seconds (10.15 k allocations: 166.417 KB) 
>> >> > 0.000012 seconds (5 allocations: 176 bytes) 
>> >> > 
>> >> > 
>> >> > This is a HUGE difference! Am I missing something big? Is there a 
>> good 
>> >> > way 
>> >> > to inspect code to figure out where I am going wrong? 
>> >> 
>> >> This is because of type instability as you will find in the 
>> performance 
>> >> tips. 
>> >> Note that slow and fast are not equivalent since the fast version only 
>> >> accept `A` or `B` but the slow version accepts any subtype of feature 
>> >> that you may ever define. Therefore there's no way the compiler can 
>> >> rewrite the slow version to the fast version. 
>> >> There are optimizations that can be applied to bring down the gap but 
>> >> there'll always be a large difference between the two. 
>> >> 
>> >> > 
>> >> > 
>> >> > Thank you in advance for any guidance. 
>> >> > 
>> >> > 
>> >> > -Tim 
>> >> > 
>> >> > 
>> >> > 
>> >> > 
>> >> > 
>>
>

Reply via email to