Building a Tiny R Package with Cuda and Rcpp

Building a tiny R package with CUDA and Rcpp

Going through your package there are multiple aspects that need to be changed.

  1. You shouldn't use a 'Makefile' but a 'Makevars' file instead to improve compatibility for multiple architecture builds.
  2. Try to follow the standard variable names (e.g. CPPC should be CXX), this makes everything play together much better.
  3. Don't try and compile the shared object yourself, there are good macros within the base R makefile that make this much simpler (e.g. PKG_LIBS, OBJECTS, etc.)
  4. With multiple compilers, you will want to use the OBJECTS macro. Here you will override R's base attempt to set the object files to be linked (make sure you include them all).
  5. You also need (AFAIK) to make CUDA functions available with 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).

Building an R package with Rcpp which contains C source and header with restrict qualifier?

It sounds like you are making a .cpp file which does #include <x.h> where x.h is a C header which uses restrict. If that's true, I think you can modify your .cpp file to do this:

#define restrict // nothing
extern "C"
{
#include <x.h>
}

Then compilation of your C++ code will not see the restrict keyword, and also I have wrapped the header in extern "C" because if the header itself doesn't do that internally, you need to, in order that your C++ compiler will not apply C++ "name mangling" to the functions declared inside.

Calling CUDA API functions from Rcpp package causes segfault

Thank you @RalfStubner, the mistake generating the error above was indeed just the declaration of a return type that was never returned.

So instead of

// [[Rcpp::export]]
Rcpp::NumericMatrix cudaTest()
{
testMalloc();
}

it should rather be

// [[Rcpp::export]]
void cudaTest()
{
testMalloc();
}

(While this was a rather simple problem, on my original pretty large project the error was the same with a different setup. I thought the cudaMalloc was the problem because I was only able to debug my way through with printf statements, which were completely omitted when the erroneous part was introduced. In this larger project, the error was a wrapper around the launch of CUDA kernels, which was simply removed afterwards.)

Building Rcpp package with external C library on Windows

Yes, it is possible to build a static library on Windows during package installation. I am doing that in the experimental windows branch of dqmagic:

PKG_CPPFLAGS = -I./libmagic -I./libgnurx -DHAVE_CONFIG_H
PKG_LIBS = -L. -lmagic -lregex -lshlwapi

all: $(SHLIB)
$(SHLIB): libmagic.a libregex.a

LIBMAGIC =libmagic/apprentice.o \
[... many object files ...]
libmagic.a: $(LIBMAGIC)

LIBREGEX = libgnurx/regex.o
libregex.a: $(LIBREGEX)

Note that I do not tell makehow to build a static library, leaving that to the automatic rules. That way there are no issues with ar missing. Note that the Linux/Mac OSX build uses a system installed library.

I think RcppGSL is not a good comparison in your case, since it uses an external library on all platforms. Reason is that with this package it has to be possible to compile and link with GSL after package installation. In your case, all the compilation and linking is done at installation time, right?



Related Topics



Leave a reply



Submit