如果没有root用户访问权限,请在将RLAS与参考BLAS链接时使用已调整的BLAS运行R [英] Without root access, run R with tuned BLAS when it is linked with reference BLAS

查看:114
本文介绍了如果没有root用户访问权限,请在将RLAS与参考BLAS链接时使用已调整的BLAS运行R的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以告诉我为什么我不能通过以下方式未成功在R中测试OpenBLAS的dgemm性能(在GFLOP中)吗?

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

第1点看起来很奇怪,但是我别无选择,因为我在要测试的机器上没有root访问权限,因此无法实际链接到OpenBLAS. 未成功" ,是指我的程序最终报告了参考BLAS(而非OpenBLAS)的dgemm性能.我希望有人可以向我解释:

  1. 为什么我的方法行不通;
  2. 是否有可能使其正常工作(这很重要,因为如果不可能,我必须编写一个C main函数并在C程序中完成工作.)

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

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

有两种方法可以使用RRscript来调用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 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命令后,共享库的格式为<可以生成c17>.请注意,我们没有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,用于计算将大小为N的2个平方矩阵相乘的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, &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,用于报告案例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 -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

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

GFLOPs = 1.11

糟糕!这确实是参考BLAS性能,而不是OpenBLAS(大约8-9 GFLOP).

第5部分:为什么?

说实话,我不知道为什么会这样.每个步骤似乎都能正常工作.调用R时会发生一些细微的变化吗?例如,由于某种原因,某些时候OpenBLAS库可能被引用BLAS覆盖吗?有什么解释和解决方案吗?谢谢!

解决方案

为什么我的方法不起作用

首先,UNIX上的共享库旨在模仿存档库的工作方式(首先存在存档库).特别是,这意味着如果同时具有符号foolibfoo.solibbar.so,则首先加载的库是赢的那个:在程序中任何位置(包括libbar.so)将绑定到foofoo定义.

这模仿了如果您将程序链接到libfoo.alibbar.a时会发生的情况,这两个存档库都定义了相同的符号foo. 此处.. >

从上面应该清楚的是,如果libblas.so.3libopenblas.so.0定义了相同的符号集(它们是 do ),并且如果libblas.so.3首先被加载到进程中,那么libopenblas.so.0中的例程将从不被调用.

第二,您已经正确地确定,由于R直接链接到libR.so,并且libR.so直接链接到libblas.so.3,因此可以保证libopenblas.so.0会输掉这场战斗.

但是,您错误地认为Rscript更好,但事实并非如此:Rscript tiny 二进制文件(在我的系统上为11K;相比于2.4MB (libR.so),并且几乎全部是R中的exec.在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已被加载,而将作为mmperf.so依赖项加载的libopenblas.so.0不会实际上用于任何事情

是否有可能使其正常工作

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

  1. 假装libopenblas.so.0实际上是libblas.so.3
  2. 针对libopenblas.so重建整个R软件包.

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

这似乎对我有用:

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.3readelf -Ws libopenblas.so.0的输出中看到符号.与BLAS相关的符号,例如cgemv_,将出现在两个库中.

您对SONAME 可能的困惑来自Windows. Windows上的DLL设计完全不同.特别是,当FOO.DLLBAR.DLL导入符号bar时,两者的符号名称(bar)符号已导入(BAR.DLL)记录在FOO.DLL导入表中.

这使得RBLAS.DLL导入cgemv_很容易,而MMPERF.DLLOPENBLAS.DLL导入相同的符号.

但是,这使库插入很难,并且其工作方式与存档库的工作方式(甚至在Windows中)完全不同.

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

UNIX有多种方法可以模拟Windows样式的符号绑定:请参见dlopen中的RTLD_DEEPBIND 手册页.当心:这些问题充满了危险,可能使UNIX专家困惑,没有被广泛使用,并且可能存在实现错误.

更新2:

您是说我编译R并将其安装在主目录下?

是的

然后,当我要调用它时,我应该显式地给出我的可执行程序版本的路径,否则系统上的那个可能会被调用?或者,我可以将此路径放在环境变量$ PATH的第一个位置以欺骗系统吗?

这两种方法都可以.

Can any one tell me why I can not successfully test OpenBLAS's dgemm performance (in GFLOPs) in R via the following way?

  1. link R with the "reference BLAS" libblas.so
  2. compile my C program mmperf.c with OpenBLAS library libopenblas.so
  3. load the resulting shared library mmperf.so into R, call the R wrapper function mmperf and report dgemm performance in GFLOPs.

Point 1 looks strange, but I have no choice because I have no root access on machines I want to test, so actual linking to OpenBLAS is impossible. By "not successfully" I mean my program ends up reporting dgemm performance for reference BLAS instead of OpenBLAS. I hope someone can explain to me:

  1. why my way does not work;
  2. is it possible at all to make it work (this is important, because if it is impossible, I must write a C main function and do my job in a C program.)

I've investigated into this issue for two days, here I will include various system output to assist you to make a diagnose. To make things reproducible, I will also include the code, makefile as well as shell command.

Part 1: system environment before testing

There are 2 ways to invoke R, either using R or Rscript. There are some differences in what is loaded when they are invoked:

~/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]

Here we need to choose Rscript, because R loads libR.so, which will automatically load the reference 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]

