# QR decomposition in julia 2x slower than octave

**URL:** https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043
**Category:** Performance
**Tags:** question
**Created:** [March 28, 2018, 10:24pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043 "2018-03-28T22:24:49Z")
**Posts on this page:** 18
**Page:** 1

<div class="post-metadata">

### Author: ![mrcinv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrcinv/32/12750_2.png) [@mrcinv](https://discourse.julialang.org/u/mrcinv)
#### Post date: [March 28, 2018, 10:24pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/1 "2018-03-28T22:24:49Z")

</div>

I noticed that QR decomposition is 2x slower in julia than octave. For example on my computer I get

```julia
julia> A = rand(5000, 5000); @time qr(A);
 27.075522 seconds (37 allocations: 765.687 MiB, 0.83% gc time)

```

and

```julia
>> A=rand(5000, 5000);
>> tic; qr(A); toc
Elapsed time is 8.35741 seconds.
>>

```

The results are more or less the same if repeated more times.

Anyone has an idea why is that? I thought both julia and octave use BLAS/Lapack, so both methods should take roughly the same amount of time.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [March 28, 2018, 10:30pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/2 "2018-03-28T22:30:48Z")

</div>

What does your `versioninfo()` say? Did you rebuild the system image if you used the generic binary?

---

<div class="post-metadata">

### Author: ![simonbyrne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simonbyrne/32/19_2.png) [@simonbyrne](https://discourse.julialang.org/u/simonbyrne)
#### Post date: [March 28, 2018, 10:35pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/3 "2018-03-28T22:35:15Z")

</div>

