# Timeseries Optimization : Reducing allocations

**URL:** <https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251>\
**Category:** Performance\
**Created:** [May 16, 2021, 5:02pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251 "2021-05-16T17:02:28Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![EdgarHR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/edgarhr/32/25148_2.png) [@EdgarHR](https://discourse.julialang.org/u/EdgarHR)\
**Post date:** [May 16, 2021, 5:02pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/1 "2021-05-16T17:02:28Z")

</div>

Hello everyone!

I was working on a project and wanted to start reformatting the code to make it faster. As part of this process I am working on reducing the amount of allocations as much as possible. Currently I have a function that takes in a vector and another function, `myfunc`. Then inside a for loop I call `myfunc` on a subset of the input vector. After playing around with benchmark tools I noticed that allocations are being made when calling `myfunc` and inside `myfunc`. My is structured as follows,

```julia
function eval(timeseries::Vector{Float64}, myfunc)
    for i in 1:length(timeseries)
        alpha = myfunc(timeseries[1:i])
    end
end

```

I tried running it using `myfunc = rand(1)[1]` and was surprised by how many allocations were made. I guessing there is no way to reduce the `myfunc` random integer allocations, but maybe there is a way to reduce the allocations from `myfunc(timeseries[1:i])`. I’m new to this whole optimization stuff, so maybe what I’m trying to do is simply impossible.

Anyway, thank you for taking the time to read this! Any feedback about optimization tips or how I might restructure my code would be greatly appreciated!

---

<div class="post-metadata">

**Author:** ![affans](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/affans/32/11911_2.png) [@affans](https://discourse.julialang.org/u/affans)\
**Post date:** [May 16, 2021, 5:22pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/2 "2021-05-16T17:22:52Z")

</div>

If the allocations are in `myfunc` you’d need to post some code for folks to try to figure out whats happening.

---

<div class="post-metadata">

**Author:** ![EdgarHR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/edgarhr/32/25148_2.png) [@EdgarHR](https://discourse.julialang.org/u/EdgarHR)\
**Post date:** [May 16, 2021, 5:35pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/3 "2021-05-16T17:35:57Z")

</div>

Yeah for sure. I was testing out with `myfunc` equal to `random(timeseries) = rand(1)[1]`. In the future i would like to replace `myfunc` with some arbitrary function so I was wondering if there was a better way to re-write my code to avoid the allocations from `myfunc(timeseries[1:i])`

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 16, 2021, 5:43pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/4 "2021-05-16T17:43:15Z")

</div>

> [@EdgarHR](#):
>
> `timeseries[1:i]`

This statement allocates a _copy_ of that subset of `timeseries`, which explains at least some of your allocation issues. Try `@view timeseries[1:i]` to create a lightweight view instead, and see [Performance Tips · The Julia Language](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-views) for more info.

---

<div class="post-metadata">

**Author:** ![DaymondLing](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/daymondling/32/8474_2.png) [@DaymondLing](https://discourse.julialang.org/u/DaymondLing)\
**Post date:** [May 16, 2021, 5:52pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/5 "2021-05-16T17:52:43Z")

</div>

Here are two things to keep in mind when indexing (since Julia 1.5) and looping:

1. normal indexing `v[i,j]` copies data (allocation), use views `@view v[i,j]` to create view to underlying elements (no allocation). Use `@views` for a block of code instead of a single indexing operation.

2. normal loops `for i=1:j` generates code with bounds checking. If you are sure your code will always stay inbound, use `@inbounds for i=1:j`

Using a dummy function,

```julia
ts = rand(100)

function test1(ts)
    for i = 1:length(ts)
        dummy(ts[1:i])
    end
end

function test2(ts)
    for i = 1:length(ts)
        dummy(@view ts[1:i])
    end
end

function test3(ts)
    @inbounds for i = 1:length(ts)
        dummy(@view ts[1:i])
    end
end

function dummy(ts)
end

```

`test1` shows 100 allocations

```julia
julia> @benchmark test1($ts)
BenchmarkTools.Trial: 
  memory estimate: 49.06 KiB
  allocs estimate: 100
  --------------
  minimum time: 6.150 μs (0.00% GC)
  median time: 8.975 μs (0.00% GC)
  mean time: 9.879 μs (7.94% GC)
  maximum time: 203.525 μs (90.07% GC)
  --------------
  samples: 10000
  evals/sample: 4

```

`test2` has 0 allocations

```julia
julia> @benchmark test2($ts)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 65.000 ns (0.00% GC)
  median time: 65.102 ns (0.00% GC)
  mean time: 65.300 ns (0.00% GC)
  maximum time: 79.490 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 980

```

`test3` has 0 allocations and is faster than test2

```julia
julia> @benchmark test3($ts)
BenchmarkTools.Trial: 
  memory estimate: 0 bytes
  allocs estimate: 0
  --------------
  minimum time: 2.000 ns (0.00% GC)
  median time: 2.100 ns (0.00% GC)
  mean time: 2.130 ns (0.00% GC)
  maximum time: 25.200 ns (0.00% GC)
  --------------
  samples: 10000
  evals/sample: 1000

```

The best source of these tips is [Julia documentation performance tips](https://docs.julialang.org/en/v1/manual/performance-tips/).

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [May 16, 2021, 6:00pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/6 "2021-05-16T18:00:59Z")

</div>

All good points, but note that those benchmarks are somewhat misleading–in particular, your last example gives a 2ns result for iteration over 100 elements, which would mean each iteration takes about 1/10 of a clock cycle. That’s probably not what’s actually happening–more likely the compiler has optimized the entire loop into nothing, since it doesn’t actually _do_ anything. If you increase the length of `ts`, you’ll notice that the runtime is constant, further demonstrating that the compiler has defeated the benchmark.

`@view` and `@inbounds` are still good tools, but `@inbounds` won’t generally improve your actual code speed by a factor of 30.

---

<div class="post-metadata">

**Author:** ![EdgarHR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/edgarhr/32/25148_2.png) [@EdgarHR](https://discourse.julialang.org/u/EdgarHR)\
**Post date:** [May 16, 2021, 6:01pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/7 "2021-05-16T18:01:19Z")

</div>

Thank you for your suggestion rdeits! I’ll be sure to do that. Based on what I’ve been reading it seems that I’ll also have to be careful that `myfunc` doesnt modify `timeseries` in the future.

---

<div class="post-metadata">

**Author:** ![EdgarHR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/edgarhr/32/25148_2.png) [@EdgarHR](https://discourse.julialang.org/u/EdgarHR)\
**Post date:** [May 16, 2021, 6:05pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/8 "2021-05-16T18:05:56Z")

</div>

Thank you @DaymondLing for your suggestions and again @rdeits for the for the followup! Another technique I used was `@code_warntype` to make sure my types were stable.

---

<div class="post-metadata">

**Author:** ![jebej](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jebej/32/1784_2.png) [@jebej](https://discourse.julialang.org/u/jebej)\
**Post date:** [May 16, 2021, 6:49pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/9 "2021-05-16T18:49:38Z")

</div>

If you are passing a function as an argument, you could try forcing specialization with a type parameter.

---

<div class="post-metadata">

**Author:** ![DaymondLing](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/daymondling/32/8474_2.png) [@DaymondLing](https://discourse.julialang.org/u/DaymondLing)\
**Post date:** [May 16, 2021, 7:48pm UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/10 "2021-05-16T19:48:38Z")

</div>

Yes, of course, the code merely shows the compiler removes bounds check and could result in some time savings, YMMV obviously.

---

<div class="post-metadata">

**Author:** ![EdgarHR](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/edgarhr/32/25148_2.png) [@EdgarHR](https://discourse.julialang.org/u/EdgarHR)\
**Post date:** [May 18, 2021, 6:25am UTC](https://discourse.julialang.org/t/timeseries-optimization-reducing-allocations/61251/11 "2021-05-18T06:25:55Z")

</div>

Thank you @jebej! I’ll take a look into it
