What is the most efficient way to access (and perhaps replace) an entry in a large multidimensional array? I am using something like this inside a loop:
tup = (16,45,6,40,3)
A[tup...] = 100
but I'm wondering if there is a more efficient way. In particular, is there a way I can avoid using ...
?
There's not always a penalty involved with splatting, but determining where it is efficient isn't always obvious (or easy). Your trivial example is actually just as efficient as writing A[16,45,6,40,3] = 100
. You can see this by comparing
function f(A)
tup = (16,45,6,40,3)
A[tup...] = 100
A
end
function g(A)
A[16,45,6,40,3] = 100
A
end
julia> code_llvm(f, Tuple{Array{Int, 5}})
# Lots of output (bounds checks).
julia> code_llvm(g, Tuple{Array{Int, 5}})
# Identical to above
If there was a splatting penalty, you'd see it in the form of allocations. You can test for this with the @allocated
macro or by simply inspecting code_llvm
for a reference to @jl_pgcstack
— that's the garbage collector, which is required any time there's an allocation. Note that there is very likely other things in a more complicated function that will also cause allocations, so it's presence doesn't necessarily mean that there's a splatting pessimization. But if this is in a hot loop, you want to minimize all allocations, so it's a great target… even if your problem isn't due to splatting. You should also be using @code_warntype
, as poorly typed code will definitely pessimize splats and many other operations. Here's what will happen if your tuple isn't well typed:
function h(A)
tup = ntuple(x->x+1, 5) # type inference doesn't know the type or size of this tuple
A[tup...] = 100
A
end
julia> code_warntype(h, Tuple{Array{Int,5}})
# Lots of red flags
So optimizing this splat will be highly dependent upon how you construct or obtain tup
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With