C 对同一函数的重复调用能否提供更好的性能?

C 对同一函数的重复调用能否提供更好的性能?,c,C,我有如下代码: void foo(unsigned long k) { if (k & 1) { bar(k/2 + 1); bar(k/2); bar(k/2 + 1); } else { bar(k/2); bar(k/2); bar(k/2); } } void bar(unsigned long k) { switch(k) {

我有如下代码:

void foo(unsigned long k)
{
    if (k & 1)
    {
        bar(k/2 + 1);
        bar(k/2);
        bar(k/2 + 1);
    }
    else
    {
        bar(k/2);
        bar(k/2);
        bar(k/2);
    }
}

void bar(unsigned long k)
{
  switch(k)
  {
     case default: special_default(); break;
     case 1: specialbar1(); break;
     case 2: specialbar2(); break;
     <more cases>
     case 16: specialbar16(); break;
  }
}
void foo(无符号长k)
{
if(k&1)
{
钢筋(k/2+1);
巴(k/2);
钢筋(k/2+1);
}
其他的
{
巴(k/2);
巴(k/2);
巴(k/2);
}
}
空心条(无符号长k)
{
开关(k)
{
案例默认值:特殊_default();中断;
案例1:specialbar1();中断;
案例2:specialbar2();中断;
案例16:specialbar16();中断;
}
}
当调用
foo
的偶数值
k
时,性能会更好。每个
specialbar#()
方法都使用几个堆栈变量,这些变量的数量随着
k
的增加而急剧增加。明确地说,
specialbar#()
使用了大约
3*k
局部变量,所有这些变量都是
无符号长变量

例如,
foo(32)
的执行速度比
foo(31)
快15%。我正在使用Visual Studio 2012,性能分析向我保证,两次调用
specialbar16
和一次调用
specialbar15
比连续三次调用
specialbar16
花费的工作量要多得多

k
为偶数时,编译器是否可能利用这三个连续调用?也就是说,它能否意识到,对于偶数
k
的三次连续调用,堆栈基本上是相同的,而对于奇数
k
则不可能进行相同的优化

当k为偶数时,编译器是否可能利用这三个连续调用?也就是说,它能意识到,对于偶数k,堆栈在三次连续调用中基本相同,而对于奇数k,不可能进行相同的优化吗

这似乎不值得回答,但是,是的,这是完全可能的。编译器可能会意识到每次调用都需要相同的堆栈布局,因为每次调用都是相同的方法,因此避免了每次方法调用的整个堆栈设置/拆卸。在本例中,它可能还内联了方法调用—代码在调用方中就地生成


对于另一种情况,很可能也会执行类似的优化,尽管优化很棘手,有时编译器无法执行优化的原因也很微妙。

当k为奇数(k/2+1)时,your's foo函数会执行额外的逻辑


要回答您的具体问题,重复呼叫是否可以提高性能。是的,当参数相同时,函数中的部分相同,这允许“分支预测”以最佳方式工作。

您并不是真正测量相同的东西,因为您在每种情况下调用不同的
specialbar_k()
函数,它们可能会做不同的事情,也许最好用等价的方法来代替specialbar#()方法,每个方法都处理一个偶数k值和相应的k-1值。然而,我认为这本书可读性较差,有点迂腐。当一个人注意到最好是连续调用同一个方法时,他会走这么长的路吗?我个人认为,试图智胜优化编译器是一个糟糕的举动。表演真的如此重要以至于你需要考虑这样做吗?您可能最终会减慢这两种情况的速度。@davmac,“超过”编译器如果这是您最后做的事情,并且您需要最后的速度提升,那么出于优化目的,它是可以的。然而,从可移植性的角度来看,你是对的,这是一个糟糕的举动。@Adrian,如果你真的需要速度,当然没关系,只是(a)你可能不会成功,(b)你通常并不真的需要速度。是否有可能提供一个链接,指向分支预测的进一步信息,任何方向都会很有帮助。@Peter-搜索分支预测,还有缓存驻留,因为函数已经在处理器缓存中。后续对它的调用会更快,因为不会有任何加载或缓存未命中来获取操作码。