# Memory allocation when creating struct with dynamic array

**URL:** <https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346>\
**Category:** General Usage\
**Created:** [July 1, 2020, 5:15am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346 "2020-07-01T05:15:18Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![awin](https://avatars.discourse-cdn.com/v4/letter/a/848f3c/32.png) [@awin](https://discourse.julialang.org/u/awin)\
**Post date:** [July 1, 2020, 5:15am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/1 "2020-07-01T05:15:18Z")

</div>

I am writing a package for simulating realistic quantum systems. A key component in these simulations is defining pulses. Defining several constant size structs NormPulse, SquarePulse, etc. behaves as expected. However, when I extend the abstract type with DiscretePulse which contains a dynamic array there are allocations. Here is a minimum example:

Create a project containing:

```julia
module Example1

using SpecialFunctions

export AbstractPulse, DiscretePulse, NormPulse, amp

abstract type AbstractPulse end

mutable struct NormPulse <: AbstractPulse
    t0::Float64
    t1::Float64
    σ::Float64
    A::Float64
    B::Float64
end

mutable struct DiscretePulse <: AbstractPulse
    t0::Float64
    t1::Float64
    res::Float64
    A::Vector{ComplexF64}
    N::Int
end

norm_pdf(x, μ, σ) = exp(-(x - μ)^2 / (2 * σ^2)) / (√(2pi) * σ)
norm_cdf(x, μ, σ) = (1 + erf((x - μ) / (√2 * σ))) / 2

function norm_coeff(t0, t1, σ, area)
    τ = t1 - t0
    a = 2norm_cdf(τ / 2, 0, σ) - 1
    b = norm_pdf(0, τ / 2, σ)
    area / (a - b * τ), -area / (a / b - τ)
end

function NormPulse(t0, t1, σ, area)
    @assert t1 > t0
    @assert σ > 0
    a, b = norm_coeff(t0, t1, σ, area)
    NormPulse(t0, t1, σ, a, b)
end

inbounds(p::AbstractPulse, t) = p.t0 ≤ t ≤ p.t1
function amp(p::DiscretePulse, t)::ComplexF64
    if !inbounds(p, t)
    return 0
    end

    n = min(1 + Int(floor((t - p.t0) / p.res)), p.N)
    @inbounds return p.A[n]
end

end

```

Next run:

```julia
activate .

using Example1

Ω1 = [NormPulse(0.0, 1+rand(), rand() / 4, pi / 2) for i = 1:5]

function test(Ω)
    for i = 1:5
        t1 = 1+rand()
        amp(Ω[i], t1)
    end
end

@btime test(Ω1)

```

If I comment out the function amp(p::DiscretePulse, t) there are no allocations. However, if I do not, there are 2 allocations during every call of amp(Ω[i], t1). Does anyone know why this happens?

The function is called in a tight loop where allocations may dramatically impact performance.

---

<div class="post-metadata">

**Author:** ![awin](https://avatars.discourse-cdn.com/v4/letter/a/848f3c/32.png) [@awin](https://discourse.julialang.org/u/awin)\
**Post date:** [July 1, 2020, 6:40am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/2 "2020-07-01T06:40:17Z")

</div>

**More information**

In an important application that I cannot disclose, there is an order of magnitude reduction in performance because of this issue.

With DiscretePulse and amp(p::DiscretePulse, t) defined (not explicitly used in test):  
5.882 ms (151286 allocations: 4.56 MiB)  
Without:  
709.623 μs (669 allocations: 35.34 KiB)

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [July 1, 2020, 7:00am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/3 "2020-07-01T07:00:06Z")

</div>

Welcome! Thanks for the MWE, but for others to help please make sure it can be run:

- `SquarePulse` is not defined
- There is an unexpected `end` in the calling code
- For the array comprehension `Ω1` you might have meant `i = 1:5` instead of `i = 5`

My inital guess for the problem is that `Ω1` is defined in the global. Try to `const Ω1 = [...` it.

---

<div class="post-metadata">

**Author:** ![awin](https://avatars.discourse-cdn.com/v4/letter/a/848f3c/32.png) [@awin](https://discourse.julialang.org/u/awin)\
**Post date:** [July 1, 2020, 8:03am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/4 "2020-07-01T08:03:44Z")

</div>

Good catch, I had quickly copied the code to create an example. I’ve since corrected it.

Why would defining `Ω1` as a const fix this issue?

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [July 1, 2020, 9:45am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/5 "2020-07-01T09:45:01Z")

</div>

When you use `const` on a variable the compiler is able to assume the type and is therefore in the position to apply optimizations. See [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-global-variables-1)

Small example showing the difference:

```julia
julia> a = 2
2

julia> b = 3
3

julia> typeof(a)
Int64

julia> typeof(b)
Int64

julia> noconst() = a + b
noconst (generic function with 1 method)

julia> noconst()
5

julia> @code_warntype noconst()
Variables
  #self#::Core.Compiler.Const(noconst, false)

Body::Any
1 ─ %1 = (Main.a + Main.b)::Any
└── return %1

julia> const c = 2
2

julia> const d = 3
3

julia> withconst() = c + d
withconst (generic function with 1 method)

julia> withconst()
5

julia> @code_warntype withconst()
Variables
  #self#::Core.Compiler.Const(withconst, false)

Body::Int64
1 ─ %1 = (Main.c + Main.d)::Core.Compiler.Const(5, false)
└── return %1

```

---

<div class="post-metadata">

**Author:** ![awin](https://avatars.discourse-cdn.com/v4/letter/a/848f3c/32.png) [@awin](https://discourse.julialang.org/u/awin)\
**Post date:** [July 2, 2020, 6:14am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/6 "2020-07-02T06:14:46Z")

</div>

The variable is in the local scope, I meant to write @btime test($Ω1). Nevertheless, the issue persists.

---

<div class="post-metadata">

**Author:** ![laborg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laborg/32/5474_2.png) [@laborg](https://discourse.julialang.org/u/laborg)\
**Post date:** [July 2, 2020, 6:54am UTC](https://discourse.julialang.org/t/memory-allocation-when-creating-struct-with-dynamic-array/42346/7 "2020-07-02T06:54:38Z")

</div>

Your MWE isn’t working on Julia 1.4.2:

```julia
julia> activate .
ERROR: syntax: space before "." not allowed in "activate ." at REPL[16]:1
Stacktrace:
 [1] top-level scope at REPL[15]:0

julia> @btime test(Ω1)
ERROR: MethodError: no method matching amp(::NormPulse, ::Float64)

```

So its unclear what the problem is. I’m also not sure if I understand the

> The variable is in the local scope, I meant to write @btime test($Ω1).

comment. Do you mean that the `$` in front of `Ω1` somehow makes it local scope? A reproducible example will certainly help…
