# Integer parametric typed struct much slower than concrete struct

**URL:** <https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169>\
**Category:** Performance\
**Tags:** question, parametric-types, struct\
**Created:** [May 26, 2020, 7:14am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169 "2020-05-26T07:14:19Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lucas\_Liu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lucas_liu/32/9731_2.png) [@Lucas\_Liu](https://discourse.julialang.org/u/Lucas_Liu)\
**Post date:** [May 26, 2020, 7:14am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/1 "2020-05-26T07:14:19Z")

</div>

Need help on performance of struct with integer parametric-types.

I have the following piece of code for an AD package I am developing.

` PGrad ` is a struct for tracking gradients w.r.t N\_v variables in N\_c cells.

` PVar ` is a struct for variables.

```julia
using StaticArrays
using BenchmarkTools

struct PGrad{Nv, Nc}
    ind::SVector{Nc, Int}
    grad::SVector{Nc, SVector{Nv,Float64}}
end

struct PVar{T<:PGrad}
    val::Float64
    grad::T
end

```

Construction of one ` PVar{PGrad{2,1}} ` takes

```julia
pg1 = PGrad{2,1}(SA[1], SA[SA[1.0, 0.0]])
@btime PVar{PGrad{2,1}}(1.0, pg1)
```

```julia
 70.569 ns (1 allocation: 48 bytes) 
```

If I explicitly write

```julia
struct CGrad
    ind::SVector{1, Int}
    grad::SVector{1, SVector{2,Float64}}
end

struct CVar
    val::Float64
    grad::CGrad
end
```

Construction becomes much faster

```julia
cg1 = CGrad(SA[1], SA[SA[1.0, 0.0]])
@btime CVar(1.0, cg1)
```

```julia
7.000 ns (0 allocations: 0 bytes)
```

If I annotate types of grad, time for both cases go below ~5ns

```julia
ug1 = PGrad{2,1}(SA[1], SA[SA[1.0, 0.0]])
@btime PVar{PGrad{2,1}}(1.0, ug1::PGrad{2,1})
4.800 ns (0 allocations: 0 bytes)
```

```julia
cg1 = CGrad(SA[1], SA[SA[1.0, 0.0]])
@btime CVar(1.0, cg1::CGrad)
4.500 ns (0 allocations: 0 bytes)
```

Any idea what causes the difference in timing and number of allocations?

Maybe I am not using integer parameteric-type the correct way.

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [May 26, 2020, 7:24am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/2 "2020-05-26T07:24:45Z")

</div>

You need to interpolate to make timings accurate. If I do this I get the same timings:

```julia
julia> @btime PVar{PGrad{2,1}}(1.0, $pg1)
  0.017 ns (0 allocations: 0 bytes)
PVar{PGrad{2,1}}(1.0, PGrad{2,1}([1], SArray{Tuple{2},Float64,1,2}[[1.0, 0.0]]))

julia> @btime CVar(1.0, $cg1)
  0.017 ns (0 allocations: 0 bytes)
CVar(1.0, CGrad([1], SArray{Tuple{2},Float64,1,2}[[1.0, 0.0]]))

```

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [May 26, 2020, 7:24am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/3 "2020-05-26T07:24:49Z")

</div>

It’s simply an issue with your benchmark:

```julia
# Your benchmark
julia> @btime PVar{PGrad{2,1}}(1.0, pg1);
  59.793 ns (1 allocation: 48 bytes)

# Fixed benchmark
julia> @btime PVar{PGrad{2,1}}(1.0, $pg1);
  0.028 ns (0 allocations: 0 bytes)

```

The extra `$` in the second benchmark indicates that the compiler may treat `pg1` as a constant for the purpose of the benchmark. This allows the compiler to figure out precisely which functions to call and inline these function calls such that in the end there’s nothing left to do (hence the `<1 ns` runtime).

---

<div class="post-metadata">

**Author:** ![Lucas\_Liu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lucas_liu/32/9731_2.png) [@Lucas\_Liu](https://discourse.julialang.org/u/Lucas_Liu)\
**Post date:** [May 26, 2020, 7:45am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/4 "2020-05-26T07:45:54Z")

</div>

Thank you both!

---

<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:** [May 26, 2020, 11:26am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/5 "2020-05-26T11:26:53Z")

</div>

Note the [warning](https://github.com/JuliaCI/BenchmarkTools.jl/issues/130) for sub-nanosecond timings. It’s not real, it’s the compiler cheating.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [May 26, 2020, 11:43am UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/6 "2020-05-26T11:43:04Z")

</div>

> [@ettersi](#):
>
> `@btime PVar{PGrad{2,1}}(1.0, $pg1);`

Try `@btime PVar{PGrad{2,1}}(1.0, $(Ref(pg1))[]);`  
The `Ref` prevents the compiler from doing too much at compile time.

---

<div class="post-metadata">

**Author:** ![Lucas\_Liu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lucas_liu/32/9731_2.png) [@Lucas\_Liu](https://discourse.julialang.org/u/Lucas_Liu)\
**Post date:** [May 26, 2020, 6:48pm UTC](https://discourse.julialang.org/t/integer-parametric-typed-struct-much-slower-than-concrete-struct/40169/7 "2020-05-26T18:48:33Z")

</div>

> [@baggepinnen](#):
>
> PVar{PGrad{2,1}}(1.0, $(Ref(pg1)))

I get

```julia
pg1 = PGrad{2,1}(SA[1], SA[SA[1.0, 0.0]])
@btime PVar{PGrad{2,1}}(1.0, $(Ref(pg1))[])
1.400 ns (0 allocations: 0 bytes)
```

and

```julia
cg1 = CGrad(SA[1], SA[SA[1.0, 0.0]])
@btime CVar(1.0, $(Ref(cg1))[])
1.200 ns (0 allocations: 0 bytes)
```
