# How can I improve the speed of large matrix multiplication

**URL:** https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616
**Category:** Performance
**Tags:** question
**Created:** [March 5, 2020, 11:29pm UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616 "2020-03-05T23:29:17Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![zxjroger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zxjroger/32/11826_2.png) [@zxjroger](https://discourse.julialang.org/u/zxjroger)
#### Post date: [March 5, 2020, 11:29pm UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/1 "2020-03-05T23:29:17Z")

</div>

I have some functions involving large matrix multiplication in my code. A sample code is as follows.

```julia
function foo1()
    temp = Array[]
    for i = 1:1000
        push!(temp, randn(400,400)*randn(400,1000))
    end
end

function foo2()
    for i = 1:1000
        randn(400,400)*randn(400,1000)
    end
end

@time foo1()
@time foo2()

```

I find that `foo1()` takes 17 seconds. Without `push!`, `foo2()` takes 11 seconds. Is there any way to improve the speed of `foo1()`? Thank you.

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [March 5, 2020, 11:41pm UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/2 "2020-03-05T23:41:49Z")

</div>

The eltype of `temp` is `Array`, which isn’t a concrete type: the compiler has to assume it can hold any subtype of `Array`. Use `temp = Matrix{Float64}[]` instead.

```julia
julia> isconcretetype(Array)
false

julia> isconcretetype(Matrix{Float64})
true

```

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [March 5, 2020, 11:58pm UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/3 "2020-03-05T23:58:11Z")

</div>

That shouldn’t have any measurable effect on the speed of this code. You are more likely to be simply observing the cost of actually allocating and populating larger and larger memory. `foo2` is just creating garbage in a loop so the GC, the libc and the OS can work together to reuse the memory.

---

<div class="post-metadata">

### Author: ![stillyslalom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stillyslalom/32/45687_2.png) [@stillyslalom](https://discourse.julialang.org/u/stillyslalom)
#### Post date: [March 6, 2020, 12:18am UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/4 "2020-03-06T00:18:05Z")

</div>

Hmm, I timed it before posting my original response and saw a significant effect, but that looks to have been a fluke.

@zxjroger, your benchmark is largely just timing `randn`:

```julia
julia> @btime randn(400,400) * randn(400,1000);
  9.321 ms (6 allocations: 7.32 MiB)

julia> @btime a * b setup=(a=randn(400,400); b=randn(400,1000));
  4.182 ms (2 allocations: 3.05 MiB)

```

---

<div class="post-metadata">

### Author: ![Juan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juan/32/7657_2.png) [@Juan](https://discourse.julialang.org/u/Juan)
#### Post date: [March 6, 2020, 12:49am UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/5 "2020-03-06T00:49:03Z")

</div>

You can also preallocate the two random matrices outside the for loop and use randn!.

You can also use mul! instead of \*.  
Or use BLAS functions.

---

<div class="post-metadata">

### Author: ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)
#### Post date: [March 7, 2020, 9:10am UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/6 "2020-03-07T09:10:27Z")

</div>

To expand on what @Juan said,

```julia
using LinearAlgebra, Random
using BenchmarkTools

function foo1()
    temp = Array[]
    for i = 1:1000
        push!(temp, randn(400,400)*randn(400,1000))
    end
end

function foo_prealloc(tmp::AbstractVector, A::AbstractMatrix, B::AbstractMatrix)
    @assert size(A, 2) == size(B, 1) # multiplicable
    @assert size(first(tmp)) == (size(A, 1), size(B, 2)) # fits into tmp
    for t in tmp
        randn!(A), randn!(B)
        mul!(t, A, B)
    end
    return tmp
end

A = zeros(400,400)
B = zeros(400,1000)
tmp = [zeros(400,1000) for _ in 1:1000]

@btime foo1(); # 22.646 s (6010 allocations: 7.15 GiB)
@btime foo_prealloc($tmp, $A, $B); # 1.368 s (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

### Author: ![zxjroger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/zxjroger/32/11826_2.png) [@zxjroger](https://discourse.julialang.org/u/zxjroger)
#### Post date: [March 10, 2020, 5:17pm UTC](https://discourse.julialang.org/t/how-can-i-improve-the-speed-of-large-matrix-multiplication/35616/7 "2020-03-10T17:17:28Z")

</div>

Thank you for all the suggestions. I will look into it.
