在gcc中加速虚拟函数调用 用GPROF剖析C++代码,我发现我的一部分时间花了一遍又一遍地调用一个虚拟方法。该方法本身很短,如果不是虚拟的,则可能是内联的
除了将其全部重写为非虚拟之外,我还有哪些方法可以加快速度?您确定时间与通话相关吗?成本在哪里,可能是功能本身吗?如果是这种情况,简单地内联可能会使函数从分析器中消失,但您不会看到太多的加速 假设这真的是进行这么多虚拟调用的开销,那么在不进行非虚拟调用的情况下,您可以做的事情是有限的 如果调用有时间/标志之类的提前退出,那么我通常会使用两级方法。检查与非虚拟调用内联,仅在必要时调用特定于类的行为 例如在gcc中加速虚拟函数调用 用GPROF剖析C++代码,我发现我的一部分时间花了一遍又一遍地调用一个虚拟方法。该方法本身很短,如果不是虚拟的,则可能是内联的,c++,virtual-functions,gprof,C++,Virtual Functions,Gprof,除了将其全部重写为非虚拟之外,我还有哪些方法可以加快速度?您确定时间与通话相关吗?成本在哪里,可能是功能本身吗?如果是这种情况,简单地内联可能会使函数从分析器中消失,但您不会看到太多的加速 假设这真的是进行这么多虚拟调用的开销,那么在不进行非虚拟调用的情况下,您可以做的事情是有限的 如果调用有时间/标志之类的提前退出,那么我通常会使用两级方法。检查与非虚拟调用内联,仅在必要时调用特定于类的行为 例如 是在实际函数调用中花费的时间,还是在函数本身中花费的时间 虚拟函数调用明显比非虚拟调用慢,因为虚
是在实际函数调用中花费的时间,还是在函数本身中花费的时间 虚拟函数调用明显比非虚拟调用慢,因为虚拟调用需要额外的解引用。(如果你想阅读所有令人毛骨悚然的细节,请在谷歌上搜索“vtable”。更新:事实证明,这一点并不糟糕
“显而易见”,但是,如果它消耗了整个计算的一个重要部分,包括在调用函数中花费的时间,那么听起来像是考虑虚拟化和内联的一个奇妙的地方。
但在接近20年的C++中,我认为我从未见过这种情况。我很想看看代码。如果虚拟调用确实是瓶颈,请尝试一下。请注意,“虚拟”和“内联”不是对立的——一个方法可以两者兼而有之。如果编译器可以在编译时确定对象的类型,那么它将乐于内联虚拟函数:
struct B {
virtual int f() { return 42; }
};
struct D : public B {
virtual int f() { return 43; }
};
int main(int argc, char **argv) {
B b;
cout << b.f() << endl; // This call will be inlined
D d;
cout << d.f() << endl; // This call will be inlined
B& rb = rand() ? b : d;
cout << rb.f() << endl; // Must use virtual dispatch (i.e. NOT inlined)
return 0;
}
结构B{
虚拟int f(){return 42;}
};
结构D:公共B{
虚拟int f(){return 43;}
};
int main(int argc,字符**argv){
B B;
如果你没有C++的语法糖,你可以考虑在旧的“C”中编写代码。有时答案不是使用间接调用。参见一个例子。 < P>你可以通过改变调用约定来从虚拟调用中获得更好的性能。ler有一个uu快速调用约定,它在cpu寄存器中而不是在堆栈上传递参数
如果你被虚拟调用所困扰,并且这几个操作真的很重要,那么请查看编译器文档以了解支持的调用约定。是否可以发布一些代表虚拟函数及其调用方式的代码。我没有使用gprof,但它不是度量函数内部的时间吗比通话时间长?虚拟并不意味着非内联。详细信息请参阅我的完整答案。+1用于在这里讨论整个问题,包括您的经验。我也很难相信通话开销是真正的问题。虽然正确,但这是一种在现实生活中虚拟的人为情况(哈哈!)从不发生-如果发生,则在上述代码中“f”甚至不需要是虚拟的。B&rb=rand()?b:d;//很明显为什么f需要是虚拟的。@安德鲁:我不同意——我的观点是,有可能使一个方法成为虚拟的,从而实现随之而来的灵活性,同时尽可能不牺牲内联可用的速度。@M alters:很好的建议,我相应地更新了帖子。+1.这个解决方案是r因为在这种情况下,询问者实际上已经确定了缓慢的原因是这个函数调用——但一般来说,在确定代码在哪里花费时间之前,不要使用开关进行“优化”。
struct B {
virtual int f() { return 42; }
};
struct D : public B {
virtual int f() { return 43; }
};
int main(int argc, char **argv) {
B b;
cout << b.f() << endl; // This call will be inlined
D d;
cout << d.f() << endl; // This call will be inlined
B& rb = rand() ? b : d;
cout << rb.f() << endl; // Must use virtual dispatch (i.e. NOT inlined)
return 0;
}