我记得Agner Fog的优秀指南,64位Linux可以通过寄存器传递6个整数函数参数:
http://www.agner.org/optimize/optimizing_cpp.pdf
(第8页)
我有以下function:
void x(signed int a, uint b, char c, unit d, uint e, signed short f);
我需要传递一个额外的无符号短参数,总共为7。 但是,我现在可以从现有的一个6中得出第七个的值。
所以我的问题是以下哪个是更好的性能实践:
有关的操作是一个简单的位移:
unsigned short g = c & 1;
不完全理解x86汇编器我不太确定寄存器是多么珍贵,是否更好地重新计算一个值作为局部variables,而不是通过函数调用作为parameter passing?
我的看法是,最好两次计算这个值,因为这是一个简单的1个CPU周期任务。
编辑我知道我可以简单介绍这一点,但我也想了解两种方法在引擎盖下发生了什么。 有第七个参数这是否意味着caching/内存涉及,而不是寄存器?
传递参数的机器约定被称为应用程序二进制接口 (或ABI),而对于x86-64 ABI规范描述的是x86-64 。 另请参阅x86调用约定 wikipage。
在你的情况下,可能不值得将c & 1
作为附加参数传递(因为第 7 个参数在栈上传递)。
不要忘记,当前的处理器内核(在台式机或笔记本电脑上)通常是乱序执行,并且是超标量的 ,因此c & 1
操作可以与其他操作并行完成,并且可能“没有”任何成本。
但是让编译器留下这样的微观优化。 如果你关心性能,使用最近的GCC 4.8编译器和gcc-4.8 -O3 -flto
编译和链接(即启用链接时优化 )。
顺便说一句,缓存性能比这样的微优化更有意义。 单个高速缓存未命中可能需要与数百个CPU机器指令相同的时间(例如250纳秒)。 传闻目前的CPU主要是等待缓存。 你可能想要添加一些明确的(和明智的)调用__builtin_prefetch
(看到这个问题和这个答案 )。 但是,添加太多这些预取会减慢你的代码。
最后,代码的可读性和可维护性应该比原始性能重要得多!
巴西尔的回答是好的,我只想指出另一件事要牢记:
a)堆栈很可能在L1缓存中,所以在堆栈上传递参数不应超过3个周期。
b)在这种情况下,ABI(x86-64系统V)需要修复寄存器。 一些由呼叫者保存,另一些由被呼叫者保存。 显然,如果原来的内容被再次需要,调用者必须保存用于传递参数的寄存器。 但是当你的函数使用比保存的调用者更多的寄存器时,函数需要计算的任何额外的临时结果必须进入被调用者保存的寄存器。 所以函数最终会溢出堆栈上的寄存器,重新使用寄存器作为临时变量,然后弹出原始值。
避免访问内存的唯一方法是使用更小,更简单的函数,它需要更少的临时变量。