Может ли кто-нибудь сказать мне, почему я могу не успешно проверить производительность OpenBLAS dgemm
(в GFLOP) в R следующим образом?Без доступа к корню, запустите R с настроенным BLAS, когда он связан со ссылкой BLAS
- ссылка R с «эталонным BLAS»
libblas.so
- компилироваться C программе
mmperf.c
с библиотекой OpenBLASlibopenblas.so
- нагрузки в результате общей библиотеки
mmperf.so
в R, вызовите функцию R оберткиmmperf
и сообщитьdgemm
производительности в GFlops.
Пункт 1 выглядит странно, но у меня нет выбора, потому что у меня нет доступа к корню на машинах, которые я хочу проверить, поэтому фактическое соединение с OpenBLAS невозможно. К «не успешно» Я имею в виду, что моя программа заканчивается сообщением dgemm
для ссылки BLAS вместо OpenBLAS. Я надеюсь, что кто-то может мне объяснить:
- Почему мой способ не работает;
- это вообще возможно, чтобы заставить его работать (это важно, потому что если это невозможно, я должен написать функцию C
main
и делать свою работу в программе C.)
Я исследовал в этот вопрос в течение двух дней, здесь я буду включать различные системные выходы, чтобы помочь вам сделать диагноз. Чтобы сделать вещи воспроизводимыми, я также буду включать код, makefile, а также команду оболочки.
Часть 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
нагрузки 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
.В то же время, мы должны сделать еще одну копию с именем libopenblas.so.0
, так как это игнорирован, который во время выполнения загрузчик будет искать:
~/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: код С, Makefile, и R код
Здесь A C сценарий mmperf.c
вычислительные GFlops умножения 2 квадратных матриц размера 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);
}
Вот простой Р сценарий mmperf.R
сообщать GFlops для случая 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"))
Наконец, есть простой 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: тестирование OpenBLAS в R
Давайте
~/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 в какой-то момент по какой-то причине? Любые объяснения и решения? Благодаря!
Пробовали ли вы иметь '.' первым в своем LD_LIBRARY_PATH? –
Благодарим вас за то, что вы хотите суммировать материал на этой странице, Zheyuan - однако, пожалуйста, не делайте этого! Золотое правило с сайтами Q & A заключается в том, чтобы сохранить этот вопрос в значительной степени, как вы видели ситуацию, прежде чем обнаружили ответ. Вопрос, содержащий преамбулу, относящуюся к частям ответа, уже не является вопросом, и он отклоняется от формата Q & A, который мы предпочитаем. Вы можете добавить свое резюме в свой ответ, но я не думаю, что это необходимо. (Мы также не редактируем [решенные] сообщения в заголовки - сохраняйте их оригинальными тоже!). – halfer