[Rcpp-devel] Cost of function pointer dereferencing
Davor Cubranic
cubranic at stat.ubc.ca
Thu Dec 23 22:51:40 CET 2010
After a bit of googling, I figured out how to write the templated functor. It's very simple:
incw <- '
template<double Func(double) >
struct Ftor {
inline double operator () (double x) const {
return Func(x);
}
};
Ftor<exp> ftor;
'
fw <- cxxfunction( , '
double x ;
for( int j=0; j<1000; j++){
for( int i=0; i<1000000; i++){
x = ftor(2.0) ;
}
}
return wrap( x ) ;
', plugin = "Rcpp", includes = incw , verbose=TRUE)
And it's still (insignificantly) faster than the static call:
test replications elapsed relative user.self sys.self user.child
3 functor 1 0.463 1.000000 0.464 0.001 0
1 static 1 0.468 1.010799 0.464 0.000 0
2 pointer 1 15.960 34.470842 15.824 0.017 0
Davor
On 2010-12-23, at 9:54 AM, Davor Cubranic wrote:
> I tried using a functor, calling 'exp' in its operator(), and it was even faster than static (albeit very slightly):
>
> test replications elapsed relative user.self sys.self user.child
> 3 functor 1 0.465 1.000000 0.464 0.000 0
> 1 static 1 0.472 1.015054 0.464 0.001 0
> 2 pointer 1 15.855 34.096774 15.815 0.007 0
>
> Just add 'fw' below to your benchmark:
>
> incw <- '
> class Ftor {
> public:
> inline double operator () (double x) const {
> return exp(x);
> }
> };
> const Ftor ftor = Ftor();
> '
> fw <- cxxfunction( , '
> double x ;
> for( int j=0; j<1000; j++){
> for( int i=0; i<1000000; i++){
> x = ftor(2.0) ;
> }
> }
> return wrap( x ) ;
> ', plugin = "Rcpp", includes = incw , verbose=TRUE)
>
> Maybe you could create a functor for each basic function and use that in a common loop implementation.
>
> I also tried templatizing Ftor on the function it delegates to, so that you could do something like Ftor<exp>(), but I couldn't get it to compile. Your template-fu is far better than mine, so maybe you'll be able to wrangle it into shape and have even more succint code.
>
> Davor
>
>
> On 2010-12-23, at 8:45 AM, <romain at r-enthusiasts.com> <romain at r-enthusiasts.com> wrote:
>
>> Hello,
>>
>> Since I've been playing with efficiency of various operators for numeric vectors (+,-,/,*), I'm now looking at other functions such as exp, sqrt, etc ...
>>
>> The way we currently implement exp for vectors requires that we keep a function pointer for the atomic exp and that we dereference the function pointer each time. It turns out that this has some cost :
>>
>> test replications elapsed relative user.self sys.self user.child sys.child
>> 1 static 1 0.691 1.00000 0.691 0.000 0 0
>> 2 pointer 1 11.157 16.14616 11.144 0.012 0 0
>>
>> Reproduced by this code:
>>
>> require( Rcpp )
>> require( inline )
>>
>> fx <- cxxfunction( , '
>> double x ;
>> for( int j=0; j<1000; j++){
>> for( int i=0; i<1000000; i++){
>> x = exp(2.0) ;
>> }
>> }
>> return wrap( x ) ;
>> ', plugin = "Rcpp" )
>>
>> inc <- '
>> double (*fun)(double) = exp ;
>> '
>> fy <- cxxfunction( , '
>> double x ;
>> for( int j=0; j<1000; j++){
>> for( int i=0; i<1000000; i++){
>> x = (*fun)(2.0) ;
>> }
>> }
>> return wrap( x ) ;
>> ', plugin = "Rcpp", includes = inc )
>>
>>
>> require( rbenchmark )
>> benchmark(
>> order = "relative",
>> static = fx(),
>> pointer = fy(),
>> replications = 1L
>> )
>>
>> Romain
>>
>>
>>
>>
>> _______________________________________________
>> 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
>
> _______________________________________________
> 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