Без корневого доступа, запустите R с настроенным BLAS, когда он связан с эталонным BLAS

Может кто-нибудь сказать мне, почему я не могу успешно протестировать OpenBLAS dgemm производительность (в GFLOP) в R следующим образом?

  1. ссылка R с "ссылкой BLAS" libblas.so
  2. скомпилировать мою C программу mmperf.c с библиотекой OpenBLAS libopenblas.so
  3. загрузить получившуюся общую библиотеку mmperf.so в R, вызвать функцию оболочки R mmperf и сообщить dgemm производительность в GFLOP.

Точка 1 выглядит странно, но у меня нет выбора, потому что у меня нет доступа с правами root на машинах, которые я хочу протестировать, поэтому фактическое соединение с OpenBLAS невозможно. Под "не успешно" я имею в виду, что моя программа в конечном итоге сообщает dgemm производительность для справки BLAS вместо OpenBLAS. Я надеюсь, что кто-то может объяснить мне:

  1. почему мой путь не работает;
  2. Можно ли вообще заставить его работать (это важно, потому что, если это невозможно, я должен написать C main работать и выполнять свою работу в программе на Си.)

Я исследовал эту проблему в течение двух дней, здесь я включу различные выходные данные системы, чтобы помочь вам поставить диагноз. Чтобы сделать вещи воспроизводимыми, я также включу код, makefile и команду shell.

Часть 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, поскольку это 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 вычисление GFLOP умножения 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);
  }

Вот простой скрипт R 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"))

Наконец, есть простой make-файл для генерации разделяемой библиотеки. 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 в какой-то момент по какой-то причине? Есть объяснения и решения? Спасибо!

3 ответа

Решение

почему мой путь не работает

Во-первых, разделяемые библиотеки в UNIX предназначены для имитации работы архивных библиотек (сначала там были архивные библиотеки). В частности это означает, что если у вас есть libfoo.so а также libbar.soоба определяющих символа fooто, какая библиотека загружается первой, выигрывает: все ссылки на foo из любой точки программы (в том числе из libbar.so) будет привязан к libfoo.soопределение foo,

Это имитирует то, что произошло бы, если бы вы связали свою программу с libfoo.a а также libbar.aгде обе архивные библиотеки определяют один и тот же символ foo, Более подробную информацию о архиве ссылки здесь.

Сверху должно быть ясно, что если 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 крошечный двоичный файл (11 КБ в моей системе; сравните с 2,4 МБ для libR.so), и примерно все, что он делает, это exec из R, Это тривиально видеть в 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 был загружен, и libopenblas.so.0 который будет загружен как зависимость mmperf.so на самом деле не будет использоваться ни для чего.

можно ли вообще заставить это работать

Наверное. Я могу придумать два возможных решения:

  1. Притворись, что libopenblas.so.0 на самом деле libblas.so.3
  2. Перестроить весь R пакет против libopenblas.so,

Для #1 вам нужно ln -s libopenblas.so.0 libblas.so.3затем убедитесь, что ваша копия libblas.so.3 находится до системного, путем установки LD_LIBRARY_PATH соответственно.

Похоже, это работает для меня:

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.3 а также readelf -Ws libopenblas.so.0, Символы, связанные с BLAS, такие как cgemv_, появится в обеих библиотеках.

Ваше замешательство по поводу SONAME возможно происходит из Windows. DLLS на Windows разработаны совершенно по-другому. В частности, когда FOO.DLL символ импорта bar от BAR.DLL, оба название символа (bar) и DLL из которого этот символ был импортирован (BAR.DLL) записаны в FOO.DLLТаблица импорта.

Это позволяет легко иметь R Импортировать cgemv_ от BLAS.DLL, в то время как MMPERF.DLL импортирует тот же символ из OPENBLAS.DLL,

Однако это затрудняет вставку библиотеки и работает совершенно иначе, чем работа архивных библиотек (даже в Windows).

Мнения расходятся в том, какой дизайн лучше в целом, но ни одна из систем, вероятно, никогда не изменит свою модель.

В UNIX есть способы эмулировать привязку символов в стиле Windows: см. RTLD_DEEPBIND в справочной странице dlopen. Осторожно: это чревато опасностями, которые могут запутать экспертов по UNIX, не используются широко и могут иметь ошибки при реализации.

Обновление 2:

