# Performance with small matrices: 5-argument mul! vs BLAS.gemm!

**URL:** <https://discourse.julialang.org/t/performance-with-small-matrices-5-argument-mul-vs-blas-gemm/31543>\
**Category:** Performance\
**Created:** [November 26, 2019, 7:10pm UTC](https://discourse.julialang.org/t/performance-with-small-matrices-5-argument-mul-vs-blas-gemm/31543 "2019-11-26T19:10:06Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Egwene\_al\_Vere](https://avatars.discourse-cdn.com/v4/letter/e/df788c/32.png) [@Egwene\_al\_Vere](https://discourse.julialang.org/u/Egwene_al_Vere)\
**Post date:** [November 26, 2019, 7:10pm UTC](https://discourse.julialang.org/t/performance-with-small-matrices-5-argument-mul-vs-blas-gemm/31543/1 "2019-11-26T19:10:06Z")

</div>

Trying out the new 5-argument `mul!` [introduced in Julia 1.3](https://docs.julialang.org/en/v1.3/stdlib/LinearAlgebra/#LinearAlgebra.mul!), (ABα+Cβ → C), for the calculation of matrix commutator comu(A,B)=AB-BA. From my testing, with small (2x2 or 3x3) matrices, `mul!` is actually faster than `gemm!`, and when such functions are used in the inner-most/hot loop, it can lead to very noticeable performance differences:

```julia
using BenchmarkTools
using LinearAlgebra

ndim = 3;
m1=rand(ComplexF64,ndim,ndim);
m2=rand(ComplexF64,ndim,ndim);
ou=rand(ComplexF64,ndim,ndim);

function comu!(r, a, b)
    idy = one(eltype(r))
    mul!(r, a, b)
    mul!(r, b, a, -idy, idy)
    return nothing
end

function comu_b!(r, a, b)
    idy = one(eltype(r))
    mul!(r, a, b)
    BLAS.gemm!('N', 'N', -idy, b, a, idy, r)
    return nothing
end

```

```julia
@btime comu!($ou,$m1,$m2)

```

88.698 ns (0 allocations: 0 bytes)

```julia
@btime comu_b!($ou,$m1,$m2)

```

200.584 ns (0 allocations: 0 bytes)

Is there something special that’s going on here? As another comparison, using just 3-argument `mul!`

```julia
tmp = similar(ou);

function comu_mm!(r,a,b,h)
    mul!(r,a,b)
    mul!(h,b,a)
    r .-= h
    return nothing
end

@btime comu_mm!($ou,$m1,$m2,$tmp)

```

82.248 ns (0 allocations: 0 bytes)

Thanks!

---

<div class="post-metadata">

**Author:** ![bcmichael](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bcmichael/32/10003_2.png) [@bcmichael](https://discourse.julialang.org/u/bcmichael)\
**Post date:** [November 26, 2019, 7:26pm UTC](https://discourse.julialang.org/t/performance-with-small-matrices-5-argument-mul-vs-blas-gemm/31543/2 "2019-11-26T19:26:48Z")

</div>

For very small matrices mul! doesn’t call BLAS routines but gemm! explicitly does call BLAS. BLAS is great for large matrices but as you’ve observed has some unnecessary overhead for really small matrices.

There are matmul2x2! and matmul3x3! functions that implement fully unrolled matrix multiplication for these specific sizes in [https://github.com/JuliaLang/julia/blob/master/stdlib/LinearAlgebra/src/matmul.jl](https://github.com/JuliaLang/julia/blob/master/stdlib/LinearAlgebra/src/matmul.jl).
