这是不是一个真正的答案,你的实际问题,但我很好奇“真正是调用虚函数调用VS常规类函数的开销”。为了使其“公平”,我创建了一个classes.cpp,它实现了一个非常简单的函数,但它是一个单独的文件,它在“main”之外编译。
classes.h:
#ifndef CLASSES_H
#define CLASSES_H
class base
{
virtual int vfunc(int x) = 0;
};
class vclass : public base
{
public:
int vfunc(int x);
};
class nvclass
{
public:
int nvfunc(int x);
};
nvclass *nvfactory();
vclass* vfactory();
#endif
类。CPP:
#include "classes.h"
int vclass:: vfunc(int x)
{
return x+1;
}
int nvclass::nvfunc(int x)
{
return x+1;
}
nvclass *nvfactory()
{
return new nvclass;
}
vclass* vfactory()
{
return new vclass;
}
这就是所谓的:
#include <cstdio>
#include <cstdlib>
#include "classes.h"
#if 0
#define ASSERT(x) do { if(!(x)) { assert_fail(__FILE__, __LINE__, #x); } } while(0)
static void assert_fail(const char* file, int line, const char *cond)
{
fprintf(stderr, "ASSERT failed at %s:%d condition: %s \n", file, line, cond);
exit(1);
}
#else
#define ASSERT(x) (void)(x)
#endif
#define SIZE 10000000
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ((unsigned long long)lo)|(((unsigned long long)hi)<<32);
}
void print_avg(const char *str, const int *diff, int size)
{
int i;
long sum = 0;
for(i = 0; i < size; i++)
{
int t = diff[i];
sum += t;
}
printf("%s average =%f clocks\n", str, (double)sum/size);
}
int diff[SIZE];
int main()
{
unsigned long long a, b;
int i;
int sum = 0;
int x;
vclass *v = vfactory();
nvclass *nv = nvfactory();
for(i = 0; i < SIZE; i++)
{
a = rdtsc();
x = 16;
sum+=x;
b = rdtsc();
diff[i] = (int)(b - a);
}
print_avg("Emtpy", diff, SIZE);
for(i = 0; i < SIZE; i++)
{
a = rdtsc();
x = 0;
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
x = v->vfunc(x);
ASSERT(x == 4);
sum+=x;
b = rdtsc();
diff[i] = (int)(b - a);
}
print_avg("Virtual", diff, SIZE);
for(i = 0; i < SIZE; i++)
{
a = rdtsc();
x = 0;
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
x = nv->nvfunc(x);
ASSERT(x == 4);
sum+=x;
b = rdtsc();
diff[i] = (int)(b - a);
}
print_avg("no virtual", diff, SIZE);
printf("sum=%d\n", sum);
delete v;
delete nv;
return 0;
}
代码的真正区别是: 虚拟呼叫:
40066b: ff 10 callq *(%rax)
非虚拟呼叫:
4006d3: e8 78 01 00 00 callq 400850 <_ZN7nvclass6nvfuncEi>
结果:
Emtpy average =78.686081 clocks
Virtual average =144.732567 clocks
no virtual average =122.781466 clocks
sum=480000000
记住,这是对于每循环16所调用的开销,所以调用一个函数,而不是调用函数之间的差值大约是每次迭代5个时钟周期[包括相加的结果和所需的其它处理],和虚拟呼叫每次迭代增加22个时钟,因此每个呼叫约1.5个时钟。
我怀疑你会发现,假设你做的东西有点不是在你的函数返回X + 1更有意义。
什么是您的*显著开销定义*?您可能会惊讶于几百万次调用虚函数的开销。 –
您是否真的证明vtable开销是您的代码的问题?如果是这样,你能证明做了相关的“如果(这个班)这样做是否更快”?我怀疑它不是,除非它使编译器内联函数,并且节省了大量的工作。 –
我还没有证明它...这就是为什么我想首先创建这就避免了虚函数表的方法,这样我可以比较两个,并有那开销怎么显著是:) – linuxfever