I suspect they may be doing different things. I don’t know what [`qr` method](https://octave.sourceforge.io/octave/function/qr.html) Octave calls when no output arguments are provided, but my guess is that it’s just doing the 1st phase (computing the Householder reflectors and upper-triangular part) and not the 2nd (building Q). This would roughly match [`qrfact`](https://docs.julialang.org/en/stable/stdlib/linalg/#Base.LinAlg.qrfact) in Julia. On my machine, I get:

```julia
julia> @time qrfact(A);
  5.906331 seconds (25.99 k allocations: 194.912 MiB, 2.13% gc time)

julia> @time qr(A);
 16.202900 seconds (93.73 k allocations: 770.718 MiB, 1.62% gc time)

```

---

<div class="post-metadata">

### Author: ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)
#### Post date: [March 28, 2018, 10:43pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/4 "2018-03-28T22:43:39Z")

</div>

```julia
julia> A = rand(5000, 5000); @time qr(A);
 14.143329 seconds (294.06 k allocations: 781.888 MiB, 0.90% gc time)

julia> versioninfo()
Julia Version 0.7.0-DEV.4690
Commit 78c7d87369* (2018-03-23 22:25 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-6650U CPU @ 2.20GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, skylake)
Environment:
  JULIA_NUM_THREADS = 1

julia> A = rand(5000, 5000); @time qrfact(A);
  5.583176 seconds (2.32 k allocations: 193.608 MiB, 1.85% gc time)

julia>

```

versus

```julia
>> A=rand(5000, 5000);
>> tic; qr(A); toc
Elapsed time is 4.189508 seconds.
>> version

ans =

    '9.4.0.813654 (R2018a)'

```

---

<div class="post-metadata">

### Author: ![mrcinv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrcinv/32/12750_2.png) [@mrcinv](https://discourse.julialang.org/u/mrcinv)
#### Post date: [March 28, 2018, 11:06pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/5 "2018-03-28T23:06:37Z")

</div>

That would explain the difference. If you call the function qr in octave with both return values `[Q, R] = qr(A)`, it takes more time, since it has to generate `Q`

```julia
>> A = rand(5000); tic; [Q,R] = qr(A); toc
Elapsed time is 17.8421 seconds.
>> tic; qr(A); toc
Elapsed time is 9.22192 seconds.

```

---

<div class="post-metadata">

### Author: ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)
#### Post date: [March 28, 2018, 11:56pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/6 "2018-03-28T23:56:28Z")

</div>

Not so for Matlab:

```julia
>> A=rand(5000, 5000);
>> tic; qr(A); toc
Elapsed time is 4.189508 seconds.
>> version

ans =

    '9.4.0.813654 (R2018a)'

>> tic; [q,r]=qr(A); toc
Elapsed time is 5.785541 seconds.

```

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [March 29, 2018, 12:14am UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/7 "2018-03-29T00:14:52Z")

</div>

> [@PetrKryslUCSD](#):
>
> Not so for Matlab:

MATLAB uses MKL. For an out of the box comparison there it would be interesting to test JuliaPro+MKL against MATLAB.

---

<div class="post-metadata">

### Author: ![Seif\_Shebl](https://avatars.discourse-cdn.com/v4/letter/s/eada6e/32.png) [@Seif\_Shebl](https://discourse.julialang.org/u/Seif_Shebl)
#### Post date: [March 29, 2018, 12:43pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/8 "2018-03-29T12:43:09Z")

</div>

Still, there is a big difference in JuliaPro (MKL):

```julia
julia> A = rand(5000, 5000); @time qr(A);
  6.561612 seconds (37 allocations: 765.687 MiB, 2.20% gc time)

julia> versioninfo()
Julia Version 0.6.0
Commit 903644385b* (2017-06-19 13:05 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
  WORD_SIZE: 64
  BLAS: mkl_rt
  LAPACK: mkl_rt
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, haswell)

```

and MATLAB:

```julia
>> tic, A=rand(5000, 5000); [Q,R] = qr(A); toc
Elapsed time is 2.760503 seconds.

```

---

<div class="post-metadata">

### Author: ![JakobPeterlin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobpeterlin/32/3945_2.png) [@JakobPeterlin](https://discourse.julialang.org/u/JakobPeterlin)
#### Post date: [April 13, 2018, 12:33pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/9 "2018-04-13T12:33:58Z")

</div>

Have you tried using qrfact instead of qr?  
In my case the performance of qrfact(A) is approx. 2.5X faster than qr(A), for A = rand(5000, 5000).

---

<div class="post-metadata">

### Author: ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)
#### Post date: [April 13, 2018, 2:39pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/10 "2018-04-13T14:39:29Z")

</div>

I get similar results:

```julia

julia> versioninfo()
Julia Version 0.6.2
Commit d386e40c17* (2017-12-13 18:08 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
  WORD_SIZE: 64
  BLAS: libopenblas (USE64BITINT NO_AFFINITY HASWELL)
  LAPACK: libopenblas64_
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, haswell)

julia> using BenchmarkTools

julia> A = rand(5000, 5000);

julia> @btime qr($A)
  9.746 s (33 allocations: 765.69 MiB)

julia> @btime qrfact($A)
  4.266 s (17 allocations: 193.48 MiB)

```

Julia is running in Virtualbox. Native windows Matlab 2018a:

```julia
>> tic; A=rand(5000, 5000); [Q,R] = qr(A); toc
Elapsed time is 3.738918 seconds.

```

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [April 13, 2018, 2:57pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/11 "2018-04-13T14:57:04Z")

</div>

> [@mbaz](#):
>
> Julia is running in Virtualbox. Native windows Matlab 2018a

Use the same computer. Timings mean nothing when the same computer isn’t used. VirtualBox is a free shared cloud resource: I would expect it to not have the best performance.

---

<div class="post-metadata">

### Author: ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)
#### Post date: [April 13, 2018, 2:58pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/12 "2018-04-13T14:58:15Z")

</div>

It _is_ the same computer. Virtualbox is running locally.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [April 13, 2018, 3:00pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/13 "2018-04-13T15:00:09Z")

</div>

Oh my bad. For some reason I read JuliaBox…

---

<div class="post-metadata">

### Author: ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)
#### Post date: [April 13, 2018, 3:01pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/14 "2018-04-13T15:01:20Z")

</div>

Heh, that would indeed be a meaningless comparison 🙂

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [April 13, 2018, 3:04pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/15 "2018-04-13T15:04:13Z")

</div>

What about Julia(Pro) with MKL? MATLAB is MKL.

---

<div class="post-metadata">

### Author: ![mbaz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbaz/32/17295_2.png) [@mbaz](https://discourse.julialang.org/u/mbaz)
#### Post date: [April 13, 2018, 3:18pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/16 "2018-04-13T15:18:53Z")

</div>

I hadn’t realized that there’s a free version of JuliaPro… I’ll need to try it out. If nobody does it first, I’ll post my results in a few days.

---

<div class="post-metadata">

### Author: ![Pier](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pier/32/7335_2.png) [@Pier](https://discourse.julialang.org/u/Pier)
#### Post date: [April 13, 2018, 5:36pm UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/17 "2018-04-13T17:36:45Z")

</div>

With MKL under Windows:

```julia
versioninfo()
Julia Version 0.6.2
Commit d386e40c17* (2017-12-13 18:08 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Xeon(R) CPU E5645 @ 2.40GHz
  WORD_SIZE: 64
  BLAS: mkl_rt
  LAPACK: mkl_rt
  LIBM: libopenlibm
  LLVM: libLLVM-3.9.1 (ORCJIT, westmere)

```

Julia:

```julia
using BenchmarkTools
@btime qr($A)
14.230 s (33 allocations: 765.69 MiB)
@btime qrfact($A)
5.645 s (17 allocations: 193.48 MiB)

```

Matlab:

```julia
tic; A=rand(5000, 5000); [Q,R] = qr(A); toc
Elapsed time is 8.418957 seconds.

```

---

<div class="post-metadata">

### Author: ![Ralph\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ralph_smith/32/10344_2.png) [@Ralph\_Smith](https://discourse.julialang.org/u/Ralph_Smith)
#### Post date: [April 14, 2018, 2:34am UTC](https://discourse.julialang.org/t/qr-decomposition-in-julia-2x-slower-than-octave/10043/18 "2018-04-14T02:34:48Z")

</div>

In my experience the QR routines benefit from tuning. In particular, for sizes like 5000x5000, hyperthreading is counterproductive and the default block size is too small. So setting `BLAS.set_num_threads(nr_of_physical_cores)` and calling the LAPACK routines to manually reset the block size (default is 36):

```julia
julia> A=rand(5000,5000);

julia> A1=copy(A); @time F=Base.LinAlg.LAPACK.geqrt!(A1,256);
  1.460697 seconds (14 allocations: 19.532 MiB)

julia> FF=Base.LinAlg.QRCompactWY(F...);

# this finishes computing Q:
julia> B=eye(A); @time Base.LinAlg.LAPACK.gemqrt!('L','N',FF.factors,FF.T,B);
  2.057016 seconds (7 allocations: 190.735 MiB, 0.56% gc time)

julia> @time x=qr(A); # for comparison
  7.118840 seconds (35 allocations: 765.687 MiB, 2.22% gc time)

julia> vecnorm(x[1]-B) # consistency check
5.419168097206542e-13

```

This is about as fast as Matlab on a comparable machine. (Aside: these times are from a quiet system; I saw wild variation when other programs were minimally active.)

Here I am using Julia 0.6.2 with OpenBLAS.
