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?

link R mit der "Referenz BLAS"libblas.sokompiliere mein C Programmmmperf.c mit OpenBLAS Bibliotheklibopenblas.soaden 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:

warum mein Weg nicht funktioniert; ist es überhaupt möglich, es zum Laufen zu bringen (das ist wichtig, denn wenn es unmöglich ist, muss ich ein C schreibenmain 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

Antworten auf die Frage(6)

Ihre Antwort auf die Frage