StaticArrays.jl icon indicating copy to clipboard operation
StaticArrays.jl copied to clipboard

SVector sometimes allocates

Open dpinol opened this issue 3 years ago • 4 comments

This does not allocate

const v=[1]
const vl=length(v)
   
function g()
   SVector{vl, Int}(v)
end

@timev g()

  0.000001 seconds
elapsed time (ns):  769
gc time (ns):       0
bytes allocated:    0
pool allocs:        0
non-pool GC allocs: 0
minor collections:  0
full collections:   0

But this allocates:

const v=[1]

function g()
   vl=length(v)
   SVector{vl, Int}(v)
end

@timev g()

  0.000017 seconds (10 allocations: 528 bytes)
elapsed time (ns): 17108
bytes allocated:   528
pool allocs:       10
1-element SVector{1, Int64} with indices SOneTo(1):
 1

julia> @allocated g()
528

Using @SVector is not an option for me due to #1014

dpinol avatar Mar 15 '22 16:03 dpinol

I believe this is more or less expected, since g is type unstable -- even if v is const, the length is not.

julia> @code_warntype g()
MethodInstance for g()
  from g() in Main at REPL[5]:1
Arguments
  #self#::Core.Const(g)
Locals
  vl::Int64
Body::Any
1 ─      (vl = Main.length(Main.v))
│   %2 = Core.apply_type(Main.SVector, vl, Main.Int)::Type{SVector{_A, Int64}} where _A
│   %3 = (%2)(Main.v)::Any
└──      return %3

fredrikekre avatar Mar 15 '22 17:03 fredrikekre

@fredrikekre thank you for the quick reply. Can you think of any workaround? Any kind of function barrier?

dpinol avatar Mar 16 '22 09:03 dpinol

You can pass around Val(length(v)) to get it to specialize the inner code.

andyferris avatar Mar 16 '22 23:03 andyferris

@andyferris I still get allocations. Am I missing something? thanks

using StaticArrays
function createMVector(len::Val{L}) where {L}
           return MVector{L, Int}((1 for i in 1:L))
end
const s=[1]

julia> @allocated createMVector(Val(length(s)))
14348930

julia> @allocated createMVector(Val(length(s)))
16

dpinol avatar Mar 17 '22 13:03 dpinol