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

Kevin Ushey kevinushey at gmail.com
Wed Aug 3 20:28:50 CEST 2016


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