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

George Vega Yon g.vegayon at gmail.com
Wed Aug 3 20:38:49 CEST 2016


Thanks for the quick reply! What kind of errors are we talking about? I a
new run I explicitly caused an error by passing a character vector, and had
no memory leak (using Valgrind):

cppFuncall(letters, fun)
Error in cos(x[1]) : non-numeric argument to mathematical function

If its not too much to ask, could you give an explicit example in which
that happens (memory leak)? Just trying to learn here!

Thanks,


George G. Vega Yon
+1 (626) 381 8171
http://www.its.caltech.edu/~gvegayon/

On Wed, Aug 3, 2016 at 11:29 AM, Kevin Ushey <kevinushey at gmail.com> wrote:

> 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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20160803/45c11724/attachment-0001.html>


More information about the Rcpp-devel mailing list