I’m trying to get a small piece of code that I’ll run millions of times to run without allocations. There is a small allocation that I cannot understand the cause of (for example, using Profile.Allocs cannot attribute the allocation to anything, even with a sample rate of 100%), but that I can avoid by adding parameters to a specific function definition. Unfortunately, in practice I can’t use the parameters because I need to support the inputs being of different types.
I’ve attempted to write a MWE to highlight the problem. Unfortunately, it doesn’t exhibit the same behaviour - the allocations happen even with the parameters. I don’t yet know why it’s different. Perhaps it’s because the code I’m using is in a package I’m writing - I have no idea. However, the M(non-)WE shows the syntax I mean, so perhaps someone will be able to explain the behaviour. Here’s the code and output:
using BenchmarkTools
using StaticArrays
struct Residual{T<:Number}
meas::SVector{2, T}
end
struct Transform{T<:Number}
rot::SMatrix{3, 3, T}
trans::SVector{3, T}
end
struct Point{T<:Number}
point::SVector{3, T}
end
function project(p::Point)
return SVector{2}(p.point[1], p.point[2]) ./ p.point[3]
end
function transform(t::Transform, p::Point)
return project(Point(t.rot * p.point + t.trans))
end
function computeresidual1(r::Residual, t::Transform, p::Point)
return transform(t, p) - r.meas
end
function computeresidual2(r::Residual{T}, t::Transform{T}, p::Point{T})::SVector{2, T} where T <: Real
return transform(t, p) - r.meas
end
r = Residual(randn(SVector{2, Float64}))
t = Transform(randn(SMatrix{3, 3, Float64}), randn(SVector{3, Float64}))
p = Point(randn(SVector{3, Float64}))
@btime computeresidual1($r, $t, $p)
@btime computeresidual2($r, $t, $p)
julia> 327.487 ns (8 allocations: 256 bytes)
julia> 446.551 ns (8 allocations: 256 bytes)
In my own case, the call to the function with parameters specified (computeresidual2), has zero allocations. Here it not only still has allocations, it’s also slower; the speed becomes the same if I don’t specify the output type in the function declaration.
I’m running Julia 1.8.2