# Speeding up a function

**URL:** <https://discourse.julialang.org/t/speeding-up-a-function/102703>\
**Category:** Performance\
**Tags:** performance\
**Created:** [August 11, 2023, 7:11am UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703 "2023-08-11T07:11:28Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [August 11, 2023, 3:09pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/22 "2023-08-11T15:09:13Z")

</div>

> **[Roofline model](https://en.wikipedia.org/wiki/Roofline_model)**
>
> The Roofline model is an intuitive visual performance model used to provide performance estimates of a given compute kernel or application running on multi-core, many-core, or accelerator processor architectures, by showing inherent hardware limitations, and potential benefit and priority of optimizations. By combining locality, bandwidth, and different parallelization paradigms into a single performance figure, the model can be an effective alternative to assess the quality of attained performan...

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 11, 2023, 3:22pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/23 "2023-08-11T15:22:34Z")

</div>

Thanks, I am going to watch some videos about it as well.

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 11, 2023, 3:37pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/24 "2023-08-11T15:37:30Z")

</div>

I do not know if you care, however, Laurent’s function below is more accurate, in the sense, that the result is always the same. If I replace Laurent’s foo function with Elrods foo\_polyester! version, my function produces slightly different results every time I run it.  
That being said, Elrod’s function improves speed from 75 to 60ms but I need the accuracy.

> [@LaurentPlagne](#):
>
> ```julia
> function foo!(num,market_ids)
> @inbounds for id ∈ market_ids
> @views s = sum(num[id,:])
> @views num[id,:] ./= s+1
> end
> end
> 
> ```

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [August 11, 2023, 3:39pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/25 "2023-08-11T15:39:13Z")

</div>

Here is an analogy that I use for // lecture :

Let’s imagine a tailoring workshop where

- `nc` seamstresses make clothes and
- `nt` carriers bring the fabric and deliver the clothes.

Two questions :

If the seamstresses are often out of work because the fabric does not arrive or the finished clothes are slow to be delivered: should we add seamstresses? (_memory bound_)

If a given type of clothes requires a lot of work time and little fabric and all the seamstresses are used to the maximum, should we add seamstresses? (_compute bound_)

Conclusion #1 :

Parallelizable algorithms are characterized by their `arithmetic intensity` which measures the ratio amount of work / amount of data to read and write from/to RAM.

Conclusion #2: the exponential is the wedding dress of parallelism 😉

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 11, 2023, 3:42pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/26 "2023-08-11T15:42:14Z")

</div>

hahahah I love that analogy, that makes a lot of sense to me. And arithmetic intensity depends on the function and on the number of threads to cores? Then, I will try to measure the intensity and maybe I can find a way to optimize the level of it.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [August 11, 2023, 3:48pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/27 "2023-08-11T15:48:19Z")

</div>

> [@ditfurth](#):
>
> arithmetic intensity depends on the function and on the number of threads to cores?

The A.I. depends only on the function (not on the threads/core which are the seamstresses).

For a given algorithm/function one must minimize the RAM traffic and reuse the data that fit in cache (spatial and temporal data locality).  
One should also try to group the computation in a minimum set of parallel sections (kernel fusion).

---

<div class="post-metadata">

**Author:** ![mihalybaci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mihalybaci/32/13528_2.png) [@mihalybaci](https://discourse.julialang.org/u/mihalybaci)\
**Post date:** [August 11, 2023, 3:58pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/28 "2023-08-11T15:58:54Z")

</div>

I don’t know if it will help speed, but as a style note (my style), `@view` is typically used line-by-line for indicating a view, while `@views` (plural) will transform all slices in a code block into views. So you could remove all the `@views` inside the function and instead delcare the whole thing use views with `@views function predict_shares_bern(...` unless there is a slice that you _do_ want to make a copy.

---

<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:** [August 11, 2023, 4:09pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/29 "2023-08-11T16:09:12Z")

</div>

> [@ditfurth](#):
>
> `(vec_1 .= vec_1 .* (exp(nu_bern)/(1+exp(nu_bern))) +vec(mean(mat_1_t, dims = 1)) .* (1 - (exp(nu_bern)/(1+exp(nu_bern)))))`

Try eliminating the common subexpression (`e = exp(nu_bern)`) manually, I don’t think that Julia is able to do that yet.

I just submitted an issue to the Github, btw:

> <https://github.com/JuliaLang/julia/issues/50887>
>
> exp.jl:
> \`\`\`julia
> using BenchmarkTools
> 
> f(x) = exp(x)/(1+exp(x))
> 
> function …g(x)
> e = exp(x)
> e/(1 + e)
> end
> 
> h!(f::F, v) where {F} = map!(f, v, v)
> 
> @btime h!(f, v) setup=(v = rand(1 \<\< 10);)
> @btime h!(g, v) setup=(v = rand(1 \<\< 10);)
> 
> nothing
> \`\`\`
> 
> \`\`\`julia-repl
> julia\> include("/tmp/exp.jl")
> 9.648 μs (0 allocations: 0 bytes)
> 5.009 μs (0 allocations: 0 bytes)
> 
> julia\> Base.infer\_effects(exp, (Float64,))
> (+c,+e,+n,+t,+s,+m,+i)
> 
> julia\> @code\_lowered f(0.3)
> CodeInfo(
> 1 ─ %1 = Main.exp(x)
> │ %2 = Main.exp(x)
> │ %3 = 1 + %2
> │ %4 = %1 / %3
> └── return %4
> )
> 
> julia\> @code\_llvm f(0.3)
> ; Function Signature: f(Float64)
> ; @ /tmp/exp.jl:3 within \`f\`
> define double @julia\_f\_3383(double %"x::Float64") #0 {
> top:
> %0 = call double @j\_exp\_3387(double %"x::Float64")
> %1 = call double @j\_exp\_3387(double %"x::Float64")
> ; ┌ @ promotion.jl:422 within \`+\` @ float.jl:404
> %2 = fadd double %1, 1.000000e+00
> ; └
> ; ┌ @ float.jl:407 within \`/\`
> %3 = fdiv double %0, %2
> ; └
> ret double %3
> }
> 
> julia\> versioninfo()
> Julia Version 1.11.0-DEV.262
> Commit 2c0e1d87e73 (2023-08-11 14:14 UTC)
> Build Info:
> Official https://julialang.org/ release
> Platform Info:
> OS: Linux (x86\_64-linux-gnu)
> CPU: 8 × AMD Ryzen 3 5300U with Radeon Graphics
> WORD\_SIZE: 64
> LLVM: libLLVM-15.0.7 (ORCJIT, znver2)
> Threads: 1 on 8 virtual cores
> \`\`\`

---

<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:** [August 11, 2023, 4:15pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/30 "2023-08-11T16:15:29Z")

</div>

> [@ditfurth](#):
>
> `1 - (exp(nu_bern)/(1+exp(nu_bern)))`

Note that 1 - \frac{exp(x)}{1 + {exp(x)}} is equivalent to simply \frac{1}{1 + {exp(x)}}.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [August 11, 2023, 4:37pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/31 "2023-08-11T16:37:13Z")

</div>

Also it will be more accurate (especially for large negative x)

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 11, 2023, 8:09pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/32 "2023-08-11T20:09:48Z")

</div>

Ok, got it, thanks!

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 11, 2023, 8:10pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/33 "2023-08-11T20:10:01Z")

</div>

Ok, thanks both!

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 11, 2023, 8:10pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/34 "2023-08-11T20:10:24Z")

</div>

Thanks, will look into it!

---

<div class="post-metadata">

**Author:** ![BioinfoBuggaBoo](https://avatars.discourse-cdn.com/v4/letter/b/a9a28c/32.png) [@BioinfoBuggaBoo](https://discourse.julialang.org/u/BioinfoBuggaBoo)\
**Post date:** [August 13, 2023, 10:23pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/35 "2023-08-13T22:23:19Z")

</div>

I know this isn’t an educational forum per se, but would you be willing to elaborate on, ‘use $ to interpolate @benchmark arguments’, by any chance?

---

<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:** [August 13, 2023, 10:43pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/36 "2023-08-13T22:43:47Z")

</div>

Your question is fine.

First see the _[Avoid untyped global variables](https://docs.julialang.org/en/v1/manual/performance-tips/#Avoid-untyped-global-variables)_ section in the performance tips for context.

Regarding `@benchmark`, specifically, see: _[Interpolating values into benchmark expressions](https://juliaci.github.io/BenchmarkTools.jl/stable/manual/#Interpolating-values-into-benchmark-expressions)_ and _[Quick Start](https://github.com/JuliaCI/BenchmarkTools.jl#quick-start)_.

Expression interpolation itself is documented in Julia’s Manual in the page on Metaprogramming: _[Interpolation](https://docs.julialang.org/en/v1/manual/metaprogramming/#man-expression-interpolation)_.

But note that interpolation is only necessary if your benchmark depends on global variables: depending on, e.g., constants and functions is fine.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [August 13, 2023, 10:46pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/37 "2023-08-13T22:46:50Z")

</div>

Also interpolating variables into the benchmark typically only matters if your function takes \<100ns or so.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [August 13, 2023, 10:47pm UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/38 "2023-08-13T22:47:59Z")

</div>

On my laptop (apple M1 Max) this version is more than 3x faster for n=200000 and looks accurate:

```julia
julia> main()
  93.055 ms (110 allocations: 7.64 MiB) #predict_shares_bern_5_t
  22.784 ms (306 allocations: 4.60 MiB) #predict_shares_bern_7_t

```

```julia
@views @inbounds function foo_t!(num,market_ids)
    Threads.@threads for id ∈ market_ids
        s = sum(num[:,id])
        num[:,id] ./= s+1
    end
end

@inbounds function bar_t!(mat_1_t,randvar_nu_t,delta)
    ni,nj = size(mat_1_t)
    Threads.@threads for j ∈ 1:nj
        @turbo for i ∈ 1:ni
            mat_1_t[i,j] = exp(randvar_nu_t[i,j] + delta[j] )
        end
    end
end

@views @inbounds function mean_t!(vec_1,mat_1_t)
    Threads.@threads for j ∈ eachindex(vec_1)
        vec_1[j] = mean(mat_1_t[:,j]) 
    end
end

function predict_shares_bern_7_t(delta, randvar_nu_t, randvar_nu_inattention_t, mat_1_t, vec_1, vec_2, market_ids, nu_bern)
    bar_t!(mat_1_t,randvar_nu_t,delta)
    foo_t!(mat_1_t, market_ids)
    mean_t!(vec_1,mat_1_t)
    bar_t!(mat_1_t,randvar_nu_inattention_t,delta)
    foo_t!(mat_1_t, market_ids)
    mean_t!(vec_2,mat_1_t)

    ee = (exp(nu_bern)/(1+exp(nu_bern)))
    vec_1 .= vec_1 .* ee + vec_2 .* (1 - ee)
    return vec_1
end

```

> **complete code**
>
> ```julia
> using BenchmarkTools, Random, Distributions, ProfileView, LoopVectorization
> 
> function predict_shares_bern_5_t(delta, randvar_nu_t, randvar_nu_inattention_t, mat_1_t, vec_1, market_ids, nu_bern)
> ni = size(mat_1_t,1)
> nj = size(mat_1_t,2)
> @tturbo for i in 1:ni, j in 1:nj
> mat_1_t[i,j] = exp(randvar_nu_t[i,j] + delta[j] )
> end
> 
> Threads.@threads for id in market_ids
> @views sumj = sum(mat_1_t[:,id])
> for i ∈ 1:ni
> mat_1_t[i,id] = mat_1_t[i , id] / (sumj+1)
> end
> end
> 
> vec_1 .= vec(mean(mat_1_t, dims = 1))
> 
> @tturbo for i in 1:ni, j in 1:nj
> mat_1_t[i,j] = exp(randvar_nu_inattention_t[i,j] + delta[j] )
> end
>     
> Threads.@threads for id in market_ids
> @views sumj = sum(mat_1_t[:,id])
> for i ∈ 1:ni
> mat_1_t[i,id] = mat_1_t[i,id] / (sumj+1)
> end
> end
> share = (vec_1 .= vec_1 .* (exp(nu_bern)/(1+exp(nu_bern))) +vec(mean(mat_1_t, dims = 1)) .* (1 - (exp(nu_bern)/(1+exp(nu_bern)))))
> return share
> end
> 
> @views @inbounds function foo_t!(num,market_ids)
> Threads.@threads for id ∈ market_ids
> @views s = sum(num[:,id])
> @views num[:,id] ./= s+1
> end
> end
> 
> @inbounds function bar_t!(mat_1_t,randvar_nu_t,delta)
> ni,nj = size(mat_1_t)
> Threads.@threads for j ∈ 1:nj
> @turbo for i ∈ 1:ni
> mat_1_t[i,j] = exp(randvar_nu_t[i,j] + delta[j] )
> end
> end
> end
> 
> @views @inbounds function mean_t!(vec_1,mat_1_t)
> Threads.@threads for j ∈ eachindex(vec_1)
> vec_1[j] = mean(mat_1_t[:,j]) 
> end
> end
> 
> function predict_shares_bern_7_t(delta, randvar_nu_t, randvar_nu_inattention_t, mat_1_t, vec_1, vec_2, market_ids, nu_bern)
> bar_t!(mat_1_t,randvar_nu_t,delta)
> foo_t!(mat_1_t, market_ids)
> mean_t!(vec_1,mat_1_t)
> bar_t!(mat_1_t,randvar_nu_inattention_t,delta)
> foo_t!(mat_1_t, market_ids)
> mean_t!(vec_2,mat_1_t)
> 
> ee = (exp(nu_bern)/(1+exp(nu_bern)))
> vec_1 .= vec_1 .* ee + vec_2 .* (1 - ee)
> return vec_1
> end
> 
> function main()
> n = 200000
> markets::Int64 = 200
> Random.seed!(123)
> market_ids = repeat(1:1000,markets)
> market_ids_t = transpose(market_ids)
> delta = rand(Normal(1,5), n)
> log_share = rand(Normal(1,5), n)
> log_share_outside = rand(Normal(1,5), n)
> 
> nu_bern = -1
> randvar_nu = randn(n,100)*5 .+ 6
> randvar_nu_t = transpose(randvar_nu)
> randvar_nu_inattention= randn(n,100)*5 .+ 6.5
> randvar_nu_inattention_t = transpose(randvar_nu_inattention)
> mat_1 = similar(randvar_nu)
> mat_1_t = similar(randvar_nu_t)
> vec_1 = similar(delta)
> vec_2 = similar(delta)
> 
> s5t = predict_shares_bern_5_t(delta, randvar_nu_t, randvar_nu_inattention_t, mat_1_t, vec_1, market_ids, nu_bern)
> s7t = predict_shares_bern_7_t(delta, randvar_nu_t, randvar_nu_inattention_t, mat_1_t, vec_1, vec_2, market_ids, nu_bern)
> @assert s5t≈s7t
> 
> @btime predict_shares_bern_5_t($delta, $randvar_nu_t, $randvar_nu_inattention_t, $mat_1_t, $vec_1, $market_ids, $nu_bern)
> @btime predict_shares_bern_7_t($delta, $randvar_nu_t, $randvar_nu_inattention_t, $mat_1_t, $vec_1, $vec_2, $market_ids, $nu_bern)
> 
> nothing
> end
> 
> ```

hope it helps

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [August 14, 2023, 3:17am UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/39 "2023-08-14T03:17:30Z")

</div>

Those `@inbounds` outside the function definition do not work.

```julia
julia> @inbounds get(x,i) = x[i]
get (generic function with 1 method)

julia> get2(x,i) = @inbounds x[i]
get2 (generic function with 1 method)

julia> x = rand(3);

julia> @code_llvm debuginfo=:none get(x, 1)
; Function Signature: get(Array{Float64, 1}, Int64)
define double @julia_get_2224({}* noundef nonnull align 16 dereferenceable(40) %"x::Array", i64 signext %"i::Int64") #0 {
top:
  %0 = add i64 %"i::Int64", -1
  %1 = bitcast {}* %"x::Array" to { i8*, i64, i16, i16, i32 }*
  %.length_ptr = getelementptr inbounds { i8*, i64, i16, i16, i32 }, { i8*, i64, i16, i16, i32 }* %1, i64 0, i32 1
  %.length = load i64, i64* %.length_ptr, align 8
  %inbounds = icmp ult i64 %0, %.length
  br i1 %inbounds, label %idxend, label %oob

oob: ; preds = %top
  %errorbox = alloca i64, align 8
  store i64 %"i::Int64", i64* %errorbox, align 8
  call void @ijl_bounds_error_ints({}* %"x::Array", i64* nonnull %errorbox, i64 1)
  unreachable

idxend: ; preds = %top
  %2 = bitcast {}* %"x::Array" to double**
  %.data1 = load double*, double** %2, align 8
  %3 = getelementptr inbounds double, double* %.data1, i64 %0
  %.ref = load double, double* %3, align 8
  ret double %.ref
}

julia> @code_llvm debuginfo=:none get2(x, 1)
; Function Signature: get2(Array{Float64, 1}, Int64)
define double @julia_get2_2315({}* noundef nonnull align 16 dereferenceable(40) %"x::Array", i64 signext %"i::Int64") #0 {
top:
  %0 = add i64 %"i::Int64", -1
  %1 = bitcast {}* %"x::Array" to double**
  %.data1 = load double*, double** %1, align 8
  %2 = getelementptr inbounds double, double* %.data1, i64 %0
  %.ref = load double, double* %2, align 8
  ret double %.ref
}

```

---

<div class="post-metadata">

**Author:** ![ditfurth](https://avatars.discourse-cdn.com/v4/letter/d/3e96dc/32.png) [@ditfurth](https://discourse.julialang.org/u/ditfurth)\
**Post date:** [August 14, 2023, 5:36am UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/40 "2023-08-14T05:36:34Z")

</div>

Thanks a ton. I only have a problem with

```julia
@views @inbounds function foo2_t!(num,market_ids)
    Threads.@threads for id ∈ market_ids
        s = sum(num[:,id])
        num[:,id] ./= s+1
    end
end

```

This introduces deviations. Do you know why?

i.e., compare this

```julia
function foo1_t!(num,market_ids)
    @inbounds for id ∈ market_ids
        @views s = sum(num[:,id])
        @views num[:,id] ./= s+1
    end
end
@views @inbounds function foo2_t!(num,market_ids)
    Threads.@threads for id ∈ market_ids
        s = sum(num[:,id])
        num[:,id] ./= s+1
    end
end
mat_1_t = similar(randvar_nu_t)
mat_2_t = similar(randvar_nu_t)
bar_t!(mat_1_t,randvar_nu_t,delta)
bar_t!(mat_2_t,randvar_nu_t,delta)
mat_1_t == mat_2_t
foo1_t!(mat_1_t, market_ids)
foo2_t!(mat_2_t, market_ids)
mat_1_t == mat_2_t

```

You can see, that the two results are not the same at the end, but they are after the bar\_t!() function.

Does not matter too much, you helped me a ton! I just thought it is weird that somehow Threads.@threads changes the result.

---

<div class="post-metadata">

**Author:** ![Elrod](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/elrod/32/22461_2.png) [@Elrod](https://discourse.julialang.org/u/Elrod)\
**Post date:** [August 14, 2023, 6:08am UTC](https://discourse.julialang.org/t/speeding-up-a-function/102703/41 "2023-08-14T06:08:27Z")

</div>

Are all market\_ids unique? If not, you can’t `Threads.@threads` them without special care.

Also, to repeat my ignored earlier comment: those `@inbounds` are not doing anything, because it does not penetrate function boundaries.  
If you want `@inbounds`, move it inside.

Note also that `Threads.@threads` introduces a function boundary (a closure).  
So move it inside the for loop (if you don’t simply delete it altogether).

[Previous page](https://discourse.julialang.org/t/speeding-up-a-function/102703.md?page=1)

[Next page](https://discourse.julialang.org/t/speeding-up-a-function/102703.md?page=3)
