12

在 c++ 中,什么是估计内联函数的计算时间优势的一个很好的启发式方法,特别是当函数被非常频繁地调用并且占程序执行时间的 >= 10% 时(例如,蛮力的评估函数或随机优化过程)。尽管内联最终可能超出我的控制范围,但我仍然很好奇。

4

6 回答 6

6

没有普遍的答案。它取决于硬件、参数的数量和类型,以及函数中的功能。以及调用的频率和位置。例如,在 Sparc 上,参数(和返回值)在寄存器中传递,每个函数获得 16 个新寄存器:如果函数足够复杂,这些新寄存器可以避免函数被内联时发生的溢出,并且非内联版本最终可能比内联版本更快。在寄存器较差且在寄存器中传递参数的 Intel 上,对于同一程序中的同一函数,情况可能正好相反。更一般地说,内联可能会增加程序大小,减少局部性。或者对于非常简单的功能,它可能会减小程序大小;但这又取决于架构。唯一可能知道的方法是尝试两者,测量时间。即便如此,您也只会在该特定硬件上知道该特定程序。

于 2011-08-18T13:19:34.797 回答
1

在某些架构上,函数调用和返回每个只需要一条指令(尽管它们通常不是类似 RISC 的单周期指令。)通常,您可以将其与函数体表示的周期数进行比较. 一个简单的属性访问可能只有一条指令,因此将其放入非内联函数将使执行它的指令数量增加三倍——显然是内联的一个很好的候选者。另一方面,格式化字符串以进行打印的函数可能代表数百条指令,因此再增加两条根本不会产生任何影响。

于 2011-08-18T12:52:45.367 回答
1

如果您的瓶颈在递归函数中,并且假设递归级别不是最小的(即平均递归不仅仅是几个级别),那么您最好在函数中使用算法而不是使用内联

如果可能,尝试将递归转换为循环或尾递归(编译器可以将其隐式转换为循环),或者尝试确定函数中花费的成本。尽量减少内部操作的影响(也许您正在动态分配可能具有自动存储持续时间的内存,或者您可以考虑在包装器中在函数外部执行的常见操作并作为额外参数传入。 ..)

*在评论不是递归而是迭代之后进行编辑*

如果编译器可以访问函数的定义,它会在大多数情况下为您做出正确的决定。如果它无权访问定义,只需移动代码以便它可以看到它。也许使该函数成为一个static函数以提供一个额外的提示,即它不会在其他任何地方使用,甚至将其标记为inline(知道这不会强制内联),但避免使用将强制内联的特殊属性,因为编译器可能它比任何无需查看代码即可生成的简单启发式方法做得更好。

于 2011-08-18T13:00:09.137 回答
1

所有内联为您节省的是函数的进入/退出成本,因此只有当函数几乎什么都不做时才值得考虑。当然,如果函数本身包含函数调用,则可能不值得考虑。

即使函数做的很少,它也必须被调用很多,以至于它在相当大的百分比时间内拥有程序计数器,然后函数的任何加速才会明显。

于 2011-08-18T14:17:42.007 回答
0

这里的行为在某种程度上取决于编译器。使用递归函数,显然内联行为理论上可以是无限的。'inline' 关键字只是给编译器的一个提示,如果它不能用它做任何事情,它可以选择它忽略。一些编译器会将递归函数内联到一定深度。

至于“这将加快多少速度” - 不幸的是,我们无法为这个问题提供任何类型的答案,因为“这取决于” - 函数做了多少工作与函数调用机制本身的开销。你为什么不设置一个测试看看?

于 2011-08-18T12:53:24.093 回答
0

我们 20 多年编写计算密集型 C++ 的经验是,内联不是灵丹妙药。您确实需要分析您的代码以查看内联是否会提高性能。对我们来说,除了低级别的 2D 和 3D 点和矢量操作外,内联是浪费时间。你最好制定一个更好的算法,而不是试图微观管理时钟滴答。

于 2011-08-18T13:44:35.057 回答