Long term, Keno has some revolutionary work planned on that front that will apply to regular arrays.
I’m not sure what the time horizon for that is though, e.g. he’s busy revolutionizing AD at the moment.
One of the problems in Julia compared to something like Fortran that makes this harder is that our optimization units are smaller.
If you’re compiling a huge Fortran program at once, the compiler can see that sure an array escapes the function that created it, passing it to another function, which it escapes from, which takes a slice that escapes, which…but then that one doesn’t escape, so it’s safe to stack allocate everything!
To add to the StrideArrays documentation, the unit tests have another example:
julia> using StrideArrays, Test
julia> @noinline function dostuff(A; B = I)
StrideArrays.@avx for i in eachindex(A)
A[i] += 1
C = A * B
s = zero(eltype(C))
StrideArrays.@avx for i in eachindex(C)
s += C[i]
dostuff (generic function with 1 method)
julia> function gc_preserve_test()
A = @StrideArray rand(8,8);
B = @StrideArray rand(8,8);
@gc_preserve dostuff(A, B = B)
gc_preserve_test (generic function with 1 method)
julia> @test iszero(@allocated gc_preserve_test())
We create two random matrices, pass them to a function that isn’t inlined, mutate one of them, multiply them, and then sum the result – all without allocations.
The key is the
@gc_preserve macro (which could be made a lot smarter than it is now; currently it only applies to a single function call), which basically just replaces all the arrays in the function call with
PtrArrays – pointers + some more information like size and strides.
This stops the arrays from escaping – they don’t get passed to the function – so they can be stack allocated. The macro uses
GC.@preserve to make sure that the arrays are nonetheless protected in the meantime, so it’s still GC-safe.
You can think of the macro as like a promise that the arrays don’t escape. If you do something like assign them to a global or
push! them into a vector, you’ll get garbage.