【问题标题】:Inline function and calling cost in CC中的内联函数和调用成本
【发布时间】:2010-05-01 13:39:51
【问题描述】:

我正在制作一个向量/矩阵库。 (GCC、ARM NEON、iPhone)

typedef struct{ float v[4]; } Vector;
typedef struct{ Vector v[4]; } Matrix;

我将结构数据作为指针传递,以避免调用函数时数据复制导致性能下降。所以我一开始设计了这样的功能:

void makeTranslation(const Vector* factor, Matrix* restrict result);

但是,如果函数是内联的,是否有任何理由将值作为指针传递以提高性能?这些变量也被复制了吗?寄存器和缓存怎么样?我试图重新设计这样的功能:

inline Matrix makeTranslation(const Vector factor) __attribute__ ((always_inline));

您如何看待每个案例的通话费用?

  • 我在第二个签名中添加了“const”以反映建议。

【问题讨论】:

  • 您可能想要const Vector* factor 而不是Vector* const factor
  • 再次感谢 KennyTM。我更新了我的问题。

标签: c inline-functions


【解决方案1】:

当函数是内联的时,调用通常不会直接涉及到变量的复制。变量仍然会被移动并放入堆栈,有时作为执行的正常部分,而不是作为函数调用的直接结果。 (当您用完寄存器时,一些值可能会被放入堆栈等......但仅在需要时。)因此,当函数被内联时,“调用”的开销基本上消失了(不再设置/拆除堆栈帧,不再无条件跳转,不再推入/弹出参数。)

如果您可以依靠您的always_inline 属性始终 内联函数,那么您也不应该通过指针传递向量(如果未修改)。原因是通过指针传递它需要获取向量的地址,这意味着编译器必须确保它有一个地址,因此它不能只存在于 CPU 寄存器中。如果不需要它,这会减慢速度,并且当您获取某物的地址时,编译器将始终确保它有一个地址,因为编译器无法确定该地址是不需要的。

由于指针传递,这段代码总是有一条指令来获取对象的地址,并且至少有一个取消引用来获取成员的值。如果您按值传递,那么这可能仍然会发生,但编译器可能能够优化所有这些。

不要忘记过度使用内联会显着增加编译器二进制代码的大小。在某些情况下,具有较大的代码段(由于内联函数)可能会导致更多的指令缓存未命中,这将导致性能下降,因为 CPU 不断地不得不去主内存来获取程序的一部分,因为其中一些是太大而无法放入小型 L1 缓存中。这在嵌入式处理器(如 iPhone)中可能尤其重要,因为这些处理器通常具有较小的缓存。

【讨论】:

  • 据我所知,这仅在您将参数声明为 const 时才成立(或者编译器本身能够检测到这种行为)。该示例没有这样做,这是一个重要的细节。
  • @KillianDS: 如果参数不是 const 就没有这样的优化吗?
  • 这可能是真的,我不确定。通常在这种情况下最好的答案是“看看你的编译器在这两种情况下的汇编输出是什么,然后选择你更喜欢的那个。”我可能应该这样回答并为自己省点麻烦:-P
  • @SoapBox:感谢您的详细解释。我会考虑缓存大小和分析。但是,如果我采用按值传递设计,则内联将是唯一的选择。
  • @SoapBox:你确定编译器总是会发出指令来获取地址吗?在我看来,假设函数是内联的,编译器可能会证明实际上并不需要获取地址。
猜你喜欢
  • 2010-11-06
  • 2019-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多