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] Cost of function pointer dereferencing
5 messages · Romain Francois, Davor Cubranic
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
Le 23 d?c. 2010 ? 06:54 PM, Davor Cubranic <cubranic at stat.ubc.ca> a ?crit :
I tried using a functor, calling 'exp' in its operator(), and it was even faster than static (albeit very slightly):
Intriguing.
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.
My plan is to go through macros
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
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
On 2010-12-23, at 10:03 AM, romain at r-enthusiasts.com wrote:
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.
My plan is to go through macros
I guess it is simpler, but oh so old-fashioned. :-) Davor