在我的两台计算机上,我尝试了这段代码:
N <- 10e3
M <- 2000
X <- matrix(rnorm(N * M), N)
system.time(crossprod(X))
第一个是标准笔记本电脑,此操作需要1.7秒。
> sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-redhat-linux-gnu (64-bit)
Running under: CentOS Linux 7 (Core)
Matrix products: default
BLAS/LAPACK: /usr/lib64/R/lib/libRblas.so
第二个是一台相当不错的台式电脑,耗时17秒。
> sessionInfo()
R version 3.4.4 (2018-03-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Linux Mint 18.3
Matrix products: default
BLAS: /usr/lib/libblas/libblas.so.3.6.0
LAPACK: /usr/lib/lapack/liblapack.so.3.6.0
桌面计算机的性能比笔记本电脑更高,但这种矩阵计算需要10倍的时间。
问题来自默认的BLAS / LAPACK吗?
答案 0 :(得分:6)
tldr: CentOS使用单线程OpenBLAS,Linux Mint默认使用参考BLAS,但可以使用其他BLAS版本。
EPEL提供的CentOS的R软件包取决于openblas-Rblas
。这似乎是为R提供BLAS的OpenBLAS构建。因此,尽管看起来使用了R的BLAS,但实际上是OpenBLAS。 LAPACK版本始终是R提供的版本。
在Debian和衍生版本(如Mint)上,r-base-core
取决于
默认情况下,这些由参考实现libblas3
和liblapack3
提供。这些操作不是特别快,但是您可以通过安装libopenblas-base
之类的软件包轻松地替换它们。您可以通过update-alternatives
控制系统上使用的BLAS和LAPACK。
对于使用OpenBLAS控制线程数,我通常使用RhpcBLASctl
:
N <- 20000
M <- 2000
X <- matrix(rnorm(N * M), N)
RhpcBLASctl::blas_set_num_threads(2)
system.time(crossprod(X))
#> User System verstrichen
#> 2.492 0.331 1.339
RhpcBLASctl::blas_set_num_threads(1)
system.time(crossprod(X))
#> User System verstrichen
#> 2.319 0.052 2.316
由于某些原因,从R设置environment variables OPENBLAS_NUM_THREADS
,GOTO_NUM_THREADS
或OMP_NUM_THREADS
并没有达到预期的效果。在CentOS上,即使RhpcBLASctl
也无济于事,因为使用的OpenBLAS是单线程的。
答案 1 :(得分:5)
R与默认BLAS实施一起发布,但可能未针对您的计算机进行优化。在R ATLAS之前通过OpenBLAS或as advised on the Installation guide of R推送优化版本的BLAS {3}}是要走的路。如果您登上Download R for Linux
,然后登录debian/
。据说:
您可能希望安装自动调整的Atlas或多线程OpenBlas库,以便获得更高的线性代数运算性能
R的来源可以下载here,BLAS实施位于R-3.5.0/src/extra/blas
。例如,矩阵矩阵乘法dgemm
的Fortran源代码位于blas.f中,沿着大多数BLAS例程(在单个文件中!)。
该函数的注释指定:
-- Written on 8-February-1989.
Jack Dongarra, Argonne National Laboratory.
Iain Duff, AERE Harwell.
Jeremy Du Croz, Numerical Algorithms Group Ltd.
Sven Hammarling, Numerical Algorithms Group Ltd.
在例程dgemm的netlib实现中可以找到相同的行。
相反,OpenBLAS提供了不同的实现,每种处理器都有一种。例如,请参阅this file devoted to dgemm for haswell microarchitecture。调用prefetcht0进行预取并调用vfmadd231pd,这是一个矢量FMA SIMD指令,它一次执行双精度d = a * b + c 4次。
使用优化的BLAS可以节省一天。参见例如this benchmark,其中netlib的dgemm()持续64秒,其中MKL,OpenBLAS或ATLAS dgemm花费不到4秒。
R内部BLAS的情况可能比传统的Netlib库更糟。确实,正如A.3.1.5 Shared BLAS
中附录R Installation and Administration
中所述:
R提供了将BLAS编译到存储在R_HOME / lib中的动态库libRblas并将R本身和所有附加软件包链接到该库的选项。 ....使用共享BLAS可能存在性能上的缺点。 ...但是,实验表明,在许多情况下,如果使用高级别的编译器优化,使用共享BLAS的速度一样快。
查看R的config.site文件,写入g77 / gfortran的优化级别为“-O2”。因此,如果fortran编译器不是g77 / gfortran,那么调整FFLAGS选项可能会有用。在配置步骤中,应该有一行checking whether we are using the GNU Fortran 77 compiler... yes
(配置文件的第7521行)。