# Nested functions with  SubArray argument

**URL:** <https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502>\
**Category:** Performance\
**Created:** [April 24, 2018, 8:45am UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502 "2018-04-24T08:45:03Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [April 24, 2018, 8:45am UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502/1 "2018-04-24T08:45:03Z")

</div>

Hi,  
I compare the performances of 3 functions implementing `X.+=1` where X is a 2D Array of float.

- `shift2D_1D!` splits the 2D loop in two nested functions.

- `shift2DLoop!` uses a single function with a 2D loop nest,

- `shift2DNative!` uses the broadcast iterator,

The `shift2D_1D!` exhibits lower performances. Is there a way to improve this ?  
In particular, is the signature of the inner function `shift1D!` acting on a SubArray OK ?

Results : (Julia 0.6)

`GFlops=10.829836198727493 (shift2D_1D!)`  
`GFlops=18.726591760299627 (shift2DLoop!)`  
`GFlops=17.362785762515674 (shift2DNative!)`

Thank you for your help.  
Laurent

```julia
using BenchmarkTools

# Implementation #1 shift1D! and shift2D! 
function shift1D!(x::AbstractArray{T,1}) where T<:Real
    one_T=T(1)
    nx=length(x)
    @simd for i=1:nx
        @inbounds x[i]+=one_T
    end
end

function shift2D_1D!(x2D::Array{T,2}) where T<:Real
    nx,ny=size(x2D)
    for j=1:ny
        shift1D!(view(x2D,:,j))
    end
end

# Implementation #2 Nested Loops impl for X2D+=1
function shift2DLoop!(x2D::Array{T,2}) where T<:Real
    nx,ny=size(x2D)
    one_T=T(1)
    @simd for j=1:ny
        @simd for i=1:nx
            @inbounds x2D[i,j]+=one_T
        end
    end
end

# Implementation #3 native Julia broadcast op for X2D+=1
function shift2DNative!(x2D::Array{T,2}) where T<:Real
    one_T=T(1)
    x2D.+=one_T
end

# A function to evaluate the performances
function testShift(shiftFunction, T::Type,n::Int64)
    x=zeros(T,n,n)
    # t=@belapsed shift2D!($x)
    @benchmark $shiftFunction($x)
    t=@belapsed $shiftFunction($x)
    print("GFlops=",n*n/(t*1.e9)," (",string(shiftFunction),")\n")
end

testShift(shift2D_1D!,Float32,200)
testShift(shift2DLoop!,Float32,200)
testShift(shift2DNative!,Float32,200)

```

---

<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:** [April 24, 2018, 9:05am UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502/2 "2018-04-24T09:05:23Z")

</div>

Creating a `view` has some overhead unless all uses of the view are confined to the function where it is created.

You can do that by force inlining `shift1D!` by adding `@inline` in front of the function definition.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [April 24, 2018, 12:26pm UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502/3 "2018-04-24T12:26:56Z")

</div>

Great ! The @inline macro removed the overhead.  
Thank you very much Kristoffer.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [April 24, 2018, 12:26pm UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502/4 "2018-04-24T12:26:58Z")

</div>

GFlops=18.65671641791045 (shift2D\_1D! with @inline before shift1D!)  
GFlops=16.99556226985176 (shift2DLoop!)  
GFlops=17.584135202461777 (shift2DNative!)

---

<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:** [April 24, 2018, 12:55pm UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502/5 "2018-04-24T12:55:17Z")

</div>

I only get around 7 GFlops on my computer (2016 macbook pro), out of curiosity, what system are you running on?

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [April 24, 2018, 6:21pm UTC](https://discourse.julialang.org/t/nested-functions-with-subarray-argument/10502/6 "2018-04-24T18:21:33Z")

</div>

A Desktop CPU:  
`model name	: Intel(R) Core(TM) i7-6700K CPU @ 4.00GHz`  
but I had to build the system image in order to access the **AVX instructions** (otherwise the perfs are halved).
