This is a note to myself or anyone else who wants to take a stab at implementing an array type which stores up to N values as fixed size bits and then if the array gets too big it'll instead store them on the heap. From https://discourse.julialang.org/t/small-vectors/97121/5 a basic implementation looks like:
using StrideArrays
mutable struct SmallStore{SpillSize}
inline::NTuple{SpillSize, UInt8}
outline::Union{Vector{UInt8}, Nothing}
end;
function smallarray(::Type{T}, ::StaticInt{SpillSize}, size::Integer...) where {T, SpillSize}
@assert isbitstype(T)
N = prod(size) * sizeof(T)
inline = Ref{NTuple{SpillSize, UInt8}}()[]
if N <= SpillSize
outline = nothing
store = SmallStore{SpillSize}(inline, outline)
ptr = pointer_from_objref(store)
else
outline = Vector{UInt8}(undef, N)
store = SmallStore{SpillSize}(inline, outline)
ptr = pointer(outline)
end
ptrA = PtrArray(Ptr{T}(ptr), size)
strA = StrideArray(ptrA, store)
end;
Now here's a benchmark function comparing this smallarray to an array without a static lower size bound:
function foo_sa()
SpillSize = static(10*8)
if rand() < 0.95
# 95% of the time our vector fits inline
L = 10
else
# 5% of the time it'll be too big
L = 10000
end
A = smallarray(Float64, SpillSize, L)
A .= (1:L)
sum(A)
end;
function foo()
if rand() < 0.95
L = 10
else
L = 10000
end
A = StrideArray{Float64}(undef, L)
A .= (1:L)
sum(A)
end;
julia> @benchmark foo_sa()
BenchmarkTools.Trial: 10000 samples with 997 evaluations.
Range (min … max): 138.866 ns … 3.697 μs ┊ GC (min … max): 0.00% … 78.22%
Time (median): 273.836 ns ┊ GC (median): 0.00%
Time (mean ± σ): 321.531 ns ± 176.710 ns ┊ GC (mean ± σ): 10.40% ± 15.50%
▃▆██▇▄▂
▁▁▂▃▅█████████▇▅▄▃▃▂▂▂▁▁▁▁▁▁▂▂▂▂▂▂▂▂▂▂▁▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
139 ns Histogram: frequency by time 932 ns <
Memory estimate: 2.05 KiB, allocs estimate: 1.
julia> @benchmark foo()
BenchmarkTools.Trial: 9078 samples with 994 evaluations.
Range (min … max): 269.175 ns … 2.844 μs ┊ GC (min … max): 0.00% … 80.24%
Time (median): 475.920 ns ┊ GC (median): 0.00%
Time (mean ± σ): 551.678 ns ± 220.005 ns ┊ GC (mean ± σ): 11.35% ± 15.79%
▁▆█▇▅
▁▁▁▁▃▅██████▆▅▃▂▂▂▂▂▂▂▃▃▄▃▃▃▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
269 ns Histogram: frequency by time 1.53 μs <
Memory estimate: 4.77 KiB, allocs estimate: 1.
This is a note to myself or anyone else who wants to take a stab at implementing an array type which stores up to
Nvalues as fixed size bits and then if the array gets too big it'll instead store them on the heap. From https://discourse.julialang.org/t/small-vectors/97121/5 a basic implementation looks like:Now here's a benchmark function comparing this
smallarrayto an array without a static lower size bound: