# Why for-loop of vector multiplication is slower that dot product?

**URL:** <https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631>\
**Category:** General Usage\
**Tags:** question\
**Created:** [August 11, 2022, 5:53pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631 "2022-08-11T17:53:04Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [August 11, 2022, 5:53pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/1 "2022-08-11T17:53:04Z")

</div>

I just want to know why the `.*` below is faster that `for-loop product`?

```julia
using BenchmarkTools, LinearAlgebra
S1 = rand(10000);
S2 = rand(10000);
S = zeros(10000);
S3 = zeros(10000);
n =size(S1,1)
function mm!(S, S1, S2, n)
  for i in 1:n
    S[i] = S1[i]*S2[i]
  end  
end
julia> @btime $S .= $S1.*$S2;
  1.910 μs (0 allocations: 0 bytes)
julia> @btime mm!($S3, $S1, $S2, $n)
  2.089 μs (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)\
**Post date:** [August 11, 2022, 5:56pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/2 "2022-08-11T17:56:15Z")

</div>

Your code seems to have some clear bugs in it that cause you to use global variables:

```julia
function mm!(S, S1, S3, n)
  for i in 1:n
    S[i] = S1[i]*S2[i]
  end  
end

```

You take in S, S1 and S3 as arguments, but operate on S, S1 and S2.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [August 11, 2022, 6:04pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/3 "2022-08-11T18:04:08Z")

</div>

Sorry it was typo and updated it! Thanks for the correction.

---

<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:** [August 11, 2022, 6:17pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/4 "2022-08-11T18:17:14Z")

</div>

> [@Amro](#):
>
> ```julia
> function mm!(S, S1, S2, n)
> for i in 1:n
> @inbounds S[i] = S1[i]*S2[i]
> end  
> end
> 
> ```

add that `@inbounds` and you get the same performance, because the dot operation has that guaranteed.

That said, you can write that loop more cleanly as:

```julia
julia> function mm!(S, S1, S2)
         for i in eachindex(S, S1, S2)
            @inbounds S[i] = S1[i]*S2[i]
         end  
       end
mm! (generic function with 2 methods)

julia> @btime mm!($S3, $S1, $S2)
  1.706 μs (0 allocations: 0 bytes)

```

that `eachindex(S, S1, S2)` also guarantees that you are inbounds (it will error if the lengths of the arrays differ) - and, I bet, in the near future you won’t need, in this case, the `@inbounds` flag there to recover the performance of the dot operation.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [August 11, 2022, 6:26pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/5 "2022-08-11T18:26:38Z")

</div>

Thank you very much for your comments. Why `eachindex` and `@inbounds` give better performance? Is it related to the compiler or the memory?

> [@lmiq](#):
>
> add that `@inbounds` and you get the same performance, because the dot operation has that guaranteed.

Where can I find the function of dot operation?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [August 11, 2022, 6:35pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/6 "2022-08-11T18:35:52Z")

</div>

> [@Amro](#):
>
> Why `eachindex` and `@inbounds` give better performance? Is it related to the compiler o

> **[Matrix multiplication: Performance](https://opensourc.es/blog/matrix-multiplication-performance/index.html)**
>
> A deep dive into the performance we can obtain by thinking about cache lines and parallel code. An example step by step guide on optimizing dense matrix multiplication.

---

<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:** [August 11, 2022, 6:52pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/7 "2022-08-11T18:52:23Z")

</div>

> [@Amro](#):
>
> Why `eachindex` and `@inbounds` give better performance?

`@inbounds` disables bounds checking (which is disabled already on the dot operation, because the input guarantees that it is inbounds). By not having to check bounds, the compiler might be able (it is in this case) to use [SIMD](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data) computations.

The `eachindex` does not improve performance here, but it will probably do in future Julia versions, by automatically guaranteeing the `@inbounds` inside the loop.

> [@Amro](#):
>
> Where can I find the function of dot operation?

It is some `broadcast` operation, but that machinery is pretty complicated.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [August 11, 2022, 7:03pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/8 "2022-08-11T19:03:25Z")

</div>

Thank you. I got the

---

<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:** [August 11, 2022, 7:27pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/9 "2022-08-11T19:27:56Z")

</div>

Also, it is not safe to use `@inbounds` with `for i in 1:n`, both because the arrays may not have 1-based indexing, and also because it is easy for a user-provided `n` to be wrong. It is not a good idea to pass the length of an array as a separate input argument, that can easily, quickly and safely be read directly from the array itself.

With `eachindex` you don’t need to worry about this.

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [August 11, 2022, 7:49pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/10 "2022-08-11T19:49:39Z")

</div>

> [@DNF](#):
>
> Also, it is not safe to use `@inbounds` with `for i in 1:n`, both because the arrays may not have 1-based indexing,

How is about the index of matrix. For example:

```julia
n =4;
m=5;
s =zeros(n,m)
for i in 1:n
for j in 1:m
println(s[i,j]]
end
end

```

---

<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:** [August 11, 2022, 7:53pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/11 "2022-08-11T19:53:49Z")

</div>

It’s similar. You can use `eachindex` with matrices too:

```julia
for i in eachindex(s)
    println(s[i])
end

```

or use `axes`:

```julia
for j in axes(s, 2)
    for i in axes(s, 1) # first index should be inner loop, if possible
        println(s[i,j]]
    end
end

```

---

<div class="post-metadata">

**Author:** ![Amro](https://avatars.discourse-cdn.com/v4/letter/a/4491bb/32.png) [@Amro](https://discourse.julialang.org/u/Amro)\
**Post date:** [August 11, 2022, 7:56pm UTC](https://discourse.julialang.org/t/why-for-loop-of-vector-multiplication-is-slower-that-dot-product/85631/12 "2022-08-11T19:56:11Z")

</div>

> [@DNF](#):
>
> It’s similar. You can use `eachinde`

Got it. Thank you very much!
