Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gcc 什么是内联函数的好启发法?_Gcc_Gnu_Compiler Construction_Icc_Inlining - Fatal编程技术网

Gcc 什么是内联函数的好启发法?

Gcc 什么是内联函数的好启发法?,gcc,gnu,compiler-construction,icc,inlining,Gcc,Gnu,Compiler Construction,Icc,Inlining,考虑到您只想优化速度,有什么好的启发式方法可以决定是否内联函数?显然,代码大小应该很重要,但是当(比如)gcc或icc决定是否内联函数调用时,是否还有其他通常使用的因素?在这方面有没有什么重要的学术工作?函数调用意味着一些额外的代码(函数序言,其中设置了新堆栈框架,函数尾声,其中清理了新堆栈框架)。如果您的编译器发现函数代码与序言和尾声相比很小,那么它可以决定不值得进行实际调用,并将函数内联 我所看到的调用函数而不是内联函数的唯一好处是与大小相关的。我猜内联一个函数然后展开一个循环会导致显著的大

考虑到您只想优化速度,有什么好的启发式方法可以决定是否内联函数?显然,代码大小应该很重要,但是当(比如)gcc或icc决定是否内联函数调用时,是否还有其他通常使用的因素?在这方面有没有什么重要的学术工作?

函数调用意味着一些额外的代码(函数序言,其中设置了新堆栈框架,函数尾声,其中清理了新堆栈框架)。如果您的编译器发现函数代码与序言和尾声相比很小,那么它可以决定不值得进行实际调用,并将函数内联


我所看到的调用函数而不是内联函数的唯一好处是与大小相关的。我猜内联一个函数然后展开一个循环会导致显著的大小增加。

据我所见,函数大小是编译器用来确定内联的唯一因素。然而,如果您进行概要文件引导优化(PGO),我相信编译器能够使用其他变量,例如调用数/调用设置时间。

在.NET中,主要是基于大小。测量父函数和子函数的大小(以编译字节为单位)。然后测量组合函数的大小。如果组合函数较小,那么内联是一个好主意

这样做的原因是可以将尽可能多的代码放入CPU的缓存中。缓存未命中比现代CPU中的函数调用要昂贵得多。

维基百科有关于这一点的段落,底部有一些链接:

  • 除了内存大小和缓存问题外。从编译器的角度来看,“内联过程中添加的变量可能会消耗额外的寄存器,在寄存器压力已经很高的区域,这可能会导致溢出,从而导致额外的RAM访问。”
具有JIT编译器和运行时类加载的语言还有其他权衡,因为虚拟方法不是静态已知的,但JIT可以收集运行时分析信息,例如方法调用频率:

  • (对于Java)讨论了静态方法和动态加载类的方法内联及其性能改进

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

显示了许多文件,例如

展示了相当多的书籍,其中有关于函数内联在各种上下文中的论文或章节

  • 有一章介绍编译器设计中的统计和机器学习技术,使用启发式设置各种参数,分析结果。本章参考Vaswani等人的论文,他们在论文中提出“使用经验建模” 为编译器优化构建微体系结构敏感模型的技术”

  • (其他一些书从程序员的角度讨论内联,例如,它讨论了过多内联函数的危险以及内联与宏之间的差异。如果编译器可以确定程序员的内联请求弊大于利,那么它们通常会忽略程序员的内联请求;这可以用宏作为替代。)最后的办法。)


@Mitch:当然,但我很好奇编译器是如何决定是否内联的。我认为,主要是指令的数量……内联不会影响缓存,因此(如果没有内联)函数代码将与“主”代码放在单独的缓存线上。NET如何处理多种内联可能性(也就是说,如果在3个不同的位置调用func1,.NET是否尝试所有内联组合,或者只尝试全部或不尝试任何组合)?NET是JIT编译的,因此它可以在运行时使用关于不同内联可能性的信息做出决策。这只是我的直觉,但是如果.NET没有在3个不同的位置以不同的方式内联func1,我会感到惊讶,因为它应该有信息来做出明智的决策。在这种情况下,您可能需要一本关于JIT技术的书。Honestly、 我不太清楚细节,我只看过一篇关于它的文章。