c++ - 什么时候 sizeof(myPOD) 太大而无法在 x64 上按值传递?

标签 c++ c x86 64-bit x86-64

我预计对于最大 8 字节的结构没有什么不同,但是更大的 POD 类型呢?当类型的大小超过机器字大小时,按值传递是否会变得更昂贵,或者是否有其他因素(如缓存行大小)会影响性能?

我主要对 x64 感兴趣,但也可以随意包含一些 x86 的数字。

说明:

  • 我可能想得太狭隘了,因为我不知道在其中发挥作用的所有因素(寄存器、调用约定、编译器优化)。我主要对 Microsoft 的 C++ 编译器感兴趣,它只使用 __fastcall。
  • 我感兴趣的是,在了解架构、类型大小、缓存大小等参数传递方面,是否有任何一般性建议。例如:“当类型小于 N 字节时,最好按值传递类型。 “其中 N 是可以从我们已知的事物中推导出来的事物。

最佳答案

您混淆了两个不同的问题。您可以按值传递任何对象(只要它是可复制的)。

它是通过寄存器还是在堆栈中传递取决于实现,特别是所使用的调用约定。

在某些调用约定下,大于 8 个字节(通用寄存器大小)的参数将在堆栈上传递。在其他调用约定下,它们可能简单地分布在多个寄存器中。

在某些情况下,有可能对象从不在寄存器中传递,无论它们的大小如何。

类似地,SIMD 值 (SSE/AVX) 可能在某些调用约定中通过寄存器传递,但在其他调用约定中将始终放在堆栈中。标量浮点值可能也是如此。

但是您所问的问题并不能真正得到有意义的回答。复制对象的速度受对象大小的影响,是的。如果对象是 POD 类型,并且适合寄存器,则可以使用简单的 mov 指令复制它。编译器是否会这取决于编译器。

很明显,对象越大,它占用的缓存空间就越多,这意味着你会得到更多的缓存未命中。

但这一切都非常模糊,几乎毫无用处。我们不知道您的对象长什么样,也不知道您的代码用它做什么。如果您有特定的类型,请编写基准以查看编译器如何处理它。

回应您的修改

I'm interested if there is any kind of general recommendation when it comes to parameter passing knowing the architecture, type size, cache size, etc. Something like: "Prefer passing the type by value when it's smaller than N bytes.

首先,相信你的编译器。在许多情况下,它会积极优化拷贝,因此即使您确实按值传递大对象,也不太可能成为可衡量的问题。

其次,您看到的是微优化,无论哪种方式都不太可能产生显着差异。对于小对象,按值传递避免了指针间接寻址,因此它可能稍微快一些。在某些时候,这会被复制的成本所淹没(假设对象复制,见上文)。对于非常大的对象(为了论证,假设 500 字节或以上,大到对象 通常 达不到),你绝对应该通过引用传递.

但是对于 8、16、24、40 字节的对象呢?谁知道?谁在乎?它不太可能在实际代码中产生可衡量的差异。

这引出了两条经验法则:

  1. 做看起来很自然的事情:如果传递拷贝使您的代码更简单或更清晰,那就去做吧。
  2. 如果性能很重要,那么 (1) 确保您正在查看的内容实际上对您的性能有任何明显的影响。测量它。如果它影响性能,那么它可以被测量。如果无法衡量,那么根据定义,性能差异就不会引人注意。

所以,简而言之:

  • 对于原始类型,按值传递。
  • 对于非常大的类型,通过引用传递。
  • 对于其他所有事情,不要担心,把时间花在有成效的事情上。

关于c++ - 什么时候 sizeof(myPOD) 太大而无法在 x64 上按值传递?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9394674/

相关文章:

if-statement - 如果程序文件(x86)批量不存在,如何将路径=设置为程序文件?

c - _malloc 在汇编中到底做了什么?

embedded - BIOS ROM 如何映射到 PC 上的地址空间?

c++ - 可以通过重复函数调用来初始化 const std::array 吗?

c++ - 一旦执行完成就杀死子进程(在fork之后)

在Windows和Linux下将UTF-16转换为UTF-8,在C中

c - 在套接字库中调用 recv 时,我的 recv 缓冲区应该有多大

C 在字符串中搜索单词

c++ - 我的印象是下面的脚注 32 适用于整个段落 §3.4.1/8 而不仅仅是它的第三个要点

c++ - 我需要转换无符号字符吗?