# How do I make this allocation free?

**URL:** <https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306>\
**Category:** New to Julia\
**Created:** [January 21, 2023, 11:48am UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306 "2023-01-21T11:48:29Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 11:48am UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/1 "2023-01-21T11:48:29Z")

</div>

Hello!

Suppose I have the parameters:

```julia
using StaticArrays
using LinearAlgebra

h = 0.05
eta2 = (0.01)h * (0.01)h
points = rand(SVector{3,Float64},100000)
v = points * 0.05

```

And I wish to evaluate this expression:

```julia
 maximum(abs.(h* dot.(v,points) ./ (dot.(points,points) .+ eta2)))

```

Which currently gives me a timing of:

```julia
@btime visc = maximum(abs.($h* dot.($v,$points) ./ (dot.($points,$points) .+ $eta2)))
  442.800 μs (6 allocations: 2.29 MiB)
0.0024999997855364884

```

The speed is really good, but I just don’t understand why it is allocating 2 mb and how I avoid that?

Kind regards

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [January 21, 2023, 12:01pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/2 "2023-01-21T12:01:23Z")

</div>

your missing a `.` on the first `*`.

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 12:06pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/3 "2023-01-21T12:06:41Z")

</div>

Thank you, this reduces it to:

```julia
@btime visc = maximum(abs.($h .* dot.($v,$points) ./ (dot.($points,$points) .+ $eta2)))
  273.000 μs (2 allocations: 781.30 KiB)
0.0024999997855364884

```

So a third. Anything else I perhaps might be missing?

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 12:09pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/4 "2023-01-21T12:09:15Z")

</div>

I just don’t understand why this would allocate at all since it reduces down to one scalar value?

Is there some intermediate array which is not being cleaned up properly?

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [January 21, 2023, 12:09pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/5 "2023-01-21T12:09:40Z")

</div>

Use the form of maximum that takes a function as the first argument, and / or make a generator expression out of the broadcast because that needs to create an array right now

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 12:26pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/6 "2023-01-21T12:26:05Z")

</div>

Sorry, I don’t understand. I see the syntax:

```julia
maximum(abs2, A, dims=1)

```

But I can’t see how to convert my example into that. I tried:

```julia
f() = abs.(h .* dot.(v,points) ./ (dot.(points,points) .+ eta2))

```

And then maximum of that, but that did the same of course 🙂

Could you explain more please?

Kind regards

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://discourse.julialang.org/u/jules)\
**Post date:** [January 21, 2023, 12:54pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/7 "2023-01-21T12:54:59Z")

</div>

You’re iterating over `points` and `v` but for a maximum to be determined, not all of the results need to be stored in a vector at the same time. It is enough to compute one by one. So either you make a function to call on each element of the collection you’re interested in, or you use a generator expression which also only ever computes one element at a time. As you have two collections I use `zip` here, you’d do the same for the functional version a la `maximum(f, zip(points, v))`:

```julia
julia> @btime maximum(abs($h * dot(_v, p) / (dot(p, p) + $eta2)) for (p, _v) in zip($points, $v))
  2.237 ms (0 allocations: 0 bytes)
0.002499999788221453

```

The functional version:

```julia
julia> @btime maximum(zip($points, $v)) do (p, _v)
           abs($h * dot(_v, p) / (dot(p, p) + $eta2))
       end
  2.173 ms (0 allocations: 0 bytes)
0.002499999788221453

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [January 21, 2023, 1:13pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/8 "2023-01-21T13:13:25Z")

</div>

If you use `mapreduce` instead of `maximum`, then you don’t have to use `zip`. Something like this:

```julia
@btime mapreduce((p, _v) -> abs($h * dot(_v, p) / (dot(p, p) + $eta2)), max, $points, $v)

```

BTW, some obvious performance suggesions:

1. Always use functions: the first suggestion in the performance tips: [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/)
2. Try to provide the `init` keyword argument to `mapreduce` and related functions.

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 3:44pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/9 "2023-01-21T15:44:39Z")

</div>

Thank you @jules and @nsajko !

Benchmarking both approaches:

```julia
 @btime maximum(zip($points, $v)) do (p, _v)
                  abs($h * dot(_v, p) / (dot(p, p) + $eta2))
                         end
  1.323 ms (0 allocations: 0 bytes)
0.002499999786538688

@btime mapreduce((p, _v) -> abs($h * dot(_v, p) / (dot(p, p) + $eta2)), max, $points, $v)
  1.296 ms (2 allocations: 781.30 KiB)
0.002499999786538688

```

The zip approach still seems to work better, perhaps something can be improved in the map-reduce?

Neat knowing both ways though!

Both ways are about 6 times slower though:

```julia
@btime visc = maximum(abs.($h .* dot.($v,$points) ./ (dot.($points,$points) .+ $eta2)))
  286.900 μs (2 allocations: 781.30 KiB)
0.002499999786538688

