Führen Sie R ohne Root-Zugriff mit optimiertem BLAS aus, wenn es mit dem Verweis BLAS @ verknüpft is
Kann mir jemand sagen, warum ich kannnicht erfolgreich test OpenBLAS'sdgemm
Leistung (in GFLOPs) in R über den folgenden Weg?
libblas.so
kompiliere mein C Programmmmperf.c
mit OpenBLAS Bibliotheklibopenblas.so
aden Sie die resultierende gemeinsam genutzte Bibliothemmperf.so
in R, rufe die R-Wrapper-Funktion aufmmperf
und reportdgemm
Leistung in GFLOPs.Point 1 sieht seltsam aus, aber ich habe keine andere Wahl, da ich auf den zu testenden Computern keinen Root-Zugriff habe, sodass eine tatsächliche Verknüpfung mit OpenBLAS unmöglich ist. Durch "nicht erfolgreich" Ich meine mein Programm endet Berichterstattungdgemm
performance als Referenz BLAS anstelle von OpenBLAS. Ich hoffe mir kann jemand erklären:
main
funktionieren und meine Arbeit in einem C-Programm erledigen.)Ich habe dieses Problem zwei Tage lang untersucht. Hier werden verschiedene Systemausgaben aufgeführt, die Sie bei der Diagnose unterstützen. Um die Dinge reproduzierbar zu machen, werde ich auch den Code, das Makefile sowie den Shell-Befehl einfügen.
Teil 1: Systemumgebung vor dem Testen
Es gibt zwei Möglichkeiten, R aufzurufen, entweder mitR
oderRscript
. Es gibt einige Unterschiede, was geladen wird, wenn sie aufgerufen werden:
~/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]
Hier müssen wir @ wählRscript
, weilR
LadungenlibR.so
, das automatisch die Referenz BLAS @ lä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]
VergleichsweiseRscript
sorgt für eine sauberere Umwelt.
Teil 2: OpenBLAS
Nach dem Herunterladen der Quelldatei von OpenBLAS und ein einfachesmake
command, eine gemeinsam genutzte Bibliothek der Formlibopenblas-<arch>-<release>.so-<version>
kann generiert werden. Beachten Sie, dass wir keinen Root-Zugriff haben, um es zu installieren. Stattdessen kopieren wir diese Bibliothek in unser Arbeitsverzeichnis~/Desktop/dgemm
und benenne es einfach um inlibopenblas.so
. Gleichzeitig müssen wir eine weitere Kopie mit dem Namen @ erstellelibopenblas.so.0
, da dies das @ i SONAME nach welchem Laufzeit-Loader gesucht wird:
~/Desktop/dgemm$ readelf -d libopenblas.so | grep "RPATH\|SONAME"
0x0000000e (SONAME) Library soname: [libopenblas.so.0]
Notiere dass derRPATH
-Attribut ist nicht angegeben, was bedeutet, dass diese Bibliothek in @ abgelegt werden sol/usr/lib
und wir sollten @ anrufldconfig
um es zu @ hinzuzufügld.so.cache
. Aber auch hier haben wir keinen Root-Zugriff. In der Tat, wenn dies getan werden kann, dann sind alle Schwierigkeiten verschwunden. Wir könnten dann @ verwendupdate-alternatives --config libblas.so.3
, um R effektiv mit OpenBLAS zu verknüpfen.
Teil 3: C-Code, Makefile und R-Code
Hier ist ein C-Skriptmmperf.c
Berechnung von GFLOPs zum Multiplizieren von 2 Quadratmatrizen der GrößeN
:
#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);
}
Hier ist ein einfaches R-Skriptmmperf.R
um GFLOPs für case @ zu meldN = 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"))
Abschließend gibt es ein einfaches Makefile, um die gemeinsam genutzte Bibliothek zu generierenmmperf.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
Legen Sie all diese Dateien unter das Arbeitsverzeichnis~/Desktop/dgemm
und kompiliere es:
~/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]
Die Ausgabe versichert uns, dass OpenBLAS korrekt verknüpft ist und der Laufzeit-Ladepfad korrekt festgelegt wurde.
Teil 4: Testen von OpenBLAS in R
Lass es uns tu
~/Desktop/dgemm$ Rscript --default-packages=base --vanilla mmperf.R
Hinweis unser Skript benötigt nur dasbase
Paket in R und--vanilla
wird verwendet, um alle Benutzereinstellungen beim Start von R zu ignorieren. Auf meinem Laptop kehrt mein Programm zurück:
GFLOPs = 1.11
Hoppla! Dies ist wirklich eine Referenz für die BLAS-Leistung, nicht für OpenBLAS (das sind etwa 8-9 GFLOPs).
Teil 5: Warum?
Um ehrlich zu sein, ich weiß nicht, warum das passiert. Jeder Schritt scheint korrekt zu funktionieren. Tritt etwas Feines auf, wenn R aufgerufen wird? Gibt es zum Beispiel die Möglichkeit, dass die OpenBLAS-Bibliothek aus irgendeinem Grund von Referenz-BLAS überschrieben wird? Irgendwelche Erklärungen und Lösungen? Vielen Dank