iks*_*nov 3 c++ optimization virtual
我正在尝试对函数指针调用和虚函数调用之间的差异进行基准测试.为此,我编写了两段代码,对数组进行相同的数学计算.一个变体使用指向函数的指针数组并在循环中调用它们.另一个变体使用指向基类的指针数组并调用其虚函数,该函数在派生类中重载,与第一个变体中的函数完全相同.然后我打印经过的时间并使用简单的shell脚本多次运行基准测试并计算平均运行时间.
这是代码:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
long long timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}
void function_not( double *d ) {
*d = sin(*d);
}
void function_and( double *d ) {
*d = cos(*d);
}
void function_or( double *d ) {
*d = tan(*d);
}
void function_xor( double *d ) {
*d = sqrt(*d);
}
void ( * const function_table[4] )( double* ) = { &function_not, &function_and, &function_or, &function_xor };
int main(void)
{
srand(time(0));
void ( * index_array[100000] )( double * );
double array[100000];
for ( long int i = 0; i < 100000; ++i ) {
index_array[i] = function_table[ rand() % 4 ];
array[i] = ( double )( rand() / 1000 );
}
struct timespec start, end;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
for ( long int i = 0; i < 100000; ++i ) {
index_array[i]( &array[i] );
}
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
unsigned long long time_elapsed = timespecDiff(&end, &start);
cout << time_elapsed / 1000000000.0 << endl;
}
Run Code Online (Sandbox Code Playgroud)
这是虚函数变量:
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
using namespace std;
long long timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)
{
return ((timeA_p->tv_sec * 1000000000) + timeA_p->tv_nsec) -
((timeB_p->tv_sec * 1000000000) + timeB_p->tv_nsec);
}
class A {
public:
virtual void calculate( double *i ) = 0;
};
class A1 : public A {
public:
void calculate( double *i ) {
*i = sin(*i);
}
};
class A2 : public A {
public:
void calculate( double *i ) {
*i = cos(*i);
}
};
class A3 : public A {
public:
void calculate( double *i ) {
*i = tan(*i);
}
};
class A4 : public A {
public:
void calculate( double *i ) {
*i = sqrt(*i);
}
};
int main(void)
{
srand(time(0));
A *base[100000];
double array[100000];
for ( long int i = 0; i < 100000; ++i ) {
array[i] = ( double )( rand() / 1000 );
switch ( rand() % 4 ) {
case 0:
base[i] = new A1();
break;
case 1:
base[i] = new A2();
break;
case 2:
base[i] = new A3();
break;
case 3:
base[i] = new A4();
break;
}
}
struct timespec start, end;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);
for ( int i = 0; i < 100000; ++i ) {
base[i]->calculate( &array[i] );
}
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
unsigned long long time_elapsed = timespecDiff(&end, &start);
cout << time_elapsed / 1000000000.0 << endl;
}
Run Code Online (Sandbox Code Playgroud)
我的系统是LInux,Fedora 13,gcc 4.4.2.代码用g ++ -O3编译.第一个是test1,第二个是test2.
现在我在控制台中看到了这个:
[Ignat@localhost circuit_testing]$ ./test2 && ./test2
0.0153142
0.0153166
Run Code Online (Sandbox Code Playgroud)
好吧,或多或少,我想.然后,这个:
[Ignat@localhost circuit_testing]$ ./test2 && ./test2
0.01531
0.0152476
Run Code Online (Sandbox Code Playgroud)
应该可见的25%在哪里?第一个可执行文件如何比第二个可执行文件慢?
我问这个是因为我正在做一个项目,它涉及调用像这样的行中的许多小函数来计算数组的值,而我继承的代码执行非常复杂的操作以避免虚函数调用开销.现在这个着名的呼叫在哪里开销?
小智 8
在这两种情况下,您都是间接调用函数.在一种情况下通过你的函数指针表,在另一种情况下通过编译器的函数指针数组(vtable).毫不奇怪,两个类似的操作可以为您提供类似的计时结果.