```

And I am not sure why 🙂 Could someone elaborate for me?

Kind regards

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 3:52pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/10 "2023-01-21T15:52:35Z")

</div>

By the way, thank you so much for showing me this approach!

It gives me a completely allocation free time stepping function since I am using the principle you just showed me:  
 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/a/6a8b7e7f054aec3042d271d9b71b02b05e713755.png)

And that seems to give faster end result, even if the benchmark test is slower - a bit confusing for me, but really happy for you and @nsajko taking the time to show me how one could approach it 🙂

Kind regards

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [January 21, 2023, 4:04pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/11 "2023-01-21T16:04:07Z")

</div>

> [@Ahmed\_Salih](#):
>
> Benchmarking both approaches

Benchmarking like that is kind of pointless. The proper procedure would be organize your code into functions and then benchmark like so:

```julia
@benchmark your_function(arg1, arg2, arg3) setup=(arg1 = INIT1; arg2 = INIT2; arg3 = INIT3;)

```

We can’t organize your code into functions for you, because:

1. We’d need to have access to your entire code to understand the choices and find best design.
2. It’d be too much work for helping someone I don’t know

If you have some more specific questions, though, feel free to open new threads here in this forum.

---

<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:** [January 21, 2023, 5:20pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/12 "2023-01-21T17:20:58Z")

</div>

You can always just write the straight loop:

```julia
julia> function maxvp(v,points,h,eta2)
           maxval = -Inf
           for i in eachindex(v,points)
                maxval = max(maxval, abs(h * dot(v[i],points[i]) / (dot(points[i],points[i]) + eta2)))
           end
           return maxval
       end
maxvp (generic function with 1 method)

julia> @btime maxvp($v,$points,$h,$eta2)
  351.774 μs (0 allocations: 0 bytes)
0.002499999787200059

```

If you add `@fastmath` to `maxval = ...`, time reduces by roughly 2.

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 5:22pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/13 "2023-01-21T17:22:22Z")

</div>

True, I tried that but it became way to slow, since I used an “if branch” instead of what you are doing with max 🙂

Thank you for showing it to me!

Kind regards

---

<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:** [January 21, 2023, 5:26pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/14 "2023-01-21T17:26:18Z")

</div>

> [@Ahmed\_Salih](#):
>
> True, I tried that but it became way to slow, since I used an “if branch” instead of what you are doing with max

That does not really makes sense. Probably is something not being benchmarked correctly.

---

<div class="post-metadata">

**Author:** ![ademonts](https://avatars.discourse-cdn.com/v4/letter/a/ba8739/32.png) [@ademonts](https://discourse.julialang.org/u/ademonts)\
**Post date:** [January 21, 2023, 5:34pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/15 "2023-01-21T17:34:34Z")

</div>

You can get another bit of speed like:

```julia
julia> function maxvp_2(v,points,h,eta2)
          maxval = -Inf
          for i in eachindex(v,points)
               tmp = abs(h * dot(v[i],points[i]) / (dot(points[i],points[i]) + eta2))
               tmp > maxval && (maxval = tmp)
          end
          return maxval
       end
maxvp_2 (generic function with 1 method)

julia> @btime maxvp($v,$points,$h,$eta2)
  244.788 μs (0 allocations: 0 bytes)
0.002499999783527899

julia> @btime maxvp_2($v,$points,$h,$eta2)
  136.531 μs (0 allocations: 0 bytes)
0.002499999783527899

```

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 21, 2023, 5:46pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/16 "2023-01-21T17:46:23Z")

</div>

> [@ademonts](#):
>
> ```julia
> function maxvp_2(v,points,h,eta2)
> maxval = -Inf
> for i in eachindex(v,points)
> tmp = abs(h * dot(v[i],points[i]) / (dot(points[i],points[i]) + eta2))
> tmp > maxval && (maxval = tmp)
> end
> return maxval
> end
> 
> ```

Thank you!

That did give an extra boost yes 🙂 Of course now it is getting down to extremely small performance benefits, so probably best to stop improving it now hehe

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [January 21, 2023, 7:59pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/17 "2023-01-21T19:59:24Z")

</div>

you can also try this 😇

```julia
julia> maxvp_3(v,points,h,eta2)=0.00249999978
maxvp_3 (generic function with 1 method)

julia> @btime maxvp_3($v,$points,$h,$eta2)
  1.100 ns (0 allocations: 0 bytes)
0.00249999978

```

this isn’t fast, but it doesn’t allocate

```julia
julia> @btime maximum(abs, Iterators.map((e,p)-> ($h* dot(e,p) / (dot(p,p) + $eta2)),$v,$points))
  1.399 ms (0 allocations: 0 bytes)
0.0024999997831612647

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [January 21, 2023, 11:40pm UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/18 "2023-01-21T23:40:08Z")

</div>

Seems related:

> [@Range (statistics)](https://discourse.julialang.org/t/range-statistics/92518/13):
>
> Can you take a look at Base.extrema and see if you can tell what, if anything, is wrong with it, performance-wise? Because I really think the right approach is to use extrema for this, and fix any problems there.

TLDR: performance of `maximum` has a lot of room for improvement, and there is an [ongoing effort](https://github.com/JuliaLang/julia/pull/45581) to fix it.

---

<div class="post-metadata">

**Author:** ![Ahmed\_Salih](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ahmed_salih/32/206579_2.png) [@Ahmed\_Salih](https://discourse.julialang.org/u/Ahmed_Salih)\
**Post date:** [January 22, 2023, 6:45am UTC](https://discourse.julialang.org/t/how-do-i-make-this-allocation-free/93306/19 "2023-01-22T06:45:35Z")

</div>

Thank you for making me aware. Indeed seems to be the case that the most straight forward approach from a function perspective is not yet developed enough for performance

Kind regards
