Rcpp и CULA: ошибка сегментации
Я извлек соответствующие биты из R-пакета gputools для запуска QR-декомпозиции на моем GPU с использованием Rcpp путем динамической загрузки разделяемой библиотеки, которая ссылается на culatools. Все отлично работает в терминале и R.app на моем Mac. Результаты согласуются с функцией R ' qr(), но проблема в том, что при выходе из R.app возникает ошибка сегментации (ошибка не возникает при использовании терминала):
*** caught segfault ***
address 0x10911b050, cause 'memory not mapped'
Я думаю, что я сузил проблему до указателей 'a' и 'tau' в файле.c, который ссылается на culatools:
#include<cula.h>
void gpuQR(const int *m, const int *n, float *a, const int *lda, float *tau)
{
culaInitialize();
culaSgeqrf(m[0], n[0], a, lda[0], tau);
culaShutdown();
}
Я скомпилировал файл.c на моем Mac, используя:
/usr/local/cuda/bin/nvcc -gencode arch=compute_10,code=sm_10 -gencode arch=compute_11,code=sm_11 -gencode arch=compute_12,code=sm_12 -gencode arch=compute_13,code=sm_13 -gencode arch=compute_20,code=sm_20 -c -I. -I/usr/local/cula/include -m64 -Xcompiler -fPIC gpuQR.c -o gpuQR.o
/usr/local/cuda/bin/nvcc -gencode arch=compute_10,code=sm_10 -gencode arch=compute_11,code=sm_11 -gencode arch=compute_12,code=sm_12 -gencode arch=compute_13,code=sm_13 -gencode arch=compute_20,code=sm_20 -shared -m64 -Xlinker -rpath,/usr/local/cula/lib64 -L/usr/local/cula/lib64 -lcula_core -lcula_lapack -lcublas -o gpuQR.so gpuQR.o
Я написал.cpp файл, который использует Rcpp и динамически загружает общую библиотеку gpuQR.so:
#include <Rcpp.h>
#include <dlfcn.h>
using namespace Rcpp;
using namespace std;
typedef void (*func)(int*, int*, float*, int*, float*);
RcppExport SEXP gpuQR_Rcpp(SEXP x_, SEXP n_rows_, SEXP n_cols_)
{
vector<float> x = as<vector<float> >(x_);
int n_rows = as<int>(n_rows_);
int n_cols = as<int>(n_cols_);
vector<float> scale(n_cols);
void* lib_handle = dlopen("path/gpuQR.so", RTLD_LAZY);
if (!lib_handle)
{
Rcout << dlerror() << endl;
} else {
func gpuQR = (func) dlsym(lib_handle, "gpuQR");
gpuQR(&n_rows, &n_cols, &(x[0]), &n_rows, &(scale[0]));
}
dlclose(lib_handle);
for(int ii = 1; ii < n_rows; ii++)
{
for(int jj = 0; jj < n_cols; jj++)
{
if(ii > jj) { y[ii + jj * n_rows] *= scale[jj]; }
}
}
return wrap(x);
}
Я скомпилировал файл.cpp в R, используя:
library(Rcpp)
PKG_LIBS <- sprintf('%s $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)', Rcpp:::RcppLdFlags())
PKG_CPPFLAGS <- sprintf('%s', Rcpp:::RcppCxxFlags())
Sys.setenv(PKG_LIBS = PKG_LIBS , PKG_CPPFLAGS = PKG_CPPFLAGS)
R <- file.path(R.home(component = 'bin'), 'R')
file <- 'path/gpuQR_Rcpp.cpp'
cmd <- sprintf('%s CMD SHLIB %s', R, paste(file, collapse = ' '))
system(cmd)
и запустил пример:
dyn.load('path/gpuQR_Rcpp.so')
set.seed(100)
A <- matrix(rnorm(9), 3, 3)
n_row <- nrow(A)
n_col <- ncol(A)
res <- .Call('gpuQR_Rcpp', c(A), n_row, n_col)
matrix(res, n_row, n_col)
[,1] [,2] [,3]
[1,] 0.5250958 -0.8666927 0.8594266
[2,] -0.2504899 -0.3878644 -0.1277837
[3,] 0.1502908 0.4742033 -0.8804248
qr(A)$qr
[,1] [,2] [,3]
[1,] 0.5250957 -0.8666925 0.8594266
[2,] -0.2504899 -0.3878643 -0.1277838
[3,] 0.1502909 0.4742033 -0.8804247
У кого-нибудь есть идеи, как исправить ошибку сегментации?
2 ответа
Проблема решается удалением
dlclose(lib_handle);
из.cpp файла. Это дает следующее:
#include <Rcpp.h>
#include <dlfcn.h>
using namespace Rcpp;
using namespace std;
typedef void (*func)(int*, int*, float*, int*, float*);
RcppExport SEXP gpuQR_Rcpp(SEXP x_, SEXP n_rows_, SEXP n_cols_)
{
vector<float> x = as<vector<float> >(x_);
int n_rows = as<int>(n_rows_);
int n_cols = as<int>(n_cols_);
vector<float> scale(n_cols);
void* lib_handle = dlopen("path/gpuQR.so", RTLD_LAZY);
if (!lib_handle)
{
Rcout << dlerror() << endl;
} else {
func gpuQR = (func) dlsym(lib_handle, "gpuQR");
gpuQR(&n_rows, &n_cols, &(x[0]), &n_rows, &(scale[0]));
}
for(int ii = 1; ii < n_rows; ii++)
{
for(int jj = 0; jj < n_cols; jj++)
{
if(ii > jj) { x[ii + jj * n_rows] *= scale[jj]; }
}
}
return wrap(x);
}
Файл.cpp может быть скомпилирован в R с использованием:
library(Rcpp)
PKG_LIBS <- sprintf('%s $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)', Rcpp:::RcppLdFlags())
PKG_CPPFLAGS <- sprintf('%s', Rcpp:::RcppCxxFlags())
Sys.setenv(PKG_LIBS = PKG_LIBS , PKG_CPPFLAGS = PKG_CPPFLAGS)
R <- file.path(R.home(component = 'bin'), 'R')
file <- 'path/gpuQR_Rcpp.cpp'
cmd <- sprintf('%s CMD SHLIB %s', R, paste(file, collapse = ' '))
system(cmd)
Фактический файл.c, ссылающийся на culatools:
#include<cula.h>
void gpuQR(const int *m, const int *n, float *a, const int *lda, float *tau)
{
culaInitialize();
culaSgeqrf(m[0], n[0], a, lda[0], tau);
culaShutdown();
}
Его можно скомпилировать с помощью:
gcc -c -I/usr/local/cula/include gpuQR.c
gcc -shared -Wl,-rpath,/usr/local/cula/lib64 -L/usr/local/cula/lib64 -lcula_lapack -o gpuQR.so gpuQR.o
QR-разложение может затем быть выполнено в R с использованием:
dyn.load('path/gpuQR_Rcpp.so')
set.seed(100)
n_row <- 3
n_col <- 3
A <- matrix(rnorm(n_row * n_col), n_row, n_col)
res <- .Call('gpuQR_Rcpp', c(A), n_row, n_col)
matrix(res, n_row, n_col)
[,1] [,2] [,3]
[1,] 0.5250958 -0.8666927 0.8594266
[2,] -0.2504899 -0.3878644 -0.1277837
[3,] 0.1502908 0.4742033 -0.8804248
qr(A)$qr
[,1] [,2] [,3]
[1,] 0.5250957 -0.8666925 0.8594266
[2,] -0.2504899 -0.3878643 -0.1277838
[3,] 0.1502909 0.4742033 -0.8804247
Вот результаты теста с использованием графического процессора NVIDIA GeForce 9400M с 16 ядрами CUDA:
n_row <- 1000; n_col <- 1000
A <- matrix(rnorm(n_row * n_col), n_row, n_col)
B <- A; dim(B) <- NULL
res <- benchmark(.Call('gpuQR_Rcpp', B, n_row, n_col), qr(A), columns = c('test', 'replications', 'elapsed', 'relative'), order = 'relative')
test replications elapsed relative
1 .Call("gpuQR_Rcpp", B, n_row, n_col) 100 38.037 1.000
2 qr(A) 100 152.575 4.011
На самом деле нет необходимости динамически загружать разделяемую библиотеку, связывающуюся с culatools. Сначала я думал об этом, но я не получил файл.cpp, используя Rcpp, скомпилированный. В любом случае, новый файл.cpp:
#include<Rcpp.h>
#include<cula.h>
using namespace Rcpp;
using namespace std;
RcppExport SEXP gpuQR_Rcpp(SEXP x_, SEXP n_rows_, SEXP n_cols_)
{
vector<float> x = as<vector<float> >(x_);
int n_rows = as<int>(n_rows_);
int n_cols = as<int>(n_cols_);
vector<float> scale(n_cols);
culaInitialize();
culaSgeqrf(n_rows, n_cols, &(x[0]), n_rows, &(scale[0]));
culaShutdown();
for(int ii = 1; ii < n_rows; ii++)
{
for(int jj = 0; jj < n_cols; jj++)
{
if(ii > jj) { x[ii + jj * n_rows] *= scale[jj]; }
}
}
return wrap(x);
}
Файл.cpp компилируется с использованием:
library(Rcpp)
PKG_LIBS <- sprintf('-Wl,-rpath,/usr/local/cula/lib64 -L/usr/local/cula/lib64 -lcula_lapack %s $(LAPACK_LIBS) $(BLAS_LIBS) $(FLIBS)', Rcpp:::RcppLdFlags())
PKG_CPPFLAGS <- sprintf('-I/usr/local/cula/include %s', Rcpp:::RcppCxxFlags())
Sys.setenv(PKG_LIBS = PKG_LIBS , PKG_CPPFLAGS = PKG_CPPFLAGS)
R <- file.path(R.home(component = 'bin'), 'R')
file <- 'path/gpuQR_inc.cpp'
cmd <- sprintf('%s CMD SHLIB %s', R, paste(file, collapse = ' '))
system(cmd)
где я установил соответствующий путь к culatools. Все это не работает быстрее, но больше не нужно компилировать разделяемую библиотеку, связывающуюся с culatools и динамически загружать ее.
Я думаю, что это хорошая альтернатива R-пакету gputools для расширения R с помощью C++ и выполнения операций линейной алгебры на GPU.