dude..
dictZ = Dict{Int, Int}()
for z = 1:1000
dictZ[z] = z
end
function testNoFunCopy()
for z = 1:1000
function2.z = dictZ[z]
# do whatever with function2, including making a copy
end
end
@code_llvm testNoFunCopy()
@code_native testNoFunCopy()
@time testNoFunCopy()
# Test to see if multiple functions are created. They are.
# We would only need to create a single function if we used julia anon, but
its time inefficient.
dict = Dict{Int, Any}()
for z = 1:1000
function2 = @anon c -> (c + z)
dict[z] = function2
end
a = 1
b = 2
function testWithFunCopy()
for z = 1:1000
function1(a,b, dict[z])
end
end
@code_llvm testWithFunCopy()
@code_native testWithFunCopy()
@time testWithFunCopy()
For 1000 elements:
0.00019s vs 0.035s respectively
Thanks!
Is the reason the faster code has more allocations bc it is
inserting vars into the single function? (Opposed to the slower
code already having its vars filled in.)
On Friday, January 22, 2016 at 12:23:59 PM UTC-5, Tim Holy wrote:
>
> Just use
>
> z = 1
> function2 = @anon c -> c + z
> for z = 1:100
> function2.z = z
> # do whatever with function2, including making a copy
> end
>
> --Tim
>
> On Friday, January 22, 2016 08:55:25 AM Cedric St-Jean wrote:
> > (non-mutating) Closures and FastAnonymous work essentially the same way.
> > They store the data that is closed over (more or less) and a function
> > pointer. The thing is that there's only one data structure in Julia for
> all
> > regular anonymous functions, whereas FastAnonymous creates one per @anon
> > site. Because the FastAnonymous-created datatype is specific to that
> > function definition, the standard Julia machinery takes over and
> produces
> > efficient code. It's just as good as if the function had been defined
> > normally with `function foo(...) ... end`
> >
> >
> > for z = 1:100
> > function2 = @anon c -> (c + z)
> >
> > dict[z] = function2
> > end
> >
> >
> > So we end up creating multiple functions for each z value.
> >
> >
> > In this code, whether you use @anon or not, Julia will create 100 object
> > instances to store the z values.
> >
> > The speed difference between the two will soon be gone.
> > <https://github.com/JuliaLang/julia/pull/13412>
> >
> > Cédric
> >
> > On Friday, January 22, 2016 at 11:31:36 AM UTC-5, Bryan Rivera wrote:
> > > I have to do some investigating here. I thought we could do something
> > > like that but wasn't quite sure how it would look.
> > >
> > > Check this out:
> > >
> > > This code using FastAnonymous optimizes to the very same code below it
> > > where functions have been manually injected:
> > >
> > > using FastAnonymous
> > >
> > >
> > > function function1(a, b, function2)
> > >
> > > if(a > b)
> > >
> > > c = a + b
> > > return function2(c)
> > >
> > > else
> > >
> > > # do anything
> > > # but return nothing
> > >
> > > end
> > >
> > > end
> > >
> > >
> > > z = 10
> > > function2 = @anon c -> (c + z)
> > >
> > >
> > > a = 1
> > > b = 2
> > > @code_llvm function1(a, b, function2)
> > > @code_native function1(a, b, function2)
> > >
> > > Manually unrolled equivalent:
> > >
> > > function function1(a, b, z)
> > >
> > > if(a > b)
> > >
> > > c = a + b
> > > return function2(c, z)
> > >
> > > else
> > >
> > > # do anything
> > > # but return nothing
> > >
> > > end
> > >
> > > end
> > >
> > >
> > > function function2(c, z)
> > >
> > > return c + z
> > >
> > > end
> > >
> > >
> > > a = 1
> > > b = 2
> > > z = 10
> > >
> > >
> > > @code_llvm function1(a, b, z)
> > >
> > > @code_native function1(a, b, z)
> > >
> > > However, this is a bit too simplistic. My program actually does this:
> > >
> > > # Test to see if multiple functions are created. They are.
> > > # We would only need to create a single function if we used julia
> anon,
> > > but its time inefficient.
> > >
> > > dict = Dict{Int, Any}()
> > > for z = 1:100
> > >
> > > function2 = @anon c -> (c + z)
> > >
> > > dict[z] = function2
> > >
> > > end
> > >
> > >
> > > a = 1
> > > b = 2
> > >
> > > function test()
> > >
> > > function1(a,b, dict[100])
> > > function1(a,b, dict[50])
> > >
> > > end
> > >
> > > @code_llvm test()
> > > @code_native test()
> > >
> > >
> > >
> > > So we end up creating multiple functions for each z value. We could
> use
> > > Julia's anon funs, which would only create a single function, however
> > > these
> > > lamdas are less performant than FastAnon.
> > >
> > > So its a space vs time tradeoff, I want the speed of FastAnon, without
> the
> > > spacial overhead of storing multiple functions.
> > >
> > > Can we be greedy? :)
> > >
> > > On Thursday, January 21, 2016 at 9:56:51 PM UTC-5, Cedric St-Jean
> wrote:
> > >> Something like this?
> > >>
> > >> function function1(a, b, f) # Variable needed in callback fun
> injected.
> > >>
> > >> if(a > b)
> > >>
> > >> c = a + b
> > >> res = f(c) # Callback function has been injected.
> > >> return res + 1
> > >>
> > >> else
> > >>
> > >> # do anything
> > >> # but return nothing
> > >>
> > >> end
> > >>
> > >> end
> > >>
> > >> type SomeCallBack
> > >>
> > >> z::Int
> > >>
> > >> end
> > >> Base.call(callback::SomeCallBack, c) = c + callback.z
> > >>
> > >> function1(2, 1, SomeCallBack(10))
> > >>
> > >> Because of JIT, this is 100% equivalent to your "callback function
> has
> > >> been injected" example, performance-wise. My feeling is that .call
> > >> overloading is not to be abused in Julia, so I would favor using a
> > >> regular
> > >> function call with a descriptive name instead of call overloading,
> but
> > >> the
> > >> same performance guarantees apply. Does that answer your question?
> > >>
> > >> On Thursday, January 21, 2016 at 9:02:50 PM UTC-5, Bryan Rivera
> wrote:
> > >>> I think what I wrote above might be too complicated, as it is an
> attempt
> > >>> to solve this problem.
> > >>>
> > >>> In essence this is what I want:
> > >>>
> > >>>
> > >>> # wasmerged, _, _, _ = elide_pairwise!(ttree1, ttree2, canmerge;
> nbrs=idbgv)
>
> > >>> function function1(a, b, onGreaterThanCallback)
> > >>>
> > >>> if(a > b)
> > >>>
> > >>> c = a + b
> > >>> res = onGreaterThanCallback(c, z)
> > >>> return res + 1
> > >>>
> > >>> else
> > >>>
> > >>> # do anything
> > >>> # but return nothing
> > >>>
> > >>> end
> > >>>
> > >>> end
> > >>>
> > >>>
> > >>> global onGreaterThanCallback = (c) -> c + z
> > >>>
> > >>> function1(a, b, onGreaterThanCallback)
> > >>>
> > >>>
> > >>> Problems:
> > >>>
> > >>> The global variable.
> > >>>
> > >>> The anonymous function which has performance impact (vs other
> > >>> approaches). We could use Tim Holy's @anon, but then the value of
> `z`
> > >>> is
> > >>> fixed at function definition, which we don't always want.
> > >>>
> > >>> I think that the ideal optimization would look like this:
> > >>> function function1(a, b, z) # Variable needed in callback fun
> > >>>
> > >>> injected.
> > >>>
> > >>> if(a > b)
> > >>>
> > >>> c = a + b
> > >>> res = c + z # Callback function has been injected.
> > >>> return res + 1
> > >>>
> > >>> else
> > >>>
> > >>> # do anything
> > >>> # but return nothing
> > >>>
> > >>> end
> > >>>
> > >>> end
> > >>>
> > >>>
> > >>> function1(a, b, z)
> > >>>
> > >>> In OO languages we would be using an abstract class or its
> equivalent.
> > >>>
> > >>> But I've thought about it, and read the discussions on interfaces,
> and
> > >>>
> > >>> don't see those solutions optimizing the code out like I did above.
> > >>>
> > >>> Any ideas?
>
>