# Memory allocation and usage of dot notation

**URL:** https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951
**Category:** Performance
**Tags:** question
**Created:** [October 19, 2022, 9:31am UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951 "2022-10-19T09:31:23Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![dgegen](https://avatars.discourse-cdn.com/v4/letter/d/f4b2a3/32.png) [@dgegen](https://discourse.julialang.org/u/dgegen)
#### Post date: [October 19, 2022, 9:31am UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/1 "2022-10-19T09:31:23Z")

</div>

The article [Performance Tips](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-tips) advises to pay attention to memory allocation when trying to evaluate or improve the efficiency of a program. This made me wonder whether the **estimated number of allocations** or the **estimated memory consumption** is the more meaningful quantity in this respect (or if this is a meaningless question and they should always be considered jointly).

In trying to find out, I produced the following result.

```julia
using BenchmarkTools

function fun(x)
    return @. 2*x^5 + 3*x^2 + sqrt(x) + 10.0 + x^1/5
end

x = rand(Float64, 100_000)

@btime fun.(x);
# 723.400 μs (5 allocations: 781.36 KiB)
@btime fun(x);
# 755.700 μs (2 allocations: 781.30 KiB)

```

If I have used `@btime` correctly, this seems to indicate that the second function call with a smaller estimated number of allocations is slower than the first, which I find rather counter-intuitive. This would imply that in some cases the number of assignments is of no concern when evaluating the speed of a function. Does anyone have a good explanation of why this is the case in this particular example or general advice on what quantities I should focus on when benchmarking using `@btime`?  
Many thanks in advance!

---

<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: [October 19, 2022, 10:53am UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/2 "2022-10-19T10:53:17Z")

</div>

> [@dgegen](#):
>
> `@btime fun.(x);`

`x` is a non-`const` global variable here. That can often influence benchmarking, though it is somewhat unpredictable when it will happen. Try interpolating the variable with `$`:

```julia
julia> @btime fun($x);
  641.000 μs (2 allocations: 781.30 KiB)

julia> @btime fun.($x);
  518.600 μs (2 allocations: 781.30 KiB)

```

The difference in allocations disappeared, but there is a clear performance difference, I don’t know why.

---

<div class="post-metadata">

### Author: ![dgegen](https://avatars.discourse-cdn.com/v4/letter/d/f4b2a3/32.png) [@dgegen](https://discourse.julialang.org/u/dgegen)
#### Post date: [October 19, 2022, 2:09pm UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/3 "2022-10-19T14:09:21Z")

</div>

Thanks for the advise! Good to at least see the difference in allocations disappear. 🙂

---

<div class="post-metadata">

### Author: ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)
#### Post date: [October 19, 2022, 2:29pm UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/4 "2022-10-19T14:29:13Z")

</div>

> [@dgegen](#):
>
> This made me wonder whether the **estimated number of allocations** or the **estimated memory consumption** is the more meaningful quantity

The ideal is 0 allocations, so it doesn’t matter to know (or some low fixed number, when you see e.g. 2, then it may be artifact of using in the REPL, and will go to 0).

Sometimes type-instability is ok, thus allocations, and not all code is speed-critical. I would look at the timings first to see if I need to worry (for a realistic-sized workload). If you want the fastest code, and it’s often not easy to know the performance ceiling of code, if you have any allocations then it’s a good indicator you haven’t reacted it.

---

<div class="post-metadata">

### Author: ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)
#### Post date: [October 19, 2022, 3:07pm UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/5 "2022-10-19T15:07:03Z")

</div>

> [@dgegen](#):
>
> `x^1/5`

This parses as `(x^1)/5`. I’m guessing that you intended `x^(1/5)`.

---

<div class="post-metadata">

### Author: ![fins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fins/32/43444_2.png) [@fins](https://discourse.julialang.org/u/fins)
#### Post date: [October 19, 2022, 6:14pm UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/6 "2022-10-19T18:14:58Z")

</div>

> [@dgegen](#):
>
> `@btime fun.(x);`

…apart from interpolating (pointed out, already)…

```julia
julia> @btime fun($x)
  690.700 μs (2 allocations: 781.30 KiB)
100000-element Vector{Float64}:

```

…I would _also_ always consider, whether you really still need the input (original vector x, in this case), or if you “only” need the results, to continue with whatever you’re doing, after calling that function. If only the result is needed, I’d reuse that already existing memory, like so (disclaimer: I’m new to julia, so maybe there’s a more elegant way):

```julia
function fun2!(x::Vector{Float64})
    @. x .= 2*x^5 + 3*x^2 + sqrt(x) + 10.0 + x^1/5
end

```

```julia
julia> @btime fun2!($x)
  552.700 μs (0 allocations: 0 bytes)
100000-element Vector{Float64}:

```

…it may only be some 20% performance-improvement, in this case, but can be more dramatic in other cases, when you’re operating on larger data, I think.

And while the number of allocations might hint at _where_ memory is being allocated (i.e. how often), I would pay more attention to the amount. In this case, the original version allocated 781.3 KiB = 781.3 x 1024 Bytes, which is exactly 800.000 Bytes, which tells you that it allocated _exactly_ the amount of memory, needed to store the result of the fct. for 100.000 x `Float64` (8B, each). Why it is saying “2 allocations” and not just one, I have no idea, though.

---

<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: [October 19, 2022, 6:35pm UTC](https://discourse.julialang.org/t/memory-allocation-and-usage-of-dot-notation/88951/7 "2022-10-19T18:35:59Z")

</div>

Just for the records, usually the idiomatic way to do this in Julia is to write a scalar function, and broadcast it, in place, or not:

```julia
julia> f(x) = 2*x^5 + 3*x^2 + sqrt(x) + 10.0 + x^(1/5)
f (generic function with 1 method)

julia> x = rand(10^5);

julia> @btime $x .= f.($x);
  588.600 μs (0 allocations: 0 bytes)

julia> @btime y = f.($x);
  612.474 μs (2 allocations: 781.30 KiB)

```
