为什么将返回移动到函数的末尾效率较低?[关闭]

Why is moving return to the end of the function less efficient? [closed]

提问人:Luchian Grigore 提问时间:7/9/2012 最后编辑:Luchian Grigore 更新时间:7/9/2012 访问量:227

问:

编辑:删除UB后(好地方,我错过了),时间或多或少相同。将标记版主以将其删除。

这两个函数是相同的,除了在两个分支上都有返回值,而末尾有一个:fooifgooreturn

int foo()
{
    static int x = 0;
    if ( x )
    {
        x > 2 ? x = 0 : ++x;
        return x-1;
    }
    else
    {
        x++;
        return x-1;
    }
}
int goo()
{
    static int x = 0;
    if ( x )
    {
        x > 2 ? x = 0 : ++x;
    }
    else
    {
        x++;
    }
    return x-1;
}

这些数字就在那里,所以优化不会太难,函数调用也不会被优化。在 MSVS 2010 上进行了全面优化

调用函数 4000000000 次,采样 10 次,总是更快:foo

  • foo - 平均 8830 毫秒
  • goo - 平均 8703 毫秒

差异很小,但它就在那里。为什么?另外,为什么编译器不将它们优化为相同的内容?

C++ 性能 优化

评论

1赞 Fred Foo 7/9/2012
您是否检查过汇编程序输出?
4赞 David Rodríguez - dribeas 7/9/2012
您正在编写代码来打扰优化器,然后您想知道其中的差异?如果您想了解您的特定示例,请阅读生成的程序集,但请注意,这可能根本不反映任何其他函数中会发生什么。
3赞 Fred Foo 7/9/2012
顺便说一句,in应该怎么做?我不是迂腐;我真的不知道该表达式的预期行为是什么,以及它是否会干扰优化器。++xx = x > 2 ? 0 : ++x
3赞 David Rodríguez - dribeas 7/9/2012
@larsmans:很好,这个表达是未定义的行为。
1赞 Luchian Grigore 7/9/2012
@larsmans UB 修复改变了一切。

答:

3赞 Torsten Robitzki 7/9/2012 #1

看一下汇编器的输出,在 goo() 的第一个分支中可能会跳转到函数的末尾。

评论

0赞 TerryE 7/9/2012
是的,但第一个分支从未被占用。
1赞 Chris Dargis 7/9/2012
我认为这与分支预测和流水线有关。
1赞 Torsten Robitzki 7/9/2012
@TerryE x 是静态的,因此它在第二个早午餐中递增,因此在下一个函数调用中调用第一个分支。
0赞 TerryE 7/9/2012
@TorstenRobitzki,是的,我也意识到在发表评论后,但为时已晚,无法编辑它:哎呀: -- Mindfart
0赞 Dorin Rusu 7/9/2012 #2

我假设这是因为在操作完成的那一刻,每个 ,都会返回计算出的变量。iffoo

goo,即使以为它做了同样的事情,除了两次返回之外,还是要检查语句。这需要一些时间(非常小),但正如你所看到的,它是可测量的。else

评论

4赞 Luchian Grigore 7/9/2012
你的意思是它仍然必须检查声明?else
0赞 Brandon 12/31/2013
我认为其他的不需要检查。首先,没有“检查”另一个。如果之前的一切都是假的,否则就是真的。此外,如果条件为真,则该块永远不会运行,因此我看不出工作有任何差异。就像其他人说的,汇编代码可能不同。ifelse
-3赞 Narendra 7/9/2012 #3

如果是 foo,则不会执行“if”和“else”的尾括号。退货后

语句 控件将直接获得函数的尾括号。

这就是为什么 foo 需要更少的时间。

评论

1赞 TerryE 7/9/2012
Naren,核心不执行“大括号”。它执行指令。但是,您在某种程度上是对的,因为某些编译器在 4/8 字节边界上对齐分支目标以帮助改进指令缓存,并且为第一个目标提供额外的目标和额外的代码可能会影响时序。return x+1
0赞 Narendra 7/9/2012
我知道这没有执行,但我通过给出断点来尝试这样做,执行直接转到函数的结束大括号......您还可以尝试使用断点并检查。