我正在制作矢量/矩阵库。 (海湾合作委员会,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));
您如何看待每个案件的费用?
答案 0 :(得分:3)
当函数内联时,通常不会直接涉及调用的变量复制。变量仍然会被移动并放在堆栈上,有时作为执行的正常部分,但不是函数调用的直接结果。 (当你用完寄存器时,一些值可能会被放到堆栈上等等......但仅在需要的时候。)所以当一个函数被内联时,“call”的开销基本上消失了(不再设置/拆除)堆栈帧,没有更多的无条件跳转,没有更多的推/弹参数。)
如果你可以依靠你的always_inline
属性总是内联函数,那么你也不应该通过指针传递Vector(如果没有修改)。这样做的原因是通过指针传递它需要采用向量的地址,这意味着编译器必须确保它有一个地址,因此它不能仅存在于CPU寄存器中。如果不需要,这会减慢速度,当你获取某些东西的地址时,编译器将始终确保它有一个地址,因为编译器无法确定不需要该地址。
由于pass-by-pointer,此代码总是会有一条指令来获取对象的地址,并且至少有一个解引用来获取成员的值。如果你按值传递,那么这可能仍然会发生,但编译器可能能够优化所有这些。
不要忘记过度使用内联可能会显着增加编译器二进制代码的大小。在某些情况下,具有较大的代码段(由于内联函数)会导致更多的指令缓存未命中,从而导致性能降低,因为CPU经常不得不去主内存来获取程序的一部分,因为其中一些是太大了,不适合小型L1缓存。这在嵌入式处理器(如iPhone)中尤其重要,因为这些处理器通常具有较小的缓存。