考虑到您只是尝试优化速度,那么决定是否内联函数的良好启发式是什么?显然代码大小应该很重要,但是当(例如)gcc 或 icc 确定是否内联函数调用时通常会使用其他因素吗?该领域有任何重要的学术工作吗?

有帮助吗?

解决方案

维基百科有 A 很少 关于此的段落,底部有一些链接:

  • 除了内存大小和缓存问题之外, 另一个考虑因素是套准压力. 。从编译器的角度来看,“内联过程中添加的变量可能会消耗额外的寄存器,并且在寄存器压力已经很高的区域中,这可能会强制溢出,从而导致额外的 RAM 访问。”

具有 JIT 编译器和运行时类加载的语言还有其他权衡,因为虚拟方法不是静态已知的,但 JIT 可以收集运行时分析信息,例如方法调用频率:

  • 即时编译器中优化的设计、实现和评估 (针对 Java)讨论静态方法和动态加载类的方法内联及其对性能的改进。

  • 练习柔道:动态优化下的 Java 声称他们的“内联策略基于代码大小和分析信息。如果方法条目的执行频率低于某个阈值,则该方法不会被内联,因为它被视为冷方法。为了避免代码爆炸,我们不会内联字节码大小超过 25 字节的方法。。。。为了避免沿着深度调用链进行内联,当沿着调用链累积的内联字节码大小超过 40 个字节时,内联就会停止。”尽管他们有运行时分析信息(方法调用频率),但他们仍然小心地避免内联大型函数或函数链以防止肿胀。

在谷歌学术上搜索 揭示了许多论文,例如

在 Google 图书上搜索 揭示了相当多的书籍,其中包含有关各种上下文中的函数内联的论文或章节。

  • 编译器设计手册:优化和机器代码生成 有一个关于编译器设计中的统计和机器学习技术的章节,通过启发式方法设置各种参数,分析结果。本章参考了 Vaswani 等人的论文 用于编译器优化的微架构敏感经验模型 他们建议“使用经验建模技术来构建用于编译器优化的微体系敏感模型”。

  • (其他一些书是从程序员的角度讲inling,比如 游戏程序员的 C++, ,其中讨论了过于频繁内联函数的危险以及内联和宏之间的差异。如果编译器确定程序员的内联请求弊大于利,那么他们通常会忽略程序员的内联请求。作为最后的手段,这可以用宏覆盖。)

其他提示

一个函数调用意味着一些附加代码(函数序言,其中所述新的堆栈帧被设置,和函数尾声,在那里它的清理)。如果你的编译器看到的是功能代码是小相比,序幕和尾声,它可以决定它不值得做的实际调用,并会内联函数。

的唯一受益我看到调用一个函数,而不是内联它是尺寸相关的。我估计内联函数然后展开循环可导致显著尺寸增加。

据我有锯,功能大小是用于确定内联的唯一因素编译器。但是,如果你这样做了profile指导的优化(PGO),我相信编译器能够使用其他变量,如通话/呼叫建立时间的数量。

在.NET是主要基于大小。测量父函数的编译字节大小和子功能。然后测量组合函数的大小。如果组合函数越小,则内联是一个好主意。

这样做的原因是为了使人们有可能推尽可能多的代码插入到CPU的缓存越好。高速缓存未命中是远远大于在现代CPU函数调用更贵。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top