# Why is SVector faster than MVector

**URL:** <https://discourse.julialang.org/t/why-is-svector-faster-than-mvector/55174>\
**Category:** Performance\
**Created:** [February 12, 2021, 9:12pm UTC](https://discourse.julialang.org/t/why-is-svector-faster-than-mvector/55174 "2021-02-12T21:12:10Z")\
**Posts on this page:** 1\
**Showing post:** 10

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [February 13, 2021, 2:12am UTC](https://discourse.julialang.org/t/why-is-svector-faster-than-mvector/55174/10 "2021-02-13T02:12:47Z")

</div>

> [@Mason](#):
>
> Currently, the answer really just is that you can’t guarantee it, and all of these things are allowed to change between versions. This can be a blessing and a curse.

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](https://github.com/chriselrod/StrideArrays.jl/blob/f16c3e5d6f17ed682e5a561e0d97406a1c46a799/test/misc.jl#L2) have another example:

```julia
julia> using StrideArrays, Test

julia> @noinline function dostuff(A; B = I)
           StrideArrays.@avx for i in eachindex(A)
               A[i] += 1
           end
           C = A * B
           s = zero(eltype(C))
           StrideArrays.@avx for i in eachindex(C)
               s += C[i]
           end
           s
       end
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)
       end
gc_preserve_test (generic function with 1 method)

julia> @test iszero(@allocated gc_preserve_test())
Test Passed

julia> gc_preserve_test()
374.2746212074998

```

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 `PtrArray`s – 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.

---

_[View the full topic](https://discourse.julialang.org/t/why-is-svector-faster-than-mvector/55174)._
