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

resize! of HybridArray

Open judober opened this issue 1 year ago • 6 comments

I use HybridArrays as a replacement for a Vector of SMatrices. Now I found the need to resize! the Vector. This works for Vector of SMatrices but not a HybridArray:

V = [SA[1 2; 3 4], SA[5 6; 7 8]]; 
resize!(V, 3) # adds one entry

H = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(randn(2,2,2));
resize!(H, 3) # errors

Is there a way to achieve this with a HybridArray?

judober avatar May 01 '23 10:05 judober

Currently there is no such functionality but I can add it for https://github.com/JuliaArrays/ElasticArrays.jl wrapped in HybridArrays. Would that work for you?

mateuszbaran avatar May 01 '23 15:05 mateuszbaran

I didn't know ElasticArrays but it sounds interesting!

However, I understand my problem better now and solved it differently.

My first attempt to increase the Array was generate a new one and copy the data resulting in bad performance (example with short arrays):

H = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(randn(2,2,2))
H2 = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(Array{Float64}(undef, 2, 2, 4))
@btime H2[:,:,1:2] .= H #30.800 μs (333 allocations: 21.00 KiB)

But when I insted loop over the third dimension, I get good performance:

@btime for i = 1:2; H2[:,:,i] = H[:,:,i]; end #66.667 ns (2 allocations: 96 bytes)

I guess .= is not implemented efficiently as it depends on which dimensions are Dynamic.

So from my side this issue can actually be closed.

judober avatar May 01 '23 21:05 judober

Hm, that broadcast shouldn't be so slow but I'm not sure what causes that issue. I'll have to investigate.

mateuszbaran avatar May 02 '23 17:05 mateuszbaran

I improved the benchmark a little with:

H = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(randn(2,2,2))
H2 = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(Array{Float64}(undef, 2, 2, 4))
@btime $H2[:,:,1:2] .= $H #196.189 ns (16 allocations: 512 bytes)
@btime for i = 1:2; $H2[:,:,i] = $H[:,:,i]; end #3.000 ns (0 allocations: 0 bytes)

The difference is smaller but still signifficant.

f() = begin H = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(randn(2,2,2))
       H2 = HybridArray{Tuple{2,2,StaticArrays.Dynamic()}}(Array{Float64}(undef, 2, 2, 4))
       H2[:,:,1:2] .= H
       end
@profview for i = 1:10_000_000 f() end

tells me that most time is spend in _setindex!_scalar, not sure if this helps.

judober avatar May 06 '23 20:05 judober

I've spent some time investigating but I got stuck: https://discourse.julialang.org/t/tracking-the-cause-of-allocation-in-the-presence-of-a-generated-function/98215 . I have no idea why Julia failed to optimize that call and the tools I know don't help :confused: . I think it would be easier to implement resize! for hybrid elastic arrays.

mateuszbaran avatar May 07 '23 09:05 mateuszbaran

Ok, thanks for looking into this!

judober avatar May 07 '23 16:05 judober