I\'m working on a tiny R package that uses CUDA and Rcpp, adapted from the output of Rcpp.package.skeleton()
. I will first describe what happens on the master b
Several packages on CRAN use GPUs via CUDA:
I would start with these.
Going through your package there are multiple aspects that need to be changed.
extern "C"
. You will prefix both the function in the .cu
file and when you declare it at the start of your cpp
file.The following Makevars
worked for me whereby I modified my CUDA_HOME, R_HOME, and RCPP_INC (switched back for you). Note, this is where a configure
file is recommended to make the package as portable as possible.
CUDA_HOME = /usr/local/cuda
R_HOME = /apps/R-3.2.0
CXX = /usr/bin/g++
# This defines what the shared object libraries will be
PKG_LIBS= -L/usr/local/cuda-7.0/lib64 -Wl,-rpath,/usr/local/cuda-7.0/lib64 -lcudart -d
#########################################
R_INC = /usr/share/R/include
RCPP_INC = $(R_HOME)/library/Rcpp/include
NVCC = $(CUDA_HOME)/bin/nvcc
CUDA_INC = $(CUDA_HOME)/include
CUDA_LIB = $(CUDA_HOME)/lib64
LIBS = -lcudart -d
NVCC_FLAGS = -Xcompiler "-fPIC" -gencode arch=compute_20,code=sm_20 -gencode arch=compute_30,code=sm_30 -gencode arch=compute_35,code=sm_35 -I$(R_INC)
### Define objects
cu_sources := $(wildcard *cu)
cu_sharedlibs := $(patsubst %.cu, %.o,$(cu_sources))
cpp_sources := $(wildcard *.cpp)
cpp_sharedlibs := $(patsubst %.cpp, %.o, $(cpp_sources))
OBJECTS = $(cu_sharedlibs) $(cpp_sharedlibs)
all : rcppcuda.so
rcppcuda.so: $(OBJECTS)
%.o: %.cpp $(cpp_sources)
$(CXX) $< -c -fPIC -I$(R_INC) -I$(RCPP_INC)
%.o: %.cu $(cu_sources)
$(NVCC) $(NVCC_FLAGS) -I$(CUDA_INC) $< -c
A follow-up point (as you say this is a learning exercise):
A. You aren't using one of the parts of Rcpp that make it such a wonderful package, namely 'attributes'. Here is how your cpp
file should look:
#include <Rcpp.h>
using namespace Rcpp;
extern "C"
void someCUDAcode();
//[[Rcpp::export]]
SEXP someCPPcode(SEXP r) {
S4 c(r);
double *x = REAL(c.slot("x"));
int *y = INTEGER(c.slot("y"));
x[0] = 500.0;
y[1] = 1000;
someCUDAcode();
return R_NilValue;
}
This will automatically generate the corresponding RcppExports.cpp
and RcppExports.R
files and you no longer need a .Call
function yourself. You just call the function. Now .Call('someCPPcode', r)
becomes someCPPcode(r)
:)
For completeness, here is the updated someCUDAcode.cu
file:
__global__ void mykernel(int a){
int id = threadIdx.x;
int b = a;
b++;
id++;
}
extern "C"
void someCUDAcode() {
mykernel<<<1, 1>>>(1);
}
With respect to a configure file (using autoconf), you are welcome to check out my gpuRcuda package using Rcpp, CUDA, and ViennaCL (a C++ GPU computing library).