如果没有root访问权限,则在与参考BLAS链接时使用调优的BLAS运行R.

如果没有root访问权限,则在与参考BLAS链接时使用调优的BLAS运行R.,第1张

概述任何人都可以告诉我为什么我不能通过以下方式成功测试R中OpenBLAS的dgemm性能(在GFLOP中)? >链接R与“参考BLAS”libblas.so >使用OpenBLAS库libopenblas.so编译我的C程序mmperf.c >将生成的共享库mmperf.so加载到R中,调用R包装函数mmperf并在GFLOP中报告dgemm性能. 第1点看起来很奇怪,但我别无选择,因为我在我想测试 任何人都可以告诉我为什么我不能通过以下方式成功测试R中OpenBLAS的dgemm性能(在GFLOP中)?

>链接R与“参考BLAS”libblas.so
>使用OpenBLAS库libopenblas.so编译我的C程序mmperf.c
>将生成的共享库mmperf.so加载到R中,调用R包装函数mmperf并在GFLOP中报告dgemm性能.

第1点看起来很奇怪,但我别无选择,因为我在我想测试的机器上没有root访问权限,所以实际链接到OpenBLAS是不可能的. “不成功”我的意思是我的程序最终报告dgemm性能参考BLAS而不是OpenBLAS.我希望有人可以向我解释一下:

>为什么我的方式不起作用;
>是否有可能使它工作(这很重要,因为如果不可能,我必须编写一个C main函数并在C程序中完成我的工作.)

我已经调查了这个问题两天,在这里我将包括各种系统输出,以帮助您进行诊断.为了使事情可以重现,我还将包括代码,makefile以及shell命令.

第1部分:测试前的系统环境

有两种方法可以使用R或Rscript来调用R.调用它们时加载的内容有一些差异:

~/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加载libR.so,它会自动加载引用BLAS libblas.so.3:

~/Desktop/dgemm$readelf -d $(R RHOME)/lib/libR.so | grep blas0x00000001 (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 SOname0x0000000e (SOname)         library soname: [libblas.so.3]

相比之下,Rscript提供了一个更清洁的环境.

第2部分:OpenBLAS

从OpenBLAS下载源文件和简单的make命令后,形式为libopenblas-< arch> – < release> .so-< version>的共享库.可以生成.请注意,我们没有root权限来安装它;相反,我们将这个库复制到我们的工作目录〜/ Desktop / dgemm中,并将其重命名为libopenblas.so.同时我们必须创建另一个名为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个大小为N的矩阵的GFLOP:

#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,&one,A,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,用于报告案例N = 2000的GFLOP

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 -lopenblasmmperf.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

注意我们的脚本只需要R中的基本包,而–vanilla用于忽略R启动时的所有用户设置.在我的笔记本电脑上,我的程序返回

GFLOPs = 1.11

哎呀!这确实是参考BLAS性能而不是OpenBLAS(约为8-9 GFLOP).

第5部分:为什么?

说实话,我不知道为什么会这样.每个步骤似乎都正常工作.调用R时是否会发生微妙的事情?例如,出于某种原因,某些时候参考BLAS会覆盖OpenBLAS库的任何可能性吗?任何解释和解决方案?谢谢!

解决方法

why my way does not work

首先,UNIX上的共享库旨在模仿归档库的工作方式(归档库首先存在).特别是这意味着如果你有libfoo.so和libbar.so,两者都定义符号foo,那么首先加载的是获胜者:从程序中的任何地方(包括来自libbar.so)对foo的所有引用都将绑定到foo的libfoo.sos定义.

这模仿了如果将程序与libfoo.a和libbar.a链接起来会发生什么,其中两个归档库都定义了相同的符号foo.有关存档链接here的更多信息.

从上面应该清楚,如果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;相比之下,libR.so是2.4MB),而且它所做的几乎都是R的执行.这是微不足道的.在strace输出:

strace -e trace=execve /usr/bin/Rscript --default-packages=base --vanilla /dev/nullexecve("/usr/bin/Rscript",["/usr/bin/Rscript","--default-packages=base","--vanilla","/dev/null"],[/* 42 vars */]) = 0execve("/usr/lib/R/bin/R",["/usr/lib/R/bin/R","--slave","--no-restore","--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_pID=89626,si_stime=0} ---execve("/usr/lib/R/bin/exec/R",["/usr/lib/R/bin/exec/R",[/* 51 vars */]) = 0--- SIGCHLD {si_signo=SIGCHLD,si_pID=89630,si_stime=0} ---+++ exited with 0 +++

这意味着当脚本开始执行时,已经加载了libblas.so.3,并且将作为mmperf.so的依赖项加载的libopenblas.so.0实际上不会用于任何事情.

is it possible at all to make it work

大概.我可以想到两种可能的解决方案:

>假设libopenblas.so.0实际上是libblas.so.3
>针对libopenblas.so重建整个R包.

对于#1,你需要ln -s libopenblas.so.0 libblas.so.3,然后通过适当地设置LD_liBRARY_PATH,确保在系统之前找到你的libblas.so.3副本.

这似乎对我有用:

mkdir /tmp/libblas# pretend that libc.so.6 is really libblas.so.3cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/libblas/libblas.so.3LD_liBRARY_PATH=/tmp/libblas /usr/bin/Rscript /dev/nullError 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,你说:

I have no root access on machines I want to test,so actual linking to OpenBLAS is impossible.

但这似乎是一个虚假的论点:如果你可以构建libopenblas,当然你也可以构建自己的R版本.

更新:

You mentioned in the beginning that libblas.so.3 and libopenblas.so.0 define the same symbol,what does this mean? They have different SOname,is that insufficIEnt to distinguish them by the system?

符号和SOname彼此无关.

您可以在readelf -Ws libblas.so.3和readelf -Ws libopenblas.so.0的输出中看到符号.与BLAS相关的符号(如cgemv_)将出现在两个库中.

您对SOname的困惑可能来自windows. windows上的DLL设计完全不同.特别是,当FOO.DLL从bar.DLL导入符号栏时,符号(bar)的名称和导入该符号的DLL(bar.DLL)都记录在FOO.DLLs导入表中.

这样可以很容易地从BLAS.DLL导入R import cgemv_,而MMPERF.DLL从OPENBLAS.DLL导入相同的符号.

但是,这使得library interpositioning很难,并且与归档库的工作方式完全不同(即使在windows上).

关于哪种设计总体上更好的意见不同,但两种系统都不可能改变其模型.

UNIX可以通过多种方式模拟windows样式的符号绑定:请参阅dlopen man page中的RTLD_DEEPBIND.注意:这些都充满了危险,可能会使UNIX专家感到困惑,没有被广泛使用,并且可能存在实施错误.

更新2:

you mean I compile R and install it under my home directory?

是.

Then when I want to invoke it,I should explicitly give the path to my version of executable program,otherwise the one on the system might be invoked instead? Or,can I put this path at the first position of environment variable $PATH to cheat the system?

无论哪种方式都有效.

总结

以上是内存溢出为你收集整理的如果没有root访问权限,则在与参考BLAS链接时使用调优的BLAS运行R.全部内容,希望文章能够帮你解决如果没有root访问权限,则在与参考BLAS链接时使用调优的BLAS运行R.所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1027976.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存