Thank you for the comments. In my original code it means the difference between a 30 min execution with memory allocation in the Gigabytes and a few seconds of execution with only 800 bytes using the second version. I thought under-the-hood Julia basically runs those if statements anyway for its dispatch, and don't know why it needs to allocate any memory. Having the if-statement workaround will be fine though.
On Saturday, April 2, 2016 at 7:26:11 AM UTC-7, Cedric St-Jean 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 > > 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 <[email protected]> >> 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 >> > >> > >> > >> > >> > >> >
