在函数定义中使用引用参数:performance

Using reference arguments in function definition: perfomance?

本文关键字:引用 参数 performance 函数 定义      更新时间:2023-10-16

是否知道两种变体中哪一种工作速度更快,或者它们相同,或者比较不正确。

Vector test(Vector &vec)
{
 // return modified vector, or write directly to vec,
 // or do not return anything, but access vec anyway
}
Vector test(Vector vec)
{
 // same (but no reference)
}

我之所以问,是因为我可能知道,为Direct3D游戏创建最佳优化代码。

UPDATE:我说的是来自xnamath.h(d3d-sdk)的XMVECTOR——16字节,4个浮点。

这不是一种有用的概括方法。

在谷歌上搜索XMVECTOR,我得到

typedef __m128 XMVECTOR;

因此,尽管是16个字节,但它都是一个SSE机器寄存器,所以您当然应该按值传递这个吸盘。引用寄存器中的某个内容只会有将其强行放入堆栈的风险。

EDIT:即使您没有使用上面的typedef,XMVECTOR仍然可能是一种特殊类型,编译器会对其进行不同的处理。请注意有关XBox平台的注意事项。在任何情况下,我下面所说的都是双倍的:

<小时>

将微观优化视为惯用方法是错误的。微观优化从机器代码开始。这里的起点应该是探查器指向的任何机器指令,因为任何程序中都有太多的微小部分,你不会仅仅凭直觉就能找到慢的部分。

如果你刚刚开始你的第一个优化项目,你应该研究不同的评测工具(告诉你程序的哪个部分很慢),并熟悉其中一个。一旦你深入到足够的程度,当你无法通过调整源代码所说的来提高速度时,你就必须开始分析机器指令。这需要熟悉CPU及其指令集的细节。只有这样,您才能有效地开始调整源代码中关于如何做小事的细微差异。

如果你对CPU如何执行指令不太了解,就不要急于优化这类事情。考虑到程序的算法和整体结构都很重要,这完全是浪费时间。

编辑:有关16字节长的Vector的详细信息,请参阅底部

如果向量有几个以上的元素(或者元素本身相当大),那么第一个很可能会快得多。

然而,正如他们所说,"细节是魔鬼"。在某些特定情况下,第二种情况可能确实更快。这将是一个例外,而不是规则,但这仍然是一种可能性。

在第二种情况下,向量正在被复制[除非编译器能够内联代码,并且编译器能够意识到正在发生的事情,并删除额外的副本]。如果向量有10000个元素,那就是向量中任何元素的10000个副本。

在第一种情况下,从调用函数传递给调用方函数的所有内容都是一个指针。另一方面,由于它是一个引用,因此生成的代码必须再进行一次内存引用才能读取内容。因此,如果向量很小,并且test函数对vec变量进行了多次访问,那么间接操作的额外开销可能比内容的副本"更糟"。

如果有疑问,请对这两种解决方案进行基准测试。

确保基准是有代表性的-你可以把10k个元素的速度提高100倍,然后当元素数量少于20时,速度降低2倍-平均值为11…

编辑:由于问题已经更新,我不得不补充一点,"由于Vector对象很小",因此两个选项之间的显著差异可能性要小得多。在32位系统上,pass-by-reference选项可能仍然有一点好处[但是,正如我在上文中所说,它与更复杂的Vector内容访问相平衡]。在64位系统上,传递两个寄存器值可能比传递一个引用更快。

再次,在"正常"类型负载下进行基准测试。

通过引用传递的向量参数会更快,如果向量中有许多元素,则会更快。这样,您就可以避免在本地复制上花费的时间。

您应该始终通过引用传递对象,除非您需要传递地址,例如,如果您也想允许空指针。按值传递对象意味着:

  1. 正在复制
  2. 对象切片

这两者你都不想发生。

过早的优化是万恶之源

这主要是过早的优化。这也是一个微观优化。因此,它需要更多关于Vector类型和所需用法、编译器以及许多其他因素的知识。

这两者并不相等;后者将不接受右值,并允许函数更改向量。您应该使用const&使它们真正相似。

你说这是一款D3D应用程序;在这种情况下(除了预计算),您真的希望在GPU上进行向量和矩阵计算。简单的探查器对此没有帮助,您需要同时探查CPU和GPU代码。

正如@Potatoswatter所注意到的,这是一种CPU将比通过引用传递时优化得更多的类型。