# Why do these two similar functions lead to different timings?

**URL:** <https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621>\
**Category:** New to Julia\
**Created:** [November 16, 2018, 10:04pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621 "2018-11-16T22:04:57Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![DrPapa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drpapa/32/6835_2.png) [@DrPapa](https://discourse.julialang.org/u/DrPapa)\
**Post date:** [November 16, 2018, 10:04pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/1 "2018-11-16T22:04:57Z")

</div>

I am in the process of porting over some Matlab code that implements the Vector Field Navigation approached outline in [Goncalves et al. 2010](http://www.cpdee.ufmg.br/~gpereira/papers/tro2010.pdf) leveraging AD. The code is working properly, but I am confused why two seemingly equivalent implementations results in significantly different timings and # of allocations.

`VF_grad()`, takes function gradients as its arguments, while `VF_func()` takes the original function and then determines the gradients.

```julia
using ForwardDiff
using StaticArrays
using LinearAlgebra
using BenchmarkTools

α1(x::AbstractArray) = (x[1]/13.0).^2.0 .+ (x[2]/7.0).^2.0 .- 1.0
α2(x::AbstractArray) = x[3]
V(x::AbstractArray) = -sqrt(α1(x)^2.0 + α2(x)^2.0);

∇α1(x::AbstractArray) = ForwardDiff.gradient(α1,x)
∇α2(x::AbstractArray) = ForwardDiff.gradient(α2,x)
∇V(x::AbstractArray) = ForwardDiff.gradient(V,x);

function VF_grad(x::AbstractArray, ∇α1::Function, ∇α2::Function, ∇V::Function, G::Real=1.0, H::Real=1.0)
    ∇α1x = ∇α1(x)
    ∇α2x = ∇α2(x)
    circ = ∇α1x × ∇α2x
    converge = ∇V(x)

    G*converge + H*circ
end;

function VF_func(x::AbstractArray, α1::Function, α2::Function, V::Function, G::Real=1.0, H::Real=1.0)
    ∇α1x = ForwardDiff.gradient(α1,x)
    ∇α2x = ForwardDiff.gradient(α2,x)
    circ = ∇α1x × ∇α2x
    converge = ForwardDiff.gradient(V,x)

    G*converge + H*circ
end;

## Make Data
eval_array = [SVector(rand(3)...) for i ∈ 1:750];

```

```julia
@btime VF_func.($eval_array, α1, α2, V)
@btime VF_grad.($eval_array, ∇α1, ∇α2, ∇V);

259.922 μs (9004 allocations: 275.58 KiB)
 53.775 μs (4 allocations: 17.77 KiB)

```

Can somebody explain this behavior to me? Both look to be type-stable.

For some reason this behavior seems connected to `×`. Changing `circ = ∇α1x × ∇α2x` to `circ = ∇α1x` leads to

```julia
51.266 μs (4 allocations: 17.77 KiB)
51.253 μs (4 allocations: 17.77 KiB)

```

Also, if I use the original definition of `circ` but modify my return to `G*converge + circ`, i.e. no `H*` I get

```julia
51.489 μs (4 allocations: 17.77 KiB)
51.497 μs (4 allocations: 17.77 KiB)

```

---

<div class="post-metadata">

**Author:** ![jw3126](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jw3126/32/3086_2.png) [@jw3126](https://discourse.julialang.org/u/jw3126)\
**Post date:** [November 16, 2018, 10:18pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/2 "2018-11-16T22:18:26Z")

</div>

I think julia is not fully specializing `VR_func`. You could try to force to specialize on the function arguments like this:

```julia
function VF_func2(x::AbstractArray, α1::F1, α2::F2, V::F3, G::Real=1.0, H::Real=1.0) where {F1,F2,F3}
           ∇α1x = ForwardDiff.gradient(α1,x)
           ∇α2x = ForwardDiff.gradient(α2,x)
           circ = ∇α1x × ∇α2x
           converge = ForwardDiff.gradient(V,x)

           G*converge + H*circ
       end;

```

Note that usually julia does a good job when deciding what to specialize and you usually don’t need to force it.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [November 16, 2018, 10:32pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/3 "2018-11-16T22:32:58Z")

</div>

I think the heuristic is related to whether the function argument is directly called or not in the function body but I don’t know the details.

---

<div class="post-metadata">

**Author:** ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)\
**Post date:** [November 16, 2018, 10:34pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/4 "2018-11-16T22:34:45Z")

</div>

Another approach: return a callable function (since you presumably won’t be changing α1, α2, and V for each x), then call it:  
\*\*\*edit: sped up ~50% by `@inline` annotations

```julia
function VF(α1, α2, V, G=1.0, H=1.0)
    @inline ∇α1(x) = ForwardDiff.gradient(α1,x)
    @inline ∇α2(x) = ForwardDiff.gradient(α2,x)
    @inline converge(x) = ForwardDiff.gradient(V,x)

    x -> G*converge(x) + H*(∇α1(x) × ∇α2(x))
end

```

```julia
@btime VF(α1, α2, V).($eval_array) # 12.693 μs (7 allocations: 17.84 KiB)

```

---

<div class="post-metadata">

**Author:** ![DrPapa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drpapa/32/6835_2.png) [@DrPapa](https://discourse.julialang.org/u/DrPapa)\
**Post date:** [November 19, 2018, 1:59pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/5 "2018-11-19T13:59:44Z")

</div>

@jw3126 This works, but I am having a hard time understanding why. Are `α1`, `α2`, and `V` different subtypes of `Function`? Running `typeof(α1)` seems to indicate that, I get `typeof(α1)` returned.

Because my function requires `α1`, `α2`, and `V` to be callable, would I be best off using something like

`where {F1<:Function,F2<:Function,F3<:Function}`

Or is there a more generic way to limit to types that are “callable”. E.g. These functions should be able to handle custom types like `ODESolution` form `DifferentialEquations.jl` since they are callable, but I expect that they are not subtypes of `Functions`.

@kristoffer.carlsson I think you are probably correct. When I add any combination of

```julia
a = α1(x)
b = α2(x)
c = V(x)

```

to my function, I get reduced timings and # of allocations even though I am increasing the number of operations.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [November 19, 2018, 2:03pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/6 "2018-11-19T14:03:08Z")

</div>

> [@DrPapa](#):
>
> This works, but I am having a hard time understanding why. Are `α1` , `α2` , and `V` different subtypes of `Function` ?

Yes.

> [@DrPapa](#):
>
> Because my function requires `α1` , `α2` , and `V` to be callable, would I be best off using something like
> 
> `where {F1<:Function,F2<:Function,F3<:Function}`

That limits it to `functions` but prevents general callable objects. I would argue it is best to just remove the `<:Function` and do duck typing instead.

---

<div class="post-metadata">

**Author:** ![DrPapa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drpapa/32/6835_2.png) [@DrPapa](https://discourse.julialang.org/u/DrPapa)\
**Post date:** [November 19, 2018, 2:04pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/7 "2018-11-19T14:04:00Z")

</div>

> [@kristoffer.carlsson](#):
>
> do duck typing instead

I’m not sure I know what you mean. Can you elaborate? Does this mean adding logic in my functions based based on `α1` being callable? Something like

`isempty(methods(α1)) `

---

<div class="post-metadata">

**Author:** ![DrPapa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drpapa/32/6835_2.png) [@DrPapa](https://discourse.julialang.org/u/DrPapa)\
**Post date:** [November 19, 2018, 2:11pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/8 "2018-11-19T14:11:52Z")

</div>

> [@stillyslalom](#):
>
> Another approach: return a callable function (since you presumably won’t be changing α1, α2, and V for each x), then call it:  
> \*\*\*edit: sped up ~50% by `@inline` annotations

This works for me too and makes sense. However, I see no speed-up using `@inline` vs. not. I am using Julia v0.7. I thought it was maybe due to different optimization flags but I tried using `-O3`, but saw no change.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [November 19, 2018, 2:20pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/9 "2018-11-19T14:20:22Z")

</div>

> [@DrPapa](#):
>
> I’m not sure I know what you mean. Can you elaborate? Does this mean adding logic in my functions based based on `α1` being callable?

Just assume that the thing passed in is callable and if it isn’t, there will be a runtime error.

---

<div class="post-metadata">

**Author:** ![DrPapa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drpapa/32/6835_2.png) [@DrPapa](https://discourse.julialang.org/u/DrPapa)\
**Post date:** [November 19, 2018, 2:39pm UTC](https://discourse.julialang.org/t/why-do-these-two-similar-functions-lead-to-different-timings/17621/10 "2018-11-19T14:39:52Z")

</div>

That’s simple enough! Thanks.
