[Rcpp-devel] Alternative way of calling R functions within C++

Kevin Ushey kevinushey at gmail.com
Wed Aug 3 20:29:37 CEST 2016


Also note that you definitely don't want to call `Rf_error` from a C++
context in general, as it will bypass any active C++ try-catch blocks,
bypass destructors, and so on. You should call `Rcpp::stop` explicitly
and use Rcpp attributes to ensure the try-catch block is automagically
set up for you.

On Wed, Aug 3, 2016 at 11:28 AM, Kevin Ushey <kevinushey at gmail.com> wrote:
> The problem with your implementation is what happens if R throws an
> error. The R longjmp will cause any C++ objects on the stack to leak,
> their destructors not to run, and you'll essentially be in a bad place
> if you evaluate any R code that might return an error. (For example,
> suppose you had a file handle open, and then evaluated your R function
> using 'eval', but an R error was produced. That file handle would
> 'leak' and you wouldn't be able to recover it)
>
> You can instead use the `Rf_tryEval` or `Rf_tryEvalSilent` routines,
> but those don't respect active handlers (e.g. warning, message
> handlers) and so aren't sufficient for general use.
>
> Rcpp basically handles this by enclosing any expression to be
> evaluated in an R 'tryCatch' call, with error + interrupt handlers
> attached. This is, of course, slower since a lot more R code is being
> evaluated, but right now it's the only way to safely execute an R
> function in a C++ context while respecting all other active handlers.
>
> In short, the Rcpp::Function implementation is designed to be as safe
> + correct as possible, with the downside being that it's slower.
> However, we generally advise that you shouldn't call back to R too
> frequently from a C++ context, so that overhead should in most cases
> be not too bad.
>
> Best,
> Kevin
>
> On Wed, Aug 3, 2016 at 10:50 AM, George Vega Yon <g.vegayon at gmail.com> wrote:
>> Hey there,
>>
>> Looking at some old R code that I have I found this C++ function that allows
>> evaluating R-written functions within C++ using Rcpp. While this is no news,
>> the neat thing of it is that it seems to be faster than Rcpp::Function.
>> Using microbenchmark I compared using Rcpp::function vs my implementation vs
>> calling the function from R itself and this is what I got
>>
>> Unit: relative
>>                 expr min  lq     mean median  uq max neval
>>   cppFuncall(x, fun) 1.3 1.3 1.39    1.3 1.4  83 10000
>>  RcppFuncall(x, fun) 7.2 7.1 7.13    6.9 6.8  89 10000
>>               fun(x) 1.0 1.0 1.00    1.0 1.0   1 10000
>>
>> So, on average, while Rcpp::Function took ~7 times the R call took, my
>> implementation took ~1.3 times. To be sure I was not breaking anything I ran
>> the example using valgrind and there is no memory leak. The source code for
>> the test follows:
>>
>> -------- example_calling_r_functions.cpp ----
>>
>> #include <Rinternals.h>
>> #include <Rcpp.h>
>>
>> // [[Rcpp::export]]
>> SEXP cppFuncall(SEXP par, SEXP fn)
>> {
>>   SEXP R_fcall, ans;
>>
>>   if(!isFunction(fn)) error("'fn' must be a function");
>>   R_fcall = PROTECT(lang2(fn, R_NilValue));
>>
>>   SETCADR(R_fcall, par);
>>   ans=eval(R_fcall, R_GlobalEnv);
>>   UNPROTECT(1);
>>   return ans;
>> }
>>
>> using namespace Rcpp;
>>
>> // [[Rcpp::export]]
>> SEXP RcppFuncall(NumericVector par, Function fn)
>> {
>>   return fn(par);
>> }
>>
>>
>>
>> /*** R
>> # R function to be called
>> fun <- function(x) {
>>   -cos(x[1])*cos(x[2])*exp(-((x[1] - pi)^2 + (x[2] - pi)^2))
>> }
>>
>> # Input data
>> set.seed(3331)
>> x <- runif(1e3)
>>
>> # Benchmarking
>> library(microbenchmark)
>> microbenchmark(
>>   cppFuncall(x, fun), RcppFuncall(x,fun), fun(x), times=1e4,
>>   unit="relative", control = list(warmup=100)
>> )
>> */
>>
>> -------- example_calling_r_functions.cpp ----
>>
>> I've asked around about how to make things faster for function calls in Rcpp
>> but, from what I've been told it is difficult since the implementation of
>> Rcpp::Function actually has to go back to R to work (or something like that
>> :P). Now, this implementation, -cppFuncall-, has no problem when it comes to
>> passing wrong arguments, e.g. if you pass a character vector to it R will
>> complain but there won't be any system crash. One big difference is that
>> here I'm relying on passing all the function's arguments in a single object
>> while Rcpp::Function does not. Either way, if this is OK this could be a
>> nice extra feature for Rcpp, I'm thinking of optimization routines (or other
>> kinds of algorithms) that rely on calling R functions multiple times.
>>
>> The thing is that I'm still learning C++  and  I'm not Rinternals expert at
>> all! So I would love to get some feedback from you guys. Does this function,
>> -cppFuncall-, looks OK? in other words, am I doing/getting something wrong
>> here?
>>
>> Thanks,
>>
>> George G. Vega Yon
>> +1 (626) 381 8171
>> http://www.its.caltech.edu/~gvegayon/
>>
>> _______________________________________________
>> Rcpp-devel mailing list
>> Rcpp-devel at lists.r-forge.r-project.org
>> https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel


More information about the Rcpp-devel mailing list