C 中的内联函数和调用成本

Eon*_*nil 5 c inline-functions

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

typedef struct{ float v[4]; } Vector;
typedef struct{ Vector v[4]; } Matrix;
Run Code Online (Sandbox Code Playgroud)

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

void makeTranslation(const Vector* factor, Matrix* restrict result);
Run Code Online (Sandbox Code Playgroud)

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

inline Matrix makeTranslation(const Vector factor) __attribute__ ((always_inline));
Run Code Online (Sandbox Code Playgroud)

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

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

Soa*_*Box 5

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

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

由于采用指针传递,此代码将始终有一条指令来获取对象的地址,并且至少有一次取消引用来获取成员的值。如果您按值传递,那么这种情况仍然可能发生,但编译器可能能够优化所有这些。

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