Addition of floats allocates memory in not fully qualified struct

Hi,
I see allocations when adding floats in a not fully qualified struct. Can you explain why the function func allocates memory when passing a BarSlow type into it? Below you find a minimal working example.
Thank you,
ncxst

using BenchmarkTools

mutable struct Foo{T}
    u::Float64
    t::T
end

mutable struct BarFast{T}
    foo::Foo{T}
    u::Float64
end
mutable struct BarSlow
    foo::Foo
    u::Float64
end

function func(bar)
    bar.foo.u += bar.u
    return nothing
end

f() = 0.0
foo = Foo(0.0, (f,))
barFast = BarFast(foo, 0.1)
barSlow = BarSlow(foo, 0.1)

@btime func($barFast)
  3.127 ns (0 allocations: 0 bytes)

@btime func($barSlow)
  53.306 ns (2 allocations: 32 bytes)

This is a type instability. The compiler doesn’t know the type of bar.foo at compile time, so it has store it in a heap-allocated “box” with a type tag that is inspected at runtime.

See Performance Tips: Avoid fields with abstract type.

4 Likes