在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;
}