Search code examples
arraysperformancememoryjuliaallocation

Performance assigning and copying with StaticArrays.jl in Julia


I was thinking of using the package StaticArrays.jl to enhance the performance of my code. However, I only use arrays to store computed variables and use them later after certain conditions are set. Hence, I was benchmarking the type SizedVector in comparison with normal vector, but I do not understand to code below. I also tried StaticVector and used the work around Setfield.jl.

using StaticArrays, BenchmarkTools, Setfield
function copySized(n::Int64)
    v = SizedVector{n, Int64}(zeros(n))
    w = Vector{Int64}(undef, n)
    for i in eachindex(v)
        v[i] = i
    end
    for i in eachindex(v)
        w[i] = v[i]
    end
end
function copyStatic(n::Int64)
    v = @SVector zeros(n)
    w = Vector{Int64}(undef, n)
    for i in eachindex(v)
        @set v[i] = i
    end
    for i in eachindex(v)
        w[i] = v[i]
    end
end
function copynormal(n::Int64)
    v = zeros(n)
    w = Vector{Int64}(undef, n)
    for i in eachindex(v)
        v[i] = i
    end
    for i in eachindex(v)
        w[i] = v[i]
    end
end
n = 10
@btime copySized($n)
@btime copyStatic($n)
@btime copynormal($n)

3.950 μs (42 allocations: 2.08 KiB)
5.417 μs (98 allocations: 4.64 KiB) 
78.822 ns (2 allocations: 288 bytes)

Why does the case with SizedVector does have some much more allocations and hence worse performance? Do I not use SizedVector correctly? Should it not at least have the same performance as normal arrays?

Thank you in advance.

Cross post of Julia Discourse


Solution

  • I feel this is apples-to oranges comparison (and size should be store in statically in type). More illustrative code could look like this:

    function copySized(::Val{n}) where n
        v = SizedVector{n}(1:n)
        w = Vector{Int64}(undef, n)
        w .= v
    end
    function copyStatic(::Val{n}) where n
        v =  SVector{n}(1:n)
        w = Vector{Int64}(undef, n)
        w .= v
    end
    function copynormal(n) 
        v = [1:n;]
        w = Vector{Int64}(undef, n)
        w .= v
    end
    

    And now benchamrks:

    julia> n = 10
    10
    
    julia> @btime copySized(Val{$n}());
      248.138 ns (1 allocation: 144 bytes)
    
    julia> @btime copyStatic(Val{$n}());
      251.507 ns (1 allocation: 144 bytes)
    
    julia> @btime copynormal($n);
      77.940 ns (2 allocations: 288 bytes)
    
    julia>
    
    julia>
    
    julia> n = 1000
    1000
    
    julia> @btime copySized(Val{$n}());
      840.000 ns (2 allocations: 7.95 KiB)
    
    julia> @btime copyStatic(Val{$n}());
      830.769 ns (2 allocations: 7.95 KiB)
    
    julia> @btime copynormal($n);
      1.100 μs (2 allocations: 15.88 KiB)