# Undesired memory allocation during interpolation

**URL:** https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713
**Category:** Performance
**Tags:** memory-allocation
**Created:** [December 7, 2021, 3:00pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713 "2021-12-07T15:00:43Z")
**Posts on this page:** 14
**Page:** 2

<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: [December 8, 2021, 4:17pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/21 "2021-12-08T16:17:12Z")

</div>

```julia
getindex.((Xdata,), iW)

```

then?

---

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [December 8, 2021, 4:22pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/22 "2021-12-08T16:22:01Z")

</div>

> [@DNF](#):
>
> `getindex.((Xdata,), iW)`

Works, but is slower.

```julia
# Xc .= wW .* Xdata[iW] .+ (1.0 .- wW) .* getindex.((Xdata, ), iW .+ 1)

julia> main() # tuple trick
  8.547 ms (0 allocations: 0 bytes)

julia> main() # Ref broadcasting
  8.266 ms (1 allocation: 16 bytes)

```

I mean, it’s de-facto standard (also mentioned in `?Ref`) to use `Ref` as wrapper in broadcasting and not tuples. I don’t know why but there seem to be some (performance) differences.

And 1 allocation with 16 Byte is really negligible in the context of those operations here. We’re talking about operations processing Megabytes of data.

---

<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: [December 8, 2021, 4:27pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/23 "2021-12-08T16:27:46Z")

</div>

Avoiding all allocations is critical in some cases. I must admit I am stunned that `Ref` allocates, and yet is the idiomatic wrapper to avoid broadcast. That 16b ‘isn’t much’ is unpersuasive.

---

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [December 8, 2021, 4:30pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/24 "2021-12-08T16:30:44Z")

</div>

Yeah, I agree.  
In this specific case you could create the Ref wrapper outside of the hot for loop but that’s probably not elegant.

Maybe a broadcast expert such as @mbauman can provide more details?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [December 8, 2021, 4:47pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/25 "2021-12-08T16:47:26Z")

</div>

> [@Gravlax](#):
>
> ```julia
> iW .= Int64.(round.(trunc.( (Pc .- Pmin)./dP ) .+ 1)) # index of the west node is database
> wW .= 1.0 .- (Pc - Pdata[iW])./dP
> Xc .= wW .* Xdata[iW] .+ (1.0 .- wW) .* Xdata[iW.+1]
> 
> ```

Would be more efficient (both in time and memory) to just write a loop for this, to avoid 3 passes over the arrays, and the code will be simpler too. (Note also that the slices `Pdata[iW]`, `Xdata[iW]`, and `Xdata[iW.+1]` are making copies. That will go away if you write a loop.). You don’t need to bend over backwards in Julia to vectorize all of your code!

That is, try something like:

```julia
for i = 1:length(Pc)
    iW = trunc(Int, (Pc[i] - Pmin) / dP) + 1
    wW = 1 - (Pc[i] - Pdata[iW]) / dP
    Xc[i] = wW * Xdata[iW] + (1 - wW) * Xdata[iW + 1]
end

```

(A similar strategy applies more globally to your code as well. Why are you doing “vectorized” interpolation at all? Possibly the interpolation can be combined with another step in your code, to eliminate the need for `Pc` and `Xc` arrays in the first place.)

The whole strategy of splitting up a long computation into a sequence of small vectorized steps, each of which does a small operation in a loop and produces a new array, is a [suboptimal anti-pattern](https://julialang.org/blog/2017/01/moredots/#why_vectorized_code_is_not_as_fast_as_it_could_be) from languages (Matlab, Python, R) where loops are slow.

PS. There is no need to write constants as `1.0` — Julia will automatically promote mixed-precision operations. In fact, it is better to write `1 - x` than `1.0 - x`, because the latter automatically promotes the results to at least double precision, whereas the former will use the precision of `x` (e.g. so that you can run the calculation in either single or double precision depending on the type of the input).

---

<div class="post-metadata">

### Author: ![Gravlax](https://avatars.discourse-cdn.com/v4/letter/g/dbc845/32.png) [@Gravlax](https://discourse.julialang.org/u/Gravlax)
#### Post date: [December 8, 2021, 5:03pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/26 "2021-12-08T17:03:24Z")

</div>

Yes, in the end I did use a loop since it did not require additional allocation. Unfortunately I got used to write either long production C loop/if codes or short concise vectorised MATLAB prototypes. Suddenly Julia makes me sit in the middle and I indeed need to reconsider these ideas…

---

<div class="post-metadata">

### Author: ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)
#### Post date: [December 8, 2021, 5:06pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/27 "2021-12-08T17:06:24Z")

</div>

`Ref` is mutable whereas tuples are immutable; sometimes that can make it hard for Julia to avoid allocating (and yes, 16 bytes is what you’d see for a Ref allocating). Tuples aren’t zero-dimensional, though, so that can act less “scalar-like” than Ref in some situations.

---

<div class="post-metadata">

### Author: ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)
#### Post date: [December 8, 2021, 5:07pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/28 "2021-12-08T17:07:20Z")

</div>

Just as benchmark addition, a lot faster:

```julia
function Itp1D_for( Xc, Pc, iW, wW, Xdata, Pdata, dP, Pmin )
    for i = 1:length(Pc)
        iW = trunc(Int, (Pc[i] - Pmin) / dP) + 1
        wW = 1 - (Pc[i] - Pdata[iW]) / dP
        Xc[i] = wW * Xdata[iW] + (1 - wW) * Xdata[iW + 1]
    end
end

julia> main() # for loop
  5.749 ms (0 allocations: 0 bytes)

julia> main() # Ref broadcasting
  8.266 ms (1 allocation: 16 bytes)

```

---

<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: [December 8, 2021, 5:32pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/29 "2021-12-08T17:32:28Z")

</div>

> [@roflmaostc](#):
>
> `trunc(Int, (Pc[i] - Pmin) / dP)`

Shouldn’t this rather be

```julia
div(Pc[i] - Pmin, dP) 

```

---

<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: [December 8, 2021, 5:47pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/30 "2021-12-08T17:47:42Z")

</div>

And this is the kind of stuff where the OP can add a `@turbo`:

```julia
using LoopVectorization
function Itp1D( Xc, Pc, iW, wW, Xdata, Pdata, dP, Pmin )
    @turbo for i = 1:length(Pc)
        iW = trunc(Int, (Pc[i] - Pmin) / dP) + 1
        wW = 1 - (Pc[i] - Pdata[iW]) / dP
        Xc[i] = wW * Xdata[iW] + (1 - wW) * Xdata[iW + 1]
    end
end

```

```julia
julia> @btime main_noturbo()
  237.058 ms (16 allocations: 45.81 MiB)

julia> @btime main_turbo()
  81.057 ms (16 allocations: 45.81 MiB)

```

(I’m running OPs complete original code here)

---

<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: [December 8, 2021, 6:01pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/31 "2021-12-08T18:01:30Z")

</div>

Now do `@tturbo` 😁

---

<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: [December 8, 2021, 6:18pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/32 "2021-12-08T18:18:56Z")

</div>

```julia
julia> Threads.nthreads()
4

julia> @btime main()
  37.210 ms (16 allocations: 45.81 MiB)

```

---

<div class="post-metadata">

### Author: ![Gravlax](https://avatars.discourse-cdn.com/v4/letter/g/dbc845/32.png) [@Gravlax](https://discourse.julialang.org/u/Gravlax)
#### Post date: [December 8, 2021, 6:44pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/33 "2021-12-08T18:44:10Z")

</div>

Excellent, should one worry about:

```julia
16 allocations: 45.81 MiB

```

I mean would it add up if one call many more times the function?  
Why is there any allocation done there by the way?

---

<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: [December 8, 2021, 6:56pm UTC](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713/34 "2021-12-08T18:56:26Z")

</div>

There I benchmarked the complete code, including all the data definition, thus there is where those allocations are.

[Previous page](https://discourse.julialang.org/t/undesired-memory-allocation-during-interpolation/72713.md?page=1)