Comparatively, Rscript gives a cleaner environment.

Part 2: OpenBLAS

After downloading source file from OpenBLAS and a simple make command, a shared library of the form libopenblas-<arch>-<release>.so-<version> can be generated. Note that we will not have root access to install it; instead, we copy this library into our working directory ~/Desktop/dgemm and rename it simply to libopenblas.so. At the same time we have to make another copy with name libopenblas.so.0, as this is the SONAME which run time loader will seek for:

~/Desktop/dgemm$ readelf -d libopenblas.so | grep "RPATH\|SONAME"
0x0000000e (SONAME)         Library soname: [libopenblas.so.0]

Note that the RPATH attribute is not given, which means this library is intended to be put in /usr/lib and we should call ldconfig to add it to ld.so.cache. But again we don't have root access to do this. In fact, if this can be done, then all the difficulties are gone. We could then use update-alternatives --config libblas.so.3 to effectively link R to OpenBLAS.

Part 3: C code, Makefile, and R code

Here is a C script mmperf.c computing GFLOPs of multiplying 2 square matrices of size 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);
  }

Here is a simple R script mmperf.R to report GFLOPs for case N = 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"))

Finally there is a simple makefile to generate the shared library 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

Put all these files under working directory ~/Desktop/dgemm, and compile it:

~/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]

The output reassures us that OpenBLAS is correctly linked, and the run time load path is correctly set.

Part 4: testing OpenBLAS in R

Let's do

~/Desktop/dgemm$ Rscript --default-packages=base --vanilla mmperf.R

Note our script needs only the base package in R, and --vanilla is used to ignore all user settings on R start-up. On my laptop, my program returns:

GFLOPs = 1.11

Oops! This is truely reference BLAS performance not OpenBLAS (which is about 8-9 GFLOPs).

Part 5: Why?

To be honest, I don't know why this happens. Each step seems to work correctly. Does something subtle occurs when R is invoked? For example, any possibility that OpenBLAS library is overridden by reference BLAS at some point for some reason? Any explanations and solutions? Thanks!

解决方案

why my way does not work

First, shared libraries on UNIX are designed to mimic the way archive libraries work (archive libraries were there first). In particular that means that if you have libfoo.so and libbar.so, both defining symbol foo, then whichever library is loaded first is the one that wins: all references to foo from anywhere within the program (including from libbar.so) will bind to libfoo.sos definition of foo.

This mimics what would happen if you linked your program against libfoo.a and libbar.a, where both archive libraries defined the same symbol foo. More info on archive linking here.

It should be clear from above, that if libblas.so.3 and libopenblas.so.0 define the same set of symbols (which they do), and if libblas.so.3 is loaded into the process first, then routines from libopenblas.so.0 will never be called.

Second, you've correctly decided that since R directly links against libR.so, and since libR.so directly links against libblas.so.3, it is guaranteed that libopenblas.so.0 will lose the battle.

However, you erroneously decided that Rscript is better, but it's not: Rscript is a tiny binary (11K on my system; compare to 2.4MB for libR.so), and approximately all it does is exec of R. This is trivial to see in strace output:

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 +++

Which means that by the time your script starts executing, libblas.so.3 has been loaded, and libopenblas.so.0 that will be loaded as a dependency of mmperf.so will not actually be used for anything.

is it possible at all to make it work

Probably. I can think of two possible solutions:

  1. Pretend that libopenblas.so.0 is actually libblas.so.3
  2. Rebuild entire R package against libopenblas.so.

For #1, you need to ln -s libopenblas.so.0 libblas.so.3, then make sure that your copy of libblas.so.3 is found before the system one, by setting LD_LIBRARY_PATH appropriately.

This appears to work for me:

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

Note how I got an error (my "pretend" libblas.so.3 doesn't define symbols expected of it, since it's really a copy of libc.so.6).

You can also confirm which version of libblas.so.3 is getting loaded this way:

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

For #2, you said:

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

but that seems to be a bogus argument: if you can build libopenblas, surely you can also build your own version of R.

Update:

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?

The symbols and the SONAME have nothing to do with each other.

You can see symbols in the output from readelf -Ws libblas.so.3 and readelf -Ws libopenblas.so.0. Symbols related to BLAS, such as cgemv_, will appear in both libraries.

Your confusion about SONAME possibly comes from Windows. The DLLs on Windows are designed completely differently. In particular, when FOO.DLL imports symbol bar from BAR.DLL, both the name of the symbol (bar) and the DLL from which that symbol was imported (BAR.DLL) are recorded in the FOO.DLLs import table.

That makes it easy to have R import cgemv_ from BLAS.DLL, while MMPERF.DLL imports the same symbol from OPENBLAS.DLL.

However, that makes library interpositioning hard, and works completely differently from the way archive libraries work (even on Windows).

Opinions differ on which design is better overall, but neither system is likely to ever change its model.

There are ways for UNIX to emulate Windows-style symbol binding: see RTLD_DEEPBIND in dlopen man page. Beware: these are fraught with peril, likely to confuse UNIX experts, are not widely used, and likely to have implementation bugs.

Update 2:

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

Yes.

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?

Either way works.

这篇关于如果没有root用户访问权限,请在将RLAS与参考BLAS链接时使用已调整的BLAS运行R的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