谁能告诉我为什么我 无法dgemm
通过以下方式在R中 成功 测试OpenBLAS的性能(在GFLOP 中)?
libblas.so
mmperf.c
用OpenBLAS库编译我的C程序libopenblas.so
mmperf.so
到R中,调用R包装器函数mmperf
并dgemm
在GFLOP中报告性能。第1点看起来很奇怪,但是我别无选择,因为我没有要测试的计算机的root访问权限,因此无法实际链接到OpenBLAS。通过 “未成功”
我的意思是我的程序结束了报告dgemm
以供参考BLAS,而不是OpenBLAS性能。我希望有人可以向我解释:
main
函数并在C程序中完成工作。)我已经对该问题进行了为期两天的调查,这里将包括各种系统输出以帮助您进行诊断。为了使事情可重现,我还将包括代码,makefile以及shell命令。
第1部分:测试之前的系统环境
有2种方式来调用R,或者使用R
或Rscript
。调用它们时加载的内容有所不同:
~/Desktop/dgemm$ readelf -d $(R RHOME)/bin/exec/R | grep "NEEDED"
0x00000001 (NEEDED) Shared library: [libR.so]
0x00000001 (NEEDED) Shared library: [libpthread.so.0]
0x00000001 (NEEDED) Shared library: [libc.so.6]
~/Desktop/dgemm$ readelf -d $(R RHOME)/bin/Rscript | grep "NEEDED"
0x00000001 (NEEDED) Shared library: [libc.so.6]
在这里,我们需要选择Rscript
,因为R
loads libR.so
会自动加载参考BLAS libblas.so.3
:
~/Desktop/dgemm$ readelf -d $(R RHOME)/lib/libR.so | grep blas
0x00000001 (NEEDED) Shared library: [libblas.so.3]
~/Desktop/dgemm$ ls -l /etc/alternatives/libblas.so.3
... 31 May /etc/alternatives/libblas.so.3 -> /usr/lib/libblas/libblas.so.3.0
~/Desktop/dgemm$ readelf -d /usr/lib/libblas/libblas.so.3 | grep SONAME
0x0000000e (SONAME) Library soname: [libblas.so.3]
比较而言,Rscript
提供了一个更清洁的环境。
第2部分:OpenBLAS
从OpenBLAS下载源文件并使用简单的make
命令后,libopenblas-<arch>-<release>.so-<version>
可以生成表单的共享库。请注意,我们没有root权限来安装它;相反,我们将此库复制到我们的工作目录中~/Desktop/dgemm
,并将其重命名为libopenblas.so
。同时,我们必须使用name创建另一个副本libopenblas.so.0
,因为这是运行时加载程序将寻找的
SONAME :
~/Desktop/dgemm$ readelf -d libopenblas.so | grep "RPATH\|SONAME"
0x0000000e (SONAME) Library soname: [libopenblas.so.0]
请注意,RPATH
没有提供该属性,这意味着打算将该库放入其中/usr/lib
,我们应该调用ldconfig
将其添加到中ld.so.cache
。但是同样,我们没有root权限来执行此操作。实际上,如果能够做到,那么所有的困难都消除了。然后,我们可以update- alternatives --config libblas.so.3
用来将R有效地链接到OpenBLAS。
第3部分:C代码,Makefile和R代码
这是一个C脚本,用于mmperf.c
计算大小乘以2的平方矩阵的GFLOP N
:
#include <R.h>
#include <Rmath.h>
#include <Rinternals.h>
#include <R_ext/BLAS.h>
#include <sys/time.h>
/* standard C subroutine */
double mmperf (int n) {
/* local vars */
int n2 = n * n, tmp; double *A, *C, one = 1.0;
struct timeval t1, t2; double elapsedTime, GFLOPs;
/* simulate N-by-N matrix A */
A = (double *)calloc(n2, sizeof(double));
GetRNGstate();
tmp = 0; while (tmp < n2) {A[tmp] = runif(0.0, 1.0); tmp++;}
PutRNGstate();
/* generate N-by-N zero matrix C */
C = (double *)calloc(n2, sizeof(double));
/* time 'dgemm.f' for C <- A * A + C */
gettimeofday(&t1, NULL);
F77_CALL(dgemm) ("N", "N", &n, &n, &n, &one, A, &n, A, &n, &one, C, &n);
gettimeofday(&t2, NULL);
/* free memory */
free(A); free(C);
/* compute and return elapsedTime in microseconds (usec or 1e-6 sec) */
elapsedTime = (double)(t2.tv_sec - t1.tv_sec) * 1e+6;
elapsedTime += (double)(t2.tv_usec - t1.tv_usec);
/* convert microseconds to nanoseconds (1e-9 sec) */
elapsedTime *= 1e+3;
/* compute and return GFLOPs */
GFLOPs = 2.0 * (double)n2 * (double)n / elapsedTime;
return GFLOPs;
}
/* R wrapper */
SEXP R_mmperf (SEXP n) {
double GFLOPs = mmperf(asInteger(n));
return ScalarReal(GFLOPs);
}
这是一个简单的R脚本,mmperf.R
用于报告案例的GFLOPN = 2000
mmperf <- function (n) {
dyn.load("mmperf.so")
GFLOPs <- .Call("R_mmperf", n)
dyn.unload("mmperf.so")
return(GFLOPs)
}
GFLOPs <- round(mmperf(2000), 2)
cat(paste("GFLOPs =",GFLOPs, "\n"))
最后,有一个简单的makefile来生成共享库mmperf.so
:
mmperf.so: mmperf.o
gcc -shared -L$(shell pwd) -Wl,-rpath=$(shell pwd) -o mmperf.so mmperf.o -lopenblas
mmperf.o: mmperf.c
gcc -fpic -O2 -I$(shell Rscript --default-packages=base --vanilla -e 'cat(R.home("include"))') -c mmperf.c
将所有这些文件放在工作目录下~/Desktop/dgemm
,并进行编译:
~/Desktop/dgemm$ make
~/Desktop/dgemm$ readelf -d mmperf.so | grep "NEEDED\|RPATH\|SONAME"
0x00000001 (NEEDED) Shared library: [libopenblas.so.0]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000f (RPATH) Library rpath: [/home/zheyuan/Desktop/dgemm]
输出使我们确信OpenBLAS已正确链接,并且运行时加载路径已正确设置。
第4部分:在R中测试OpenBLAS
让我们做
~/Desktop/dgemm$ Rscript --default-packages=base --vanilla mmperf.R
请注意,我们的脚本仅需要base
R中的软件包,并--vanilla
用于忽略R启动时的所有用户设置。在我的笔记本电脑上,我的程序返回:
GFLOPs = 1.11
糟糕!这确实是参考BLAS性能,而不是OpenBLAS(大约8-9 GFLOP)。
第5部分:为什么?
老实说,我不知道为什么会这样。每个步骤似乎正常工作。调用R时会发生一些细微的变化吗?例如,由于某种原因,某些时候OpenBLAS库可能被引用BLAS覆盖吗?有什么解释和解决方案吗?谢谢!
为什么我的方法不起作用
首先,UNIX上的共享库旨在模仿存档库的工作方式(首先存在存档库)。特别是这意味着,如果您同时具有libfoo.so
和和libbar.so
,这两个定义符号foo
,则首先加载哪个库才是获胜的:所有对foo
程序中任何位置(包括from
libbar.so
)的引用都将绑定到的libfoo.so
s定义foo
。
这模仿了如果您将程序与libfoo.a
和链接时会发生的情况libbar.a
,并且两个存档库都定义了相同的符号foo
。有关存档链接的更多信息,请参见此处。
它应该是从上面清楚的是,如果libblas.so.3
和libopenblas.so.0
定义相同的符号集(他们 这样做
),如果libblas.so.3
被加载到进程,然后再从程序libopenblas.so.0
将 永远不会 被调用。
其次,您已经正确地决定了,由于R
直接链接到libR.so
,并且由于libR.so
直接链接到libblas.so.3
,因此可以确保libopenblas.so.0
赢得这场战斗。
但是,您 错误地 决定Rscript
比较好,但它不是:Rscript
是一个 很小的
二进制文件(我的系统上11K;比较2.4MB的libR.so
),它也几乎全部是exec
的R
。在strace
输出中看到这很简单:
strace -e trace=execve /usr/bin/Rscript --default-packages=base --vanilla /dev/null
execve("/usr/bin/Rscript", ["/usr/bin/Rscript", "--default-packages=base", "--vanilla", "/dev/null"], [/* 42 vars */]) = 0
execve("/usr/lib/R/bin/R", ["/usr/lib/R/bin/R", "--slave", "--no-restore", "--vanilla", "--file=/dev/null", "--args"], [/* 43 vars */]) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=89625, si_status=0, si_utime=0, si_stime=0} ---
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=89626, si_status=0, si_utime=0, si_stime=0} ---
execve("/usr/lib/R/bin/exec/R", ["/usr/lib/R/bin/exec/R", "--slave", "--no-restore", "--vanilla", "--file=/dev/null", "--args"], [/* 51 vars */]) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=89630, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++
这意味着在你的脚本开始执行的时候,libblas.so.3
已经被加载,libopenblas.so.0
将被加载的依赖mmperf.so
不会
真正 被用于任何东西。
是否有可能使其正常工作
大概。我可以想到两种可能的解决方案:
libopenblas.so.0
实际上libblas.so.3
R
针对重建整个软件包libopenblas.so
。对于#1,您需要ln -s libopenblas.so.0 libblas.so.3
,
然后libblas.so.3
通过LD_LIBRARY_PATH
适当设置来确保在系统副本之前找到您的副本。
这似乎为我工作:
mkdir /tmp/libblas
# pretend that libc.so.6 is really libblas.so.3
cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/libblas/libblas.so.3
LD_LIBRARY_PATH=/tmp/libblas /usr/bin/Rscript /dev/null
Error in dyn.load(file, DLLpath = DLLpath, ...) :
unable to load shared object '/usr/lib/R/library/stats/libs/stats.so':
/usr/lib/liblapack.so.3: undefined symbol: cgemv_
During startup - Warning message:
package ‘stats’ in options("defaultPackages") was not found
请注意我是如何得到错误的(我的“假装” libblas.so.3
没有定义期望的符号,因为它实际上是的副本libc.so.6
)。
您还可以通过以下方式确认libblas.so.3
要加载的版本:
LD_DEBUG=libs LD_LIBRARY_PATH=/tmp/libblas /usr/bin/Rscript /dev/null |& grep 'libblas\.so\.3'
91533: find library=libblas.so.3 [0]; searching
91533: trying file=/usr/lib/R/lib/libblas.so.3
91533: trying file=/usr/lib/x86_64-linux-gnu/libblas.so.3
91533: trying file=/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/amd64/server/libblas.so.3
91533: trying file=/tmp/libblas/libblas.so.3
91533: calling init: /tmp/libblas/libblas.so.3
对于#2,您说:
我没有要测试的计算机的root访问权限,因此无法实际链接到OpenBLAS。
但这似乎是个虚假的论点:如果可以构建libopenblas
,那么当然也可以构建自己的R
。
更新:
您在一开始提到libblas.so.3和libopenblas.so.0定义了相同的符号,这意味着什么?它们具有不同的SONAME,是否不足以通过系统区分它们?
符号和SONAME
有 没有 做对方。
您可以从输出中看到的符号readelf -Ws libblas.so.3
和readelf -Ws libopenblas.so.0
。与之相关的符号BLAS
,例如cgemv_
,将出现在两个库中。
您SONAME
可能 对Windows
感到困惑。DLL
Windows上的s设计完全不同。特别是,当FOO.DLL
进口象征bar
从BAR.DLL
, 两个 符号(名称bar
)
,并 在DLL
从该符号是进口的(BAR.DLL
)被记录在FOO.DLL
的进口表。
这使得它轻松拥有R
进口cgemv_
从BLAS.DLL
,而MMPERF.DLL
进口的相同符号的OPENBLAS.DLL
。
但是,这使库插入变得困难,并且与存档库的工作方式(甚至在Windows上)完全不同。
对于哪种设计总体上更好,人们意见不一,但是两种系统都不可能改变其模型。
UNIX有多种方法可以模拟Windows样式的符号绑定:请参见RTLD_DEEPBIND
dlopen
手册页。当心:这些问题充满危险,可能使UNIX专家困惑,没有被广泛使用,并且可能存在实现错误。
更新2:
您的意思是我编译R并将其安装在主目录下?
是。
然后,当我要调用它时,应该显式地给出我的可执行程序版本的路径,否则可能会调用系统上的路径?或者,我可以将此路径放在环境变量$
PATH的第一个位置以欺骗系统吗?
无论哪种方式都行。
我找了很多,但都不适合我。 我有一个全新的LAMP服务器安装,通过任务命令安装。我的系统运行的是 7.4 和 MySql 8 出于某种原因,root用户(在我的例子中默认称为phpmyadmin)对DB没有权限。 我可以登录,所以我确信密码是正确的,但我无法创建数据库。 编辑 如建议,这是 新编辑 我试图在没有密码的情况下访问,按照这里报告的指南:... 我没有结果:( 停止MySQL服务器:su
问题内容: 我不断收到此错误。 我正在使用mySQL Workbench,从中发现根的架构特权为空。根本没有特权。 我在使用服务器的平台上遇到了麻烦,这是一个突然的问题。 root@127.0.0.1 显然具有很多访问权限,但我已以此身份登录,但无论如何它只是分配给localhost-本地主机没有特权。 我做了一些类似,,等等的事情,但是从那儿或互联网上都没有找到成功。 如何获得根对其访问的权限?
问题内容: 尝试去 并再次发生同样臭名昭著的错误/警告(无济于事): 似乎发生的是,尽管是我计算机上的当前节点版本,但在同一安装过程中一次又一次地下载并重建它: 问题: 实际上缺少目录“ /Users/dmitrizaitsev/.node-gyp/0.12.0”!为什么会有这样的误导性消息? 为什么在和之前成功重建期间都没有创建此目录? (显然)如何防止这种情况发生? 如果这很重要,我可以运行M
问题内容: 此处有一篇文章:https : //gist.github.com/JonathanRaiman/f2ce5331750da7b2d4e9,通过仅调用Fortran库(BLAS / LAPACK / Intel MKL / OpenBLAS /随NumPy一起安装的任何库),都显示了极大的速度改进。经过数小时的研究(由于不建议使用的SciPy库),我终于得到了编译,但没有结果。它比Nu
blas 是一款开发包收集器,为 Go 语言提供 BLAS 功能。 安装: go get github.com/gonum/blas BLAS C-绑定: 如果你想使用 OpenBLAS,可在任何目录安装(更多信息,可在 cgo command documentation中查看): git clone https://github.com/xianyi/OpenBLAS cd OpenBLAS
我不断收到这个错误。 我使用的是mySQL Workbench,我发现root的模式特权为空。根本没有特权。 我在我的服务器所使用的平台上遇到了麻烦,这是一个突如其来的问题。 root@127.0.0.1显然有很多访问权限,但我是以这个身份登录的,但它只是分配给localhost-localhost没有特权。 我已经做了一些事情,如,等,但没有发现成功的从它或互联网。 我如何恢复root的访问权限