Armadillo+NVBLAS 变成 RcppArmadillo+NVBLAS
Armadillo+NVBLAS into RcppArmadillo+NVBLAS
TLDR; for the ones that wants to avoid reading the whole story: Is
there a way to interface RcppArmadillo with NVBLAS to make use of the
GPU, much more like you'd do to interface Armadillo with NVBLAS using
pure c++ code without R?
我正在尝试利用 NVBLAS 库 (http://docs.nvidia.com/cuda/nvblas/) 来加速我项目中的线性代数部分(主要是计算统计、MCMC、粒子过滤器和所有这些好东西),方法是转移一些计算到 GPU。
我主要使用 C++ 代码,尤其是用于矩阵计算的 Armadillo 库,通过他们的常见问题解答,我了解到我可以通过以正确的方式链接 armadillo 来使用 NVBLAS (http://arma.sourceforge.net/faq.html)。
所以我安装了库并编写了以下虚拟程序:
#include <armadillo>
int main(){
arma::mat A = arma::randn<arma::mat>(3000,2000);
arma::mat B = cov(A);
arma::vec V = arma::randn(2000);
arma::mat C; arma::mat D;
for(int i = 0; i<20; ++i){ C = solve(V,B); D = inv(B); }
return 0;
}
用
编译
g++ arma_try.cpp -o arma_try.so -larmadillo
并使用
对其进行分析
nvprof ./arma_try.so
探查器输出显示:
==11798== Profiling application: ./arma_try.so
==11798== Profiling result:
Time(%) Time Calls Avg Min Max Name
72.15% 4.41253s 580 7.6078ms 1.0360ms 14.673ms void magma_lds128_dgemm_kernel<bool=0, bool=0, int=5, int=5, int=3, int=3, int=3>(int, int, int, double const *, int, double const *, int, double*, int, int, int, double const *, double const *, double, double, int)
20.75% 1.26902s 1983 639.95us 1.3440us 2.9929ms [CUDA memcpy HtoD]
4.06% 248.17ms 1 248.17ms 248.17ms 248.17ms void fermiDsyrk_v2_kernel_core<bool=1, bool=1, bool=0, bool=1>(double*, int, int, int, int, int, int, double const *, double const *, double, double, int)
1.81% 110.54ms 1 110.54ms 110.54ms 110.54ms void fermiDsyrk_v2_kernel_core<bool=0, bool=1, bool=0, bool=1>(double*, int, int, int, int, int, int, double const *, double const *, double, double, int)
1.05% 64.023ms 581 110.19us 82.913us 12.211ms [CUDA memcpy DtoH]
0.11% 6.9438ms 1 6.9438ms 6.9438ms 6.9438ms void gemm_kernel2x2_tile_multiple_core<double, bool=1, bool=0, bool=0, bool=1, bool=0>(double*, double const *, double const *, int, int, int, int, int, int, double*, double*, double, double, int)
0.06% 3.3712ms 1 3.3712ms 3.3712ms 3.3712ms void gemm_kernel2x2_core<double, bool=0, bool=0, bool=0, bool=1, bool=0>(double*, double const *, double const *, int, int, int, int, int, int, double*, double*, double, double, int)
0.02% 1.3192ms 1 1.3192ms 1.3192ms 1.3192ms void syherk_kernel_core<double, double, int=256, int=4, bool=1, bool=0, bool=0, bool=1, bool=0, bool=1>(cublasSyherkParams<double, double>)
0.00% 236.03us 1 236.03us 236.03us 236.03us void syherk_kernel_core<double, double, int=256, int=4, bool=0, bool=0, bool=0, bool=1, bool=0, bool=1>(cublasSyherkParams<double, double>)
我认出了 dgemm 和其他人……所以它起作用了!精彩。
现在我想 运行 相同的代码但与 R 接口,因为我有时需要做 input/output 并用它绘图。 RcppArmadillo 一直为我创造奇迹,与 Rcpp 一起提供我需要的所有工具。我因此写了 cpp:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
int arma_call(){
arma::mat A = arma::randn<arma::mat>(3000,2000);
arma::mat B = cov(A);
arma::vec V = arma::randn(2000);
arma::mat C; arma::mat D;
for(int i = 0; i<20; ++i){ C = solve(V,B); D = inv(B); }
return 0;
}
和 R 脚本:
Rcpp::sourceCpp('arma_try_R.cpp')
arma_call()
并尝试在控制台运行ning 上执行它
nvprof R CMD BATCH arma_try_R.R
(编辑:注意使用 Rscript 而不是 R CMD BATCH 会产生相同的结果)但是
[NVBLAS] Cannot open default config file 'nvblas.conf'
奇怪...也许 R 出于某种原因无法访问该文件,所以我将其复制到工作目录并重新运行 代码:
==12662== NVPROF is profiling process 12662, command: /bin/sh /usr/bin/R CMD BATCH arma_try_R.R
==12662== Profiling application: /bin/sh /usr/bin/R CMD BATCH arma_try_R.R
==12662== Profiling result: No kernels were profiled.
我不知道是什么原因造成的。
不过,我在安装了 Bumblebee 的 linux 系统上,所以我尝试了最后一次机会:
nvprof optirun R CMD BATCH arma_try_R.R
使用 Nvidia 卡将 R 排序为 运行,这次输出为
==10900== Profiling application: optirun R CMD BATCH arma_try_R.R
==10900== Profiling result:
Time(%) Time Calls Avg Min Max Name
100.00% 1.3760us 1 1.3760us 1.3760us 1.3760us [CUDA memcpy HtoD]
所以根本没有调用 cuda 库,也没有任何计算委托给 GPU,据我所知,使用探查器。
现在问题其实很多,不是一个。
- 这只是一个无法跟踪 R 内部调用的分析器问题吗? (我怀疑)
这是因为代码在R内部编译的方式吗?详细模式显示
/usr/lib64/R/bin/R CMD SHLIB -o 'sourceCpp_27457.so' --preclean 'arma_try_R.cpp'
g++ -I/usr/include/R/ -DNDEBUG -D_FORTIFY_SOURCE=2 -I"/home/marco/R/x86_64-unknown-linux-gnu-library/3.2/Rcpp/include" -I"/home/marco/R/x86_64-unknown-linux-gnu-library/3.2/RcppArmadillo/include" -I"/home/marco/prova_cuda" -fpic -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong --param=ssp-buffer-size=4 -c arma_try_R.cpp -o arma_try_R.o
g++ -shared -L/usr/lib64/R/lib -Wl,-O1,--sort-common,--as-needed,-z,relro -lblas -llapack -o sourceCpp_27457.so arma_try_R.o -llapack -lblas -lgfortran -lm -lquadmath -L/usr/lib64/R/lib -lR
即使我强制使用 -larmadillo 而不是 -lblas 标志(通过 PKG_LIBS env var)也没有任何改变。
- 有什么办法让它起作用吗?我错过了什么吗?
如果您需要更多输出,我可以提供所需的内容,无论如何感谢您阅读到这里!
编辑:
ldd /usr/lib/R/lib/libR.so
[NVBLAS] Using devices :0
linux-vdso.so.1 (0x00007ffdb5bd6000)
/opt/cuda/lib64/libnvblas.so (0x00007f4afaccd000)
libblas.so => /usr/lib/libblas.so (0x00007f4afa6ea000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f4afa3ec000)
libreadline.so.6 => /usr/lib/libreadline.so.6 (0x00007f4afa1a1000)
libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007f4af9f31000)
liblzma.so.5 => /usr/lib/liblzma.so.5 (0x00007f4af9d0b000)
libbz2.so.1.0 => /usr/lib/libbz2.so.1.0 (0x00007f4af9afa000)
libz.so.1 => /usr/lib/libz.so.1 (0x00007f4af98e4000)
librt.so.1 => /usr/lib/librt.so.1 (0x00007f4af96dc000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f4af94d7000)
libgomp.so.1 => /usr/lib/libgomp.so.1 (0x00007f4af92b5000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f4af9098000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f4af8cf3000)
/usr/lib64/ld-linux-x86-64.so.2 (0x0000556509792000)
libcublas.so.7.5 => /opt/cuda/lib64/libcublas.so.7.5 (0x00007f4af7414000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f4af7092000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f4af6e7b000)
libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f4af6c0e000)
因此,除了奇怪的 [NVBLAS] Using devices :0
之外,R 似乎至少知道 cuda nvblas 库...
回答我自己的问题:是的,有可能并且足以使 R 指向正确的 (NV)BLAS 库并且 RcppArmadillo 将在正确的位置获取例程(您可能想阅读 Dirk Eddelbuettel 评论到这个问题看看为什么)
现在详细说明我的问题和自我回答的原因:
我认为问题出在我认为的地方。
当 运行 nvidia-smi
在另一个终端而不是运行 Rscript arma_try_R.R
我得到例如
+------------------------------------------------------+
| NVIDIA-SMI 352.41 Driver Version: 352.41 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 860M Off | 0000:01:00.0 Off | N/A |
| N/A 64C P0 N/A / N/A | 945MiB / 2047MiB | 21% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 20962 C /usr/lib64/R/bin/exec/R 46MiB |
| 0 21598 C nvidia-smi 45MiB |
+-----------------------------------------------------------------------------+
说明GPU确实在工作!
因此问题出在 nvprof 例程中,它无法检测到它,有时会冻结我的 Rscript。但那是另一个完全不相关的问题。
(我等着采纳为答案看有没有人来更巧妙的解决...)
如果您想在 R
会话期间将 RcppArmadillo
与 nvbals
一起使用(而不是批量 运行ning R
,请分享我自己的经验) 在终端中打开 R
之前 LD_PRELOAD
就足够了,
export LD_PRELOAD=/usr/local/cuda-8.0/lib64/libnvblas.so
设置系统环境为
Sys.setenv("PKG_CXXFLAgs"="-I/usr/local/cuda-8.0/include")
Sys.setenv("PKG_LIBS"="-L/usr/local/cuda-8.0/lib64 -lnvblas")
使用 sourceCpp 和 运行 编译。希望这对某人有帮助。
TLDR; for the ones that wants to avoid reading the whole story: Is there a way to interface RcppArmadillo with NVBLAS to make use of the GPU, much more like you'd do to interface Armadillo with NVBLAS using pure c++ code without R?
我正在尝试利用 NVBLAS 库 (http://docs.nvidia.com/cuda/nvblas/) 来加速我项目中的线性代数部分(主要是计算统计、MCMC、粒子过滤器和所有这些好东西),方法是转移一些计算到 GPU。
我主要使用 C++ 代码,尤其是用于矩阵计算的 Armadillo 库,通过他们的常见问题解答,我了解到我可以通过以正确的方式链接 armadillo 来使用 NVBLAS (http://arma.sourceforge.net/faq.html)。
所以我安装了库并编写了以下虚拟程序:
#include <armadillo>
int main(){
arma::mat A = arma::randn<arma::mat>(3000,2000);
arma::mat B = cov(A);
arma::vec V = arma::randn(2000);
arma::mat C; arma::mat D;
for(int i = 0; i<20; ++i){ C = solve(V,B); D = inv(B); }
return 0;
}
用
编译g++ arma_try.cpp -o arma_try.so -larmadillo
并使用
对其进行分析nvprof ./arma_try.so
探查器输出显示:
==11798== Profiling application: ./arma_try.so
==11798== Profiling result:
Time(%) Time Calls Avg Min Max Name
72.15% 4.41253s 580 7.6078ms 1.0360ms 14.673ms void magma_lds128_dgemm_kernel<bool=0, bool=0, int=5, int=5, int=3, int=3, int=3>(int, int, int, double const *, int, double const *, int, double*, int, int, int, double const *, double const *, double, double, int)
20.75% 1.26902s 1983 639.95us 1.3440us 2.9929ms [CUDA memcpy HtoD]
4.06% 248.17ms 1 248.17ms 248.17ms 248.17ms void fermiDsyrk_v2_kernel_core<bool=1, bool=1, bool=0, bool=1>(double*, int, int, int, int, int, int, double const *, double const *, double, double, int)
1.81% 110.54ms 1 110.54ms 110.54ms 110.54ms void fermiDsyrk_v2_kernel_core<bool=0, bool=1, bool=0, bool=1>(double*, int, int, int, int, int, int, double const *, double const *, double, double, int)
1.05% 64.023ms 581 110.19us 82.913us 12.211ms [CUDA memcpy DtoH]
0.11% 6.9438ms 1 6.9438ms 6.9438ms 6.9438ms void gemm_kernel2x2_tile_multiple_core<double, bool=1, bool=0, bool=0, bool=1, bool=0>(double*, double const *, double const *, int, int, int, int, int, int, double*, double*, double, double, int)
0.06% 3.3712ms 1 3.3712ms 3.3712ms 3.3712ms void gemm_kernel2x2_core<double, bool=0, bool=0, bool=0, bool=1, bool=0>(double*, double const *, double const *, int, int, int, int, int, int, double*, double*, double, double, int)
0.02% 1.3192ms 1 1.3192ms 1.3192ms 1.3192ms void syherk_kernel_core<double, double, int=256, int=4, bool=1, bool=0, bool=0, bool=1, bool=0, bool=1>(cublasSyherkParams<double, double>)
0.00% 236.03us 1 236.03us 236.03us 236.03us void syherk_kernel_core<double, double, int=256, int=4, bool=0, bool=0, bool=0, bool=1, bool=0, bool=1>(cublasSyherkParams<double, double>)
我认出了 dgemm 和其他人……所以它起作用了!精彩。
现在我想 运行 相同的代码但与 R 接口,因为我有时需要做 input/output 并用它绘图。 RcppArmadillo 一直为我创造奇迹,与 Rcpp 一起提供我需要的所有工具。我因此写了 cpp:
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
int arma_call(){
arma::mat A = arma::randn<arma::mat>(3000,2000);
arma::mat B = cov(A);
arma::vec V = arma::randn(2000);
arma::mat C; arma::mat D;
for(int i = 0; i<20; ++i){ C = solve(V,B); D = inv(B); }
return 0;
}
和 R 脚本:
Rcpp::sourceCpp('arma_try_R.cpp')
arma_call()
并尝试在控制台运行ning 上执行它
nvprof R CMD BATCH arma_try_R.R
(编辑:注意使用 Rscript 而不是 R CMD BATCH 会产生相同的结果)但是
[NVBLAS] Cannot open default config file 'nvblas.conf'
奇怪...也许 R 出于某种原因无法访问该文件,所以我将其复制到工作目录并重新运行 代码:
==12662== NVPROF is profiling process 12662, command: /bin/sh /usr/bin/R CMD BATCH arma_try_R.R
==12662== Profiling application: /bin/sh /usr/bin/R CMD BATCH arma_try_R.R
==12662== Profiling result: No kernels were profiled.
我不知道是什么原因造成的。 不过,我在安装了 Bumblebee 的 linux 系统上,所以我尝试了最后一次机会:
nvprof optirun R CMD BATCH arma_try_R.R
使用 Nvidia 卡将 R 排序为 运行,这次输出为
==10900== Profiling application: optirun R CMD BATCH arma_try_R.R
==10900== Profiling result:
Time(%) Time Calls Avg Min Max Name
100.00% 1.3760us 1 1.3760us 1.3760us 1.3760us [CUDA memcpy HtoD]
所以根本没有调用 cuda 库,也没有任何计算委托给 GPU,据我所知,使用探查器。 现在问题其实很多,不是一个。
- 这只是一个无法跟踪 R 内部调用的分析器问题吗? (我怀疑)
这是因为代码在R内部编译的方式吗?详细模式显示
/usr/lib64/R/bin/R CMD SHLIB -o 'sourceCpp_27457.so' --preclean 'arma_try_R.cpp'
g++ -I/usr/include/R/ -DNDEBUG -D_FORTIFY_SOURCE=2 -I"/home/marco/R/x86_64-unknown-linux-gnu-library/3.2/Rcpp/include" -I"/home/marco/R/x86_64-unknown-linux-gnu-library/3.2/RcppArmadillo/include" -I"/home/marco/prova_cuda" -fpic -march=x86-64 -mtune=generic -O2 -pipe -fstack-protector-strong --param=ssp-buffer-size=4 -c arma_try_R.cpp -o arma_try_R.o
g++ -shared -L/usr/lib64/R/lib -Wl,-O1,--sort-common,--as-needed,-z,relro -lblas -llapack -o sourceCpp_27457.so arma_try_R.o -llapack -lblas -lgfortran -lm -lquadmath -L/usr/lib64/R/lib -lR
即使我强制使用 -larmadillo 而不是 -lblas 标志(通过 PKG_LIBS env var)也没有任何改变。
- 有什么办法让它起作用吗?我错过了什么吗?
如果您需要更多输出,我可以提供所需的内容,无论如何感谢您阅读到这里!
编辑:
ldd /usr/lib/R/lib/libR.so
[NVBLAS] Using devices :0
linux-vdso.so.1 (0x00007ffdb5bd6000)
/opt/cuda/lib64/libnvblas.so (0x00007f4afaccd000)
libblas.so => /usr/lib/libblas.so (0x00007f4afa6ea000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f4afa3ec000)
libreadline.so.6 => /usr/lib/libreadline.so.6 (0x00007f4afa1a1000)
libpcre.so.1 => /usr/lib/libpcre.so.1 (0x00007f4af9f31000)
liblzma.so.5 => /usr/lib/liblzma.so.5 (0x00007f4af9d0b000)
libbz2.so.1.0 => /usr/lib/libbz2.so.1.0 (0x00007f4af9afa000)
libz.so.1 => /usr/lib/libz.so.1 (0x00007f4af98e4000)
librt.so.1 => /usr/lib/librt.so.1 (0x00007f4af96dc000)
libdl.so.2 => /usr/lib/libdl.so.2 (0x00007f4af94d7000)
libgomp.so.1 => /usr/lib/libgomp.so.1 (0x00007f4af92b5000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f4af9098000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f4af8cf3000)
/usr/lib64/ld-linux-x86-64.so.2 (0x0000556509792000)
libcublas.so.7.5 => /opt/cuda/lib64/libcublas.so.7.5 (0x00007f4af7414000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f4af7092000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f4af6e7b000)
libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007f4af6c0e000)
因此,除了奇怪的 [NVBLAS] Using devices :0
之外,R 似乎至少知道 cuda nvblas 库...
回答我自己的问题:是的,有可能并且足以使 R 指向正确的 (NV)BLAS 库并且 RcppArmadillo 将在正确的位置获取例程(您可能想阅读 Dirk Eddelbuettel 评论到这个问题看看为什么)
现在详细说明我的问题和自我回答的原因:
我认为问题出在我认为的地方。
当 运行 nvidia-smi
在另一个终端而不是运行 Rscript arma_try_R.R
我得到例如
+------------------------------------------------------+
| NVIDIA-SMI 352.41 Driver Version: 352.41 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 860M Off | 0000:01:00.0 Off | N/A |
| N/A 64C P0 N/A / N/A | 945MiB / 2047MiB | 21% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 20962 C /usr/lib64/R/bin/exec/R 46MiB |
| 0 21598 C nvidia-smi 45MiB |
+-----------------------------------------------------------------------------+
说明GPU确实在工作!
因此问题出在 nvprof 例程中,它无法检测到它,有时会冻结我的 Rscript。但那是另一个完全不相关的问题。
(我等着采纳为答案看有没有人来更巧妙的解决...)
如果您想在 R
会话期间将 RcppArmadillo
与 nvbals
一起使用(而不是批量 运行ning R
,请分享我自己的经验) 在终端中打开 R
之前 LD_PRELOAD
就足够了,
export LD_PRELOAD=/usr/local/cuda-8.0/lib64/libnvblas.so
设置系统环境为
Sys.setenv("PKG_CXXFLAgs"="-I/usr/local/cuda-8.0/include")
Sys.setenv("PKG_LIBS"="-L/usr/local/cuda-8.0/lib64 -lnvblas")
使用 sourceCpp 和 运行 编译。希望这对某人有帮助。