# Extra allocations performing dot product in ODE callback

**URL:** https://discourse.julialang.org/t/extra-allocations-performing-dot-product-in-ode-callback/100683
**Category:** Performance
**Tags:** memory-allocation, ode, diffeqcallbacks
**Created:** [June 22, 2023, 6:03am UTC](https://discourse.julialang.org/t/extra-allocations-performing-dot-product-in-ode-callback/100683 "2023-06-22T06:03:57Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)
#### Post date: [June 22, 2023, 6:03am UTC](https://discourse.julialang.org/t/extra-allocations-performing-dot-product-in-ode-callback/100683/1 "2023-06-22T06:03:58Z")

</div>

Hello,

I’m experiencing some extra memory allocations when calculating the `dot` product inside a ODE callback. Here I write a minimal example

```julia
A = sprand(ComplexF64, 100, 100, 0.05)
u0 = rand(ComplexF64, 100)
y = rand(ComplexF64, 100)
p = [Dict(:A => A, :y => y)]

dudt!(du, u, p, t) = mul!(du, p[1][:A], u)

```

Now I check that dudt! is inplace

```julia
du = similar(u0)
@btime dudt!($du, $u0, $p, 0.0);
533.511 ns (0 allocations: 0 bytes)

```

Now I check the ODEproblem solution without any callback

```julia
prob = ODEProblem(dudt!, u0, (0.0, 10.0), p, save_on=false)
@btime solve(prob, Tsit5(), saveat=[10.0]);

193.700 μs (48 allocations: 32.59 KiB)

```

And now I introduce a simple callback without doing anything

```julia
function myaffect!(integrator)
    internal_params = integrator.p[1]
    y = internal_params[:y]

    # dot(y, integrator.u)
end

tlist = range(0, 10, 1000)
cb = PresetTimeCallback(tlist, myaffect!)
prob = ODEProblem(dudt!, u0, (0.0, 10.0), p, save_on=false, callback=cb)
@btime solve(prob, Tsit5(), saveat=[10.0]);

5.394 ms (58 allocations: 75.09 KiB)

```

Where I think that the extra 10 allocations are for creating the callback, which should be fine.  
But if I uncomment the dot function inside the callback function:

```julia
5.685 ms (1058 allocations: 106.34 KiB)

```

Which seems that is allocates the memory every time this function is called.

By benchmarking the dot function it returns zero allocations of course

```julia
integrator = init(prob, Tsit5())
@btime dot($y, $(integrator.u))

39.152 ns (0 allocations: 0 bytes)
53.40957206916622 - 1.5882023409748207im

```

while benchmarking the callback function I get one memory allocation

```julia
@btime myaffect!($integrator)

 56.135 ns (1 allocation: 32 bytes)
53.40957206916622 - 1.5882023409748207im

```

I tried to calculate `dot(integrator.u, integrator.u)` and there is no extra memory allocation, so it comes from the dot product involving `y`.

how can I perform such operation without allocating extra memory?

---

<div class="post-metadata">

### Author: ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)
#### Post date: [June 22, 2023, 7:12am UTC](https://discourse.julialang.org/t/extra-allocations-performing-dot-product-in-ode-callback/100683/2 "2023-06-22T07:12:59Z")

</div>

> [@albertomercurio](#):
>
> ```julia
> A = sprand(ComplexF64, 100, 100, 0.05)
> u0 = rand(ComplexF64, 100)
> y = rand(ComplexF64, 100)
> p = [Dict(:A => A, :y => y)]
> 
> ```

Your parameter is type unstable:

```julia
julia> p |> typeof
Vector{Dict{Symbol, AbstractArray{ComplexF64}}} (alias for Array{Dict{Symbol, AbstractArray{Complex{Float64}}}, 1})

```

This is because you use two different arrays in it (sparse and a normal array)  
It would be best to create your own struct for p to avoid the allocations that are part of the type instability

---

<div class="post-metadata">

### Author: ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)
#### Post date: [June 22, 2023, 7:13am UTC](https://discourse.julialang.org/t/extra-allocations-performing-dot-product-in-ode-callback/100683/3 "2023-06-22T07:13:05Z")

</div>

Did you check what `@code_warntype myaffect!(integrator)` says?

My guess is that the parameter vector is the problem: The Dict contains different array types, so the output of `y = integrator.p[1][:y]` is not determined based on the type of `integrator` alone.

Using a `NamedTuple` instead of a `Dict` should help:

```julia
p = [(A = A, y = y)]

```

(the rest of the code would probably stay the same, but I didn’t check)

---

<div class="post-metadata">

### Author: ![albertomercurio](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/albertomercurio/32/27051_2.png) [@albertomercurio](https://discourse.julialang.org/u/albertomercurio)
#### Post date: [June 23, 2023, 3:10pm UTC](https://discourse.julialang.org/t/extra-allocations-performing-dot-product-in-ode-callback/100683/4 "2023-06-23T15:10:35Z")

</div>

Thanks, it worked!
