【问题标题】:Why does't the compiler inline functions written on different source files?为什么编译器不内联编写在不同源文件上的函数?
【发布时间】:2013-09-28 21:37:22
【问题描述】:

我一直在使用 Valgrind 进行一些测试,以了解编译器如何翻译函数,并发现有时,由于未内联,与编写在同一源文件中的函数相比,编写在不同文件上的函数性能较差。

考虑到我有不同的文件,每个文件都包含与特定区域相关的函数,并且所有文件共享一个声明所有函数的公共标题,这是预期的吗?

为什么当它们写在不同的文件上时编译器不内联它们而当它们在同一个页面上时呢?

如果这种行为开始导致性能问题,建议采取什么措施,在编译之前手动将所有函数放在同一个文件中?

示例:

//source 1
    void foo(char *str1, char *str2)
    {
        //here goes the code
    }

//source 2
    void *bar(int something, char *somethingElse)
    {
        //bar code
        foo(variableInsideBar, anotherVariableCreatedInsideBar);
        return variableInsideBar;
    }

示例性能成本:

在不同的文件上:29920

两者都在同一个文件中:8704

对于更大的功能,它不那么明显,但仍然会发生。

【问题讨论】:

    标签: c function compilation inline


    【解决方案1】:

    如果您使用gcc,您应该尝试选项-combine-fwhole-program,并在一次调用中将所有源文件传递给编译器。传统上不同的 C 文件是分开编译的,但优化交叉编译单元(文件)变得越来越普遍。

    【讨论】:

    • 这个选项的 MS 版本是 /gl 值得注意的是,在大型项目中,这些选项可以完全破坏迭代时间。我不了解 gcc,但在 MS 工具链中,链接是单线程的,因此您最终会获得 30 多分钟的链接时间,而无法加快它们的速度。
    【解决方案2】:

    编译器本身不能内联定义在不同翻译单元中的函数,因为它看不到这些函数的定义,即看不到这些函数的源代码。从历史上看,C 编译器(以及语言本身)是围绕独立翻译的原则构建的。每个翻译单元从源代码编译成目标代码,完全独立于其他翻译单元。只有在翻译的最后阶段,所有这些不相交的目标代码片段才通过所谓的链接器组装成最终程序。但在那个时候,在传统的编译器实现中,内联任何东西已经太迟了。

    您可能知道,函数内联的语言级支持表明,为了使函数在某个翻译单元中“可内联”,它必须在该翻译单元中定义,即其主体的源代码应该该翻译单元中的编译器可以看到。这一要求直接源于上述独立翻译原则。

    许多现代编译器正在逐步引入克服经典纯独立翻译限制的功能。它们实现了诸如全局优化之类的特性,允许跨越翻译单元边界的各种优化。这可能包括内联其他翻译单元中定义的函数的能力。请查阅您的编译器文档,以了解它是否可以跨翻译单元内联函数以及如何启用此类优化。

    默认情况下通常禁用此类全局优化的原因是它们会显着增加翻译时间。

    【讨论】:

      【解决方案3】:

      哇,你怎么注意到的。我认为那是因为你编译了一些东西,首先编译器将一个 c 文件转换为一个目标文件,而不查看任何其他文件。生成目标文件后,它不会应用任何优化。

      我认为它不会花费太多性能。

      【讨论】:

      • 发生这种情况,即使在最高级别进行优化,所有函数都在头文件中声明,并且同时编译。
      • 然后编译器将源代码编译为目标文件,他只寻找这一个c文件,并从头文件中寻找带有函数声明的常量。它不知道使用的函数的代码,他只知道如何调用它们,并留下信息供链接器稍后链接该函数。它不能内联那个代码,他甚至在这个阶段都不知道。如果需要,您可以简单地复制它。
      猜你喜欢
      • 2011-01-25
      • 1970-01-01
      • 2018-06-16
      • 1970-01-01
      • 2017-01-05
      • 2015-02-20
      • 2021-04-29
      • 1970-01-01
      • 2017-07-03
      相关资源
      最近更新 更多