ты имеешь в виду, что я компилирую R и устанавливаю его в своем домашнем каталоге?

Да.

Затем, когда я хочу вызвать его, я должен явно указать путь к моей версии исполняемой программы, в противном случае вместо этого может быть вызван тот, что в системе? Или я могу поместить этот путь в первую позицию переменной среды $PATH, чтобы обмануть систему?

В любом случае работает.

*********************

Решение 2:

*********************

Здесь мы предлагаем другое решение, используя переменную среды LD_PRELOAD упоминается в нашем решении 1. Использование LD_PRELOAD является более "жестоким", так как он заставляет загружать данную библиотеку в программу перед любой другой программой, даже перед библиотекой C libc.so! Это часто используется для срочного исправления в разработке Linux.

Как показано во второй части оригинального сообщения, общая библиотека BLAS libopenblas.so имеет SONAME libopenblas.so.0, SONAME - это внутреннее имя, которое динамический библиотечный загрузчик будет искать во время выполнения, поэтому нам нужно сделать символическую ссылку на libopenblas.so с этим SONAME:

~/Desktop/dgemm$ ln -sf libopenblas.so libopenblas.so.0

тогда мы экспортируем это:

~/Desktop/dgemm$ export LD_PRELOAD=$(pwd)/libopenblas.so.0

Обратите внимание, что полный путь к libopenblas.so.0 нужно кормить LD_PRELOAD для успешной загрузки, даже если libopenblas.so.0 находится под $(pwd),

Теперь мы запускаем Rscript и проверить, что происходит LD_DEBUG:

~/Desktop/dgemm$ LD_DEBUG=libs Rscript --default-packages=base --vanilla /dev/null |& grep blas
  4860: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4860: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4865: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4868: calling fini: /home/zheyuan/Desktop/dgemm/libopenblas.so [0]
  4870: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4869: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4867: calling fini: /home/zheyuan/Desktop/dgemm/libopenblas.so [0]
  4860: find library=libblas.so.3 [0]; searching
  4860:   trying file=/usr/lib/R/lib/libblas.so.3
  4860:   trying file=/usr/lib/i386-linux-gnu/i686/sse2/libblas.so.3
  4860:   trying file=/usr/lib/i386-linux-gnu/i686/cmov/libblas.so.3
  4860:   trying file=/usr/lib/i386-linux-gnu/i686/libblas.so.3
  4860:   trying file=/usr/lib/i386-linux-gnu/sse2/libblas.so.3
  4860:   trying file=/usr/lib/i386-linux-gnu/libblas.so.3
  4860:   trying file=/usr/lib/jvm/java-7-openjdk-i386/jre/lib/i386/client/libblas.so.3
  4860:   trying file=/usr/lib/libblas.so.3
  4860: calling init: /usr/lib/libblas.so.3
  4860: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4874: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4876: calling init: /home/zheyuan/Desktop/dgemm/libopenblas.so
  4860: calling fini: /home/zheyuan/Desktop/dgemm/libopenblas.so [0]
  4860: calling fini: /usr/lib/libblas.so.3 [0]

Сравнивая с тем, что мы видели в решении 1, обманывая R с нашей собственной версией libblas.so.3, мы это видим

  • libopenblas.so.0 загружается первым, следовательно, сначала Rscript;
  • после libopenblas.so.0 найден, Rscript продолжает поиск и загрузку libblas.so.3, Однако это не повлияет на правило "первым пришел, первым обслужен", объясненное в исходном ответе.

Хорошо, все работает, поэтому мы проверяем наши mmperf.c программа:

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

Результат 9,62 больше, чем 8,77, который мы видели в предыдущем решении просто случайно. В качестве теста для использования OpenBLAS мы не проводим эксперимент много раз для получения более точного результата.

Затем, как обычно, мы сбрасываем переменную окружения в конце:

~/Desktop/dgemm$ unset LD_PRELOAD

*********************

Решение 1:

*********************

Благодаря Employed Russian моя проблема наконец-то решена. Расследование требует важных навыков в отладке и исправлении системы Linux, и я считаю, что это большой опыт, который я усвоил. Здесь я хотел бы опубликовать решение, а также исправить несколько пунктов в моем исходном сообщении.

1 О вызове R

