I could use help understanding the magic of allocations in Julia with the inplace .=
operation. Below I have 4 ways to write the same operation, but allocations are different for each. Only the first doesn’t allocate. My intention is to preallocate an array and put the output of the fn
function into that memory. Why are the 2nd, 3rd, and 4th functions allocating when the first isn’t?
using BenchmarkTools
N, M, L = 3, 5, 4
b = rand(N, M)
c = [rand(N) for _ in 1:L]
a = Array{Float64,3}(undef, N, M, L)
function foo1!(a, b, c)
for i in eachindex(c)
a[:, :, i] .= b .- c[i]
end
return nothing
end
function foo2!(a, b, c, fn=(-))
for i in eachindex(c)
a[:, :, i] .= fn.(b, c[i])
end
return nothing
end
function foo3!(a, b, c)
for i in eachindex(c)
for j in axes(b, 2)
a[:, j, i] .= view(b, :, j) - c[i]
end
end
return nothing
end
function foo4!(a, b, c, fn=(-))
for i in eachindex(c)
for j in axes(b, 2)
a[:, j, i] .= fn(view(b, :, j), c[i])
end
end
return nothing
end
@btime foo1!($a, $b, $c) # 71.783 ns (0 allocations: 0 bytes)
@btime foo2!($a, $b, $c) # 1.204 μs (12 allocations: 512 bytes)
@btime foo3!($a, $b, $c) # 864.382 ns (20 allocations: 1.56 KiB)
@btime foo4!($a, $b, $c) # 867.788 ns (20 allocations: 1.56 KiB)