c++ - 了解 GCC 内联
问题描述
我一直在尝试重构一些中等大小的低级代码,我不能说我对编译器优化器内联代码的方式太满意了。
我不太了解 gcc 如何内联代码,但对于我的一个特殊情况,通过使用以下选项,我获得的运行时速度与 gcc 8.2.1 中的手写代码相当:
-std=c++17 -Winline
-Ofast -march=native -DNDEBUG
-finline-limit=100000 --param large-function-insns=10000 --param large-stack-frame-growth=1000
--param inline-unit-growth=1000 --param early-inlining-insns=150 --param max-early-inliner-iterations=1000
-fopenmp -fPIC
如果没有内联选项,我的程序会慢 3 倍。我本来希望有一个更简单的选项来告诉编译器“相信我,当我说内联时,你必须内联它”。有这样的编译器选项吗?
笔记:
- 关于代码的一些细节:有 3 个嵌套的 for 循环,第三个是 SIMD,每次迭代都在计算复杂的固定大小的线性代数。线性代数本身不是 SIMD(因为上面的循环是)。大多数抽象处理多维数组和密集线性代数(需要表达式模板)。
- 我想要内联的所有函数都在编译单元中定义。我没有递归或虚函数,我不抛出异常。我的函数是 constexpr 而不是 inline,bu constexpr 意味着隐式内联。没有第 3 方库调用(所有调用都是数学函数,例如 std::sqrt)。除了 SIMD,没有并行性。
- 在重构之初,当内联函数还很少的时候,绝对没有问题。但是随着我添加越来越多的内联函数来抽象代码,编译器开始与内联(以及其他东西,例如似乎 SROA)斗争。
- 我有很多小函数要内联。我不是为了它而定义函数,但我确实需要定义很多函数以便通用。
- 我正在研究一个用于性能测量的现实测试用例。这不是一个微观基准,所以我确信我正在测量我真正想要测量的东西。
- 如果我的热循环中的函数没有内联,我会测量 x2 性能损失(当然是因为它阻止了许多进一步的优化,特别是矢量化和 SROA)
- 我开始使用 intel 编译器来解决这个问题,它的模板代码非常缓慢且有问题。保持手写性能非常复杂,所以我切换到 gcc。
现在我注意到一些奇怪的行为:
- 在某些情况下,不使用
-fPIC
made gcc 会发出-Winline
警告说它没有内联。我不明白-fPIC
和内联之间的关系。 - 我不明白需要为 gcc 指定早期内联传递。我本来以为
--param early-inlining-insns=150
应该只用来优化编译时间,而不是 gcc 生成的代码。但事实是,如果值为,50
我会得到一个无声的错误内联(gcc 没有警告),如果值为,1000
我也会得到错误的内联(这次 gcc 警告我)。到底是怎么回事? - 我有点不愿意使用
__attribute__((always_inline))
,因为对每个小函数都这样做会很难看,但在我看来,即使有了这个属性,gcc 有时也不会内联函数。gcc 真的总是用这个属性内联函数吗?
如何强制 gcc 内联我的所有inline
函数?即使在概念上,我也不明白为什么编译器在手动操作看起来如此简单的情况下内联如此困难。内联是否存在可伸缩性优化问题?
解决方案
推荐阅读
- python - 将文件复制到目录时出现 FileNotFoundError
- python-2.7 - wxPython 4:检测双击键
- laravel - 如何在循环中只返回两个值
- c++ - log4cxx 中的深拷贝附加程序
- java - 从复选框获取数据并使用hibernate放入数据库
- c# - 在不更改目标类型的情况下以最大精度序列化浮点数
- android - 如何从相机/行车记录仪读取视频记录
- php - 无法在 Symfony 4 中加载 Validator 组件的类
- angular - 找不到不同的支持对象 NgStyle backgroundImage
- pentaho - 在 pentaho 作业中设置 FTP 文件下载限制