Hi, I'm looking for a most efficient way to call an R function from C++ in a package. I know there are two functions (`R_forceAndCall` and `Rf_eval`) that can do the "call" part, but both are slow compared to calling the same function in R. I also try to use Rcpp and it is the worse one. Here is my test code: C++ code: ``` // [[Rcpp::export]] SEXP C_test1(SEXP f, SEXP x) { SEXP call =PROTECT(Rf_lang2(f, x)); SEXP val = R_forceAndCall(call, 1, R_GlobalEnv); UNPROTECT(1); return val; } // [[Rcpp::export]] SEXP C_test2(SEXP expr, SEXP env) { SEXP val = Rf_eval(expr, env); return val; } // [[Rcpp::export]] SEXP C_test3(SEXP f,SEXP x) { Function fun(f); return fun(x); } ``` R code: ``` testFunc<-function(x){ x=x^2 return(x) } evn=new.env() evn$x=x expr=quote(testFunc(evn$x)) testFunc(evn$x) C_test1(testFunc, evn$x) C_test2(expr,evn) C_test3(testFunc,evn$x) ``` For the results, I run each function 1,000,000 times: - testFunc : 0.47 sec - C_test1 : 2.46 sec - C_test2 : 2.74 sec - C_test3 : 18.86 sec It is clear to see that calling an R function in R is the fast one, it is about 5X faster than ` R_forceAndCall ` and ` Rf_eval`. the latter two functions have a similar performance and using Rcpp is the worst one. Is it expected? Why is calling an R function from C++ much slower than calling the function from R? Is there any faster way to do the function call in C++? Best, Jiefei [[alternative HTML version deleted]]
Hi Jiefei, Calling into R from C++ code is more complicated than one might think. Please see Tomas Kalibera's post here: https://developer.r-project.org/Blog/public/2019/03/28/use-of-c---in-packages/index.html The Rcpp Function class is more expensive than a regular Rf_eval() because it tries to prevent errors (longjmps) from jumping to the top level, so that the C++ stack can be properly unwound. In addition, your example also pays a cost for the indirect function calls used with Rcpp attributes, since the generated R wrapper functions will then use `.Call()` under the hood. You could also try to directly use .Call() to avoid that extra R function call overhead. Even then, R's dispatch system for primitive functions (like `^`) is likely still going to be faster than what you get from the .Call() interface, especially since some extra validation does occur when using .Call(). In practice, that difference is usually negligible outside of synthetic benchmarks. Best, Kevin On Tue, Jun 18, 2019 at 10:41 AM King Jiefei <szwjf08 at gmail.com> wrote:> > Hi, > > I'm looking for a most efficient way to call an R function from C++ in a > package. I know there are two functions (`R_forceAndCall` and `Rf_eval`) > that can do the "call" part, but both are slow compared to calling the same > function in R. I also try to use Rcpp and it is the worse one. Here is my > test code: > > C++ code: > ``` > // [[Rcpp::export]] > SEXP C_test1(SEXP f, SEXP x) { > SEXP call =PROTECT(Rf_lang2(f, x)); > SEXP val = R_forceAndCall(call, 1, R_GlobalEnv); > UNPROTECT(1); > return val; > } > > // [[Rcpp::export]] > SEXP C_test2(SEXP expr, SEXP env) { > SEXP val = Rf_eval(expr, env); > return val; > } > > // [[Rcpp::export]] > SEXP C_test3(SEXP f,SEXP x) { > Function fun(f); > return fun(x); > } > ``` > > R code: > ``` > testFunc<-function(x){ > x=x^2 > return(x) > } > evn=new.env() > evn$x=x > expr=quote(testFunc(evn$x)) > > testFunc(evn$x) > C_test1(testFunc, evn$x) > C_test2(expr,evn) > C_test3(testFunc,evn$x) > ``` > > For the results, I run each function 1,000,000 times: > > - testFunc : 0.47 sec > - C_test1 : 2.46 sec > - C_test2 : 2.74 sec > - C_test3 : 18.86 sec > > It is clear to see that calling an R function in R is the fast one, it is > about 5X faster than ` R_forceAndCall ` and ` Rf_eval`. the latter two > functions have a similar performance and using Rcpp is the worst one. Is it > expected? Why is calling an R function from C++ much slower than calling > the function from R? Is there any faster way to do the function call in C++? > > Best, > Jiefei > > [[alternative HTML version deleted]] > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
On Tue, 18 Jun 2019 at 19:41, King Jiefei <szwjf08 at gmail.com> wrote:> > [...] > > It is clear to see that calling an R function in R is the fast one, it is > about 5X faster than ` R_forceAndCall ` and ` Rf_eval`. the latter two > functions have a similar performance and using Rcpp is the worst one. Is it > expected? Why is calling an R function from C++ much slower than calling > the function from R? Is there any faster way to do the function call in C++?Yes, there is: enable fast evaluation by setting -DRCPP_USE_UNWIND_PROTECT, or alternatively, use // [[Rcpp::plugins(unwindProtect)]] I?aki
For reference, your benchmark using UNWIND_PROTECT:> system.time(test(testFunc, evn$x))user system elapsed 0.331 0.000 0.331> system.time(test(C_test1, testFunc, evn$x))user system elapsed 2.029 0.000 2.036> system.time(test(C_test2, expr, evn))user system elapsed 2.307 0.000 2.313> system.time(test(C_test3, testFunc, evn$x))user system elapsed 2.131 0.000 2.138 I?aki On Tue, 18 Jun 2019 at 20:35, I?aki Ucar <iucar at fedoraproject.org> wrote:> > On Tue, 18 Jun 2019 at 19:41, King Jiefei <szwjf08 at gmail.com> wrote: > > > > [...] > > > > It is clear to see that calling an R function in R is the fast one, it is > > about 5X faster than ` R_forceAndCall ` and ` Rf_eval`. the latter two > > functions have a similar performance and using Rcpp is the worst one. Is it > > expected? Why is calling an R function from C++ much slower than calling > > the function from R? Is there any faster way to do the function call in C++? > > Yes, there is: enable fast evaluation by setting > -DRCPP_USE_UNWIND_PROTECT, or alternatively, use > > // [[Rcpp::plugins(unwindProtect)]] > > I?aki-- I?aki ?car