В моем оригинальном сообщении я упоминал, что есть два способа запустить R, либо через R или же Rscript, Однако я неправильно преувеличивал их разницу. Давайте теперь исследуем их процесс запуска с помощью важного средства отладки Linux strace (увидеть man strace). На самом деле после ввода команды в оболочке происходит множество интересных вещей, и мы можем использовать

strace -e trace=process [command]

отслеживать все системные вызовы, связанные с управлением процессами. В результате мы можем наблюдать за этапами обработки, ожидания и выполнения процесса. @Employed Russian, хотя и не указано на странице руководства, показывает, что можно указать только подкласс process, например, execve для выполнения шагов.

За R у нас есть

~/Desktop/dgemm$ time strace -e trace=execve R --vanilla < /dev/null > /dev/null
execve("/usr/bin/R", ["R", "--vanilla"], [/* 70 vars */]) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5777, si_status=0, si_utime=0, si_stime=0} ---
execve("/usr/lib/R/bin/exec/R", ["/usr/lib/R/bin/exec/R", "--vanilla"], [/* 79 vars */]) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5778, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

real    0m0.345s
user    0m0.256s
sys     0m0.068s

в то время как для Rscript у нас есть

~/Desktop/dgemm$ time strace -e trace=execve Rscript --default-packages=base --vanilla /dev/null
execve("/usr/bin/Rscript", ["Rscript", "--default-packages=base", "--vanilla", "/dev/null"], [/* 70 vars */]) = 0
execve("/usr/lib/R/bin/R", ["/usr/lib/R/bin/R", "--slave", "--no-restore", "--vanilla", "--file=/dev/null"], [/* 71 vars */]) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5822, si_status=0, si_utime=0, si_stime=0} ---
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5823, 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"], [/* 80 vars */]) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5827, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

real    0m0.063s
user    0m0.020s
sys     0m0.028s

Мы также использовали time измерить время запуска. Обратите внимание, что

  1. Rscript примерно в 5,5 раз быстрее, чем R, Одна из причин в том, что R загрузит 6 пакетов по умолчанию при запуске, в то время как Rscript загружает только один base упаковка по контролю: --default-packages=base, Но это все еще намного быстрее, даже без этой настройки.
  2. В конце оба процесса запуска направлены на $(R RHOME)/bin/exec/R и в своем оригинальном посте я уже эксплуатировал readelf -d чтобы показать, что этот исполняемый файл будет загружен libR.so, которые связаны с libblas.so.3, Согласно объяснениям @Employed Russian, библиотека BLAS, загруженная первой, победит, поэтому мой оригинальный метод не будет работать.
  3. Чтобы успешно запустить strace мы использовали удивительный файл /dev/null как входной файл и выходной файл при необходимости. Например, Rscript требует входной файл, в то время как R требует обоих. Мы подаем нулевое устройство обоим, чтобы команда работала гладко и вывод был чистым. Нулевое устройство является физически существующим файлом, но работает потрясающе. При чтении из него ничего не содержится; во время записи он отбрасывает все.

2. Чит R

Сейчас с libblas.so будет загружен в любом случае, единственное, что мы можем сделать, - это предоставить собственную версию этой библиотеки. Как я уже говорил в оригинальном сообщении, если у нас есть root-доступ, это действительно легко, используя update-alternatives --config libblas.so.3, так что система Linux поможет нам завершить этот переход. Но @Employed Russian предлагает отличный способ обмануть систему без рут-доступа: давайте проверим, как R находит библиотеку BLAS при запуске, и убедимся, что мы передаем нашу версию до того, как будет найдена система по умолчанию! Чтобы отслеживать, как совместно используемые библиотеки находятся и загружаются, используйте переменную среды LD_DEBUG,

Существует ряд переменных среды Linux с префиксом LD_как указано в man ld.so, Эти переменные могут быть назначены перед исполняемым файлом, чтобы мы могли изменить функцию запуска программы. Некоторые полезные переменные включают в себя:

  • LD_LIBRARY_PATH для настройки пути поиска библиотеки времени выполнения;
  • LD_DEBUG для отслеживания поиска и загрузки общих библиотек;
  • LD_TRACE_LOADED_OBJECTS для отображения всей загруженной библиотеки программой (ведет себя подобно ldd);
  • LD_PRELOAD для принудительного внедрения библиотеки в программу с самого начала, до того, как будут найдены все остальные библиотеки;
  • LD_PROFILE а также LD_PROFILE_OUTPUT для профилирования одной указанной общей библиотеки. Пользователь R, который прочитал раздел 3.4.1.1 sprof of Написание расширений R, должен помнить, что он используется для профилирования скомпилированного кода из R.

