Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将值作为函数参数传递还是计算两次?_C++_C_Linux_Performance_Optimization - Fatal编程技术网

C++ 将值作为函数参数传递还是计算两次?

C++ 将值作为函数参数传递还是计算两次?,c++,c,linux,performance,optimization,C++,C,Linux,Performance,Optimization,我从Agner Fog的优秀指南中回忆起,64位Linux可以通过寄存器传递6个整数函数参数: (第8页) 我有以下功能: void x(signed int a, uint b, char c, unit d, uint e, signed short f); 我需要传递一个额外的无符号short参数,总共是7。然而,我实际上可以从现有的6中的一个推导出第7个的值 因此,我的问题是,以下哪项是更好的绩效实践: 在64位Linux上,将已计算的值作为第7个参数传递 不传递已计算的值,而是使

我从Agner Fog的优秀指南中回忆起,64位Linux可以通过寄存器传递6个整数函数参数:

(第8页)

我有以下功能:

void x(signed int a, uint b, char c, unit d, uint e, signed short f);
我需要传递一个额外的无符号short参数,总共是7。然而,我实际上可以从现有的6中的一个推导出第7个的值

因此,我的问题是,以下哪项是更好的绩效实践:

  • 在64位Linux上,将已计算的值作为第7个参数传递
  • 不传递已计算的值,而是使用现有的6个参数之一再次计算
所讨论的操作是一个简单的位移位:

unsigned short g = c & 1;
没有完全理解x86汇编程序,我不太确定寄存器有多珍贵,以及作为局部变量重新计算值是否比作为参数通过函数调用传递值更好

我认为最好计算两次该值,因为这是一个非常简单的1CPU周期任务


编辑我知道我可以简单地描述这一点,但我也想了解这两种方法在幕后发生了什么。具有第7个参数是否意味着涉及缓存/内存,而不是寄存器?

传递参数的机器约定称为(或ABI),对于Linux x86-64,在中进行了描述。另请参见wikipage

在您的情况下,可能不值得将
c&1
作为附加参数传递(因为第7个参数是在堆栈上传递的)

不要忘记,当前的处理器内核(台式机或笔记本电脑上的)经常在做而且正在做,因此
c&1
操作可以与其他操作并行进行,并且可能“不需要任何成本”

但将这些微观优化留给编译器。如果您非常关心性能,请使用带有
GCC-4.8-O3-flto
的最新GCC 4.8编译器进行编译和链接(即启用)

顺便说一句,缓存性能比这些微优化更相关。单个缓存未命中可能需要与数百条CPU机器指令相同的时间(例如250纳秒)。据传,当前的CPU大多等待缓存。您可能希望向(请参阅和)添加几个明确的(明智的)调用。但是添加太多这些预取会降低代码的速度


最后,代码的可读性和可维护性应该比原始性能更重要

Basile的回答很好,我只想指出另一件需要记住的事情:
a) 堆栈很可能位于一级缓存中,因此在堆栈上传递参数所需的额外周期不应超过~3个
b) ABI(在本例中为x86-64系统V)要求恢复被破坏的寄存器。一些由调用者保存,另一些由被调用者保存。显然,如果再次需要原始内容,调用方必须保存用于传递参数的寄存器。但是,如果函数使用的寄存器多于保存的调用者,则该函数需要计算的任何其他临时结果都必须放入被调用者保存的寄存器中。因此,函数最终会在堆栈上溢出一个寄存器,将该寄存器重新用于临时变量,然后将原始值弹出

避免访问内存的唯一方法是使用更小、更简单的函数,该函数需要更少的临时变量。

我认为这几乎不可能预测。您的函数可能是内联的,在这种情况下,这并不一定重要。此外,大量的内存访问延迟可以通过无序执行来隐藏,这使得预测非常困难。“实际上,我可以从现有的6个中得到第七个值。”我认为这是一个设计问题。在函数中重新计算变量而不是传递变量以将其保存在寄存器中的奇特名称是@alk设计问题是什么?如果您的函数需要所有七个变量,而第七个变量的计算成本很高,那么传递所有七个变量似乎是合理的,即使它们在逻辑上不是独立的。还要注意,这在例如64位SPARC或Power或其他任何类型上都很可能不同-Linux运行的每种类型的系统都可能具有显著不同的ABI。这意味着这一级别的优化通常最好由编译器来完成,除非您希望为不同的平台维护多个版本的代码(或者如果您只关心一个平台,但从长远来看,这往往是短视的…)。