# SVector vs struct performance

**URL:** <https://discourse.julialang.org/t/svector-vs-struct-performance/49503>\
**Category:** Performance\
**Created:** [November 3, 2020, 6:11am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503 "2020-11-03T06:11:16Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![arnief3](https://avatars.discourse-cdn.com/v4/letter/a/a698b9/32.png) [@arnief3](https://discourse.julialang.org/u/arnief3)\
**Post date:** [November 3, 2020, 6:11am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/1 "2020-11-03T06:11:16Z")

</div>

I am struggling to understand the huge performance difference I am seeing between these two approaches to creating a Vec3 DataType. I would prefer to use a SVector, but only if the performance is comparable. I feel like I must be missing a critical piece of the puzzle here.

```nohighlight

Vec3 = SVector{3,Float64}

function test(v1, v2)
    v3 = Vec3(rand(), rand(), rand())
    for i = 1:10^7
        v3 = (v1 .* v2) .+ v3
    end
    return v3
end

v1 = Vec3(rand(), rand(), rand())
v2 = Vec3(rand(), rand(), rand())

test(v1, v2)
@time v3 = test(v1, v2)

println(v3)

```

Result: 2.440927 seconds (40.00 M allocations: 2.384 GiB, 9.92% gc time)

```julia
struct Vec3
    x::Float64
    y::Float64
    z::Float64
end

add(a::Vec3, b::Vec3)::Vec3 = Vec3(a.x+b.x, a.y+b.y, a.z+b.z)
mul(a::Vec3, b::Vec3)::Vec3 = Vec3(a.x*b.x, a.y*b.y, a.z*b.z)

function test(v1, v2)
    v3 = Vec3(0,0,0)
    for i = 1:10^7
        v3 = add(mul(v1, v2), v3)
    end
    return v3
end

v1 = Vec3(rand(), rand(), rand())
v2 = Vec3(rand(), rand(), rand())

test(v1, v2)
@time v3 = test(v1, v2)

println(v3)

```

Result: 0.009356 seconds (1 allocation: 32 bytes)

Thanks,  
Arnie

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [November 3, 2020, 6:20am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/2 "2020-11-03T06:20:59Z")

</div>

`const Vec3 = SVector{3,Float64}` fixes this for me. The problem is that without the `const`, `test` can’t know that the definition of `Vec3` won’t change at any time. This makes the whole method type unstable.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [November 3, 2020, 6:21am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/3 "2020-11-03T06:21:51Z")

</div>

Your `Vec3` alias is a non-constant global variable in your first example. Marking that as `const Vec3 = ...` should fix the issue.

This isn’t necessary in your second example because `struct` definitions are always constant and therefore don’t need to be marked `const`

---

<div class="post-metadata">

**Author:** ![arnief3](https://avatars.discourse-cdn.com/v4/letter/a/a698b9/32.png) [@arnief3](https://discourse.julialang.org/u/arnief3)\
**Post date:** [November 3, 2020, 6:26am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/4 "2020-11-03T06:26:59Z")

</div>

That did the trick! Thank you both for your help.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 3, 2020, 9:06am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/5 "2020-11-03T09:06:17Z")

</div>

Off topic: you can use the splat operator to initialize those vectors:

> [@arnief3](#):
>
> ```julia
> v1 = Vec3(rand(3)...)
> 
> ```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [November 3, 2020, 9:36am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/6 "2020-11-03T09:36:28Z")

</div>

> [@](#):
>
> `v1 = Vec3(rand(3)...)`

Actually, the above first creates a length-3 standard array, then splats, which can be very expensive.

This is _much_ faster and more convenient:

```julia
v1 = rand(Vec3)

```

(\>20x as fast and zero allocations on my laptop, this is the same speed as `Vec3(rand(), rand(), rand())`, BTW.)

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [November 3, 2020, 10:33am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/7 "2020-11-03T10:33:52Z")

</div>

True, but that does not work for the custom struct Vec3. (And, I agree, even in that case if speed is a concern, splatting is not the best choice).

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [November 3, 2020, 10:44am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/8 "2020-11-03T10:44:22Z")

</div>

In this particular example, the struct `Vec3` may subtype `FieldVector` and `rand` will work as expected.

```julia
julia> struct Vec3{T} <: FieldVector{3,T}
           x::T
           y::T
           z::T
       end

julia> rand(Vec3{Float64})
3-element Vec3{Float64} with indices SOneTo(3):
 0.8851737855718469
 0.47765777403880194
 0.6473023269774472

```

This won’t work in general though.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [November 3, 2020, 10:46am UTC](https://discourse.julialang.org/t/svector-vs-struct-performance/49503/9 "2020-11-03T10:46:14Z")

</div>

It works if `Vec3` is an alias for `SVector`, which the OP actually wanted to use.

A simple fix for the custom type is

```julia
julia> Base.rand(::Type{Vec3}) = Vec3(rand(), rand(), rand())

julia> rand(Vec3)
Vec3(0.06672577632910204, 0.7133141256121924, 0.6727958470918942)

```

but it is a bit more work to get the full `rand` functionality, like e.g. `rand(Vec3, 3, 4)` or setting the rng.