Использование LD_DEBUG можно увидеть по:

~/Desktop/dgemm$ LD_DEBUG=help cat
Valid options for the LD_DEBUG environment variable are:

  libs        display library search paths
  reloc       display relocation processing
  files       display progress for input file
  symbols     display symbol table processing
  bindings    display information about symbol binding
  versions    display version dependencies
  scopes      display scope information
  all         all previous options combined
  statistics  display relocation statistics
  unused      determined unused DSOs
  help        display this help message and exit

  To direct the debugging output into a file instead of standard output a filename can be specified using the LD_DEBUG_OUTPUT environment variable.

Здесь мы особенно заинтересованы в использовании LD_DEBUG=libs, Например,

~/Desktop/dgemm$ LD_DEBUG=libs Rscript --default-packages=base --vanilla /dev/null |& grep blas
  5974: find library=libblas.so.3 [0]; searching
  5974:   trying file=/usr/lib/R/lib/libblas.so.3
  5974:   trying file=/usr/lib/i386-linux-gnu/i686/sse2/libblas.so.3
  5974:   trying file=/usr/lib/i386-linux-gnu/i686/cmov/libblas.so.3
  5974:   trying file=/usr/lib/i386-linux-gnu/i686/libblas.so.3
  5974:   trying file=/usr/lib/i386-linux-gnu/sse2/libblas.so.3
  5974:   trying file=/usr/lib/i386-linux-gnu/libblas.so.3
  5974:   trying file=/usr/lib/jvm/java-7-openjdk-i386/jre/lib/i386/client/libblas.so.3
  5974:   trying file=/usr/lib/libblas.so.3
  5974: calling init: /usr/lib/libblas.so.3
  5974: calling fini: /usr/lib/libblas.so.3 [0]

показывает различные попытки, которые программа R пыталась найти и загрузить libblas.so.3, Так что, если бы мы могли предоставить нашу собственную версию libblas.so.3 и убедитесь, что R сначала его найдет, а затем проблема решена.

Давайте сначала сделаем символическую ссылку libblas.so.3 в нашем рабочем пути к библиотеке OpenBLAS libopenblas.so, затем разверните по умолчанию LD_LIBRARY_PATH с нашим рабочим путем (и экспортировать его):

~/Desktop/dgemm$ ln -sf libopenblas.so libblas.so.3
~/Desktop/dgemm$ export LD_LIBRARY_PATH = $(pwd):$LD_LIBRARY_PATH  ## put our working path at top

Теперь давайте снова проверим процесс загрузки библиотеки:

~/Desktop/dgemm$ LD_DEBUG=libs Rscript --default-packages=base --vanilla /dev/null |& grep blas
  6063: find library=libblas.so.3 [0]; searching
  6063:   trying file=/usr/lib/R/lib/libblas.so.3
  6063:   trying file=/usr/lib/i386-linux-gnu/i686/sse2/libblas.so.3
  6063:   trying file=/usr/lib/i386-linux-gnu/i686/cmov/libblas.so.3
  6063:   trying file=/usr/lib/i386-linux-gnu/i686/libblas.so.3
  6063:   trying file=/usr/lib/i386-linux-gnu/sse2/libblas.so.3
  6063:   trying file=/usr/lib/i386-linux-gnu/libblas.so.3
  6063:   trying file=/usr/lib/jvm/java-7-openjdk-i386/jre/lib/i386/client/libblas.so.3
  6063:   trying file=/home/zheyuan/Desktop/dgemm/libblas.so.3
  6063: calling init: /home/zheyuan/Desktop/dgemm/libblas.so.3
  6063: calling fini: /home/zheyuan/Desktop/dgemm/libblas.so.3 [0]

Большой! Мы успешно обманули Р.

3. Эксперимент с OpenBLAS

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

Теперь все работает как положено!

4. Unset LD_LIBRARY_PATH (быть в безопасности)

Это хорошая практика, чтобы сбросить LD_LIBRARY_PATH после использования.

~/Desktop/dgemm$ unset LD_LIBRARY_PATH
Другие вопросы по тегам