nos*_*nos 19
不太可能.您的编译器/标准库可能会有一个非常有效和定制的memcpy实现.memcpy基本上是将一部分内存复制到另一部分的最低api.
如果你想进一步加速,找到一种不需要任何内存复制的方法.
jal*_*alf 19
首先,提出建议.假设编写标准库的人并不愚蠢.如果有更快的方法来实现一般的memcpy,他们就已经做到了.
第二,是的,有更好的选择.
std::copy函数.它做了同样的事情,但它更安全,2)在某些情况下可能更快.它是一个模板,意味着它可以专门用于特定类型,使其可能比一般的C memcpy更快.对于一个非常类似的问题(约memset())的答案也适用于这里.
它基本上说编译器为memcpy()/ memset()和不同的代码生成一些非常优化的代码,具体取决于对象的性质(大小,对齐等).
请记住,只有memcpy()C++中的POD.
为了找到或编写一个快速的内存复制例程,我们应该了解处理器是如何工作的。
自 Intel Pentium Pro 以来的处理器执行“乱序执行”。如果指令没有依赖性,它们可能会并行执行许多指令。但这只是当指令仅使用寄存器操作时的情况。如果它们与内存一起运行,则会使用额外的 CPU 单元,称为“加载单元”(从内存读取数据)和“存储单元”(将数据写入内存)。大多数 CPU 有两个加载单元和一个存储单元,即它们可以并行执行两条从内存读取的指令和一条写入内存的指令(同样,如果它们不相互影响)。这些单元的大小通常与最大寄存器大小相同——如果 CPU 有 XMM 寄存器(SSE)——它是 16 字节,如果它有 YMM 寄存器(AVX)——它是 32 字节,依此类推。所有读取或写入内存的指令都被转换为微操作(微操作),这些微操作进入微操作的公共池并在那里等待加载和存储单元能够为它们提供服务。一个加载或存储单元一次只能服务一个微操作,而不管它需要加载或存储的数据大小是 1 字节还是 32 字节。
因此,最快的内存复制将移入和移出最大大小的寄存器。对于支持 AVX 的处理器(但没有 AVX-512),复制内存的最快方法是重复以下序列,循环展开:
vmovdqa ymm0,ymmword ptr [rcx]
vmovdqa ymm1,ymmword ptr [rcx+20h]
vmovdqa ymmword ptr [rdx],ymm0
vmovdqa ymmword ptr [rdx+20h],ymm1
Run Code Online (Sandbox Code Playgroud)
之前hplbsh贴出的谷歌代码不是很好,因为他们在开始写回之前使用了所有8个xmm寄存器来保存数据,而它是不需要的——因为我们只有两个加载单元和一个存储单元。所以只有两个寄存器才能给出最好的结果。使用这么多寄存器并不能提高性能。
内存复制例程还可以使用一些“高级”技术,例如“预取”来指示处理器提前将内存加载到缓存中和“非临时写入”(如果您正在复制非常大的内存块并且不需要数据从输出缓冲区立即读取),对齐与未对齐的写入等。
自 2013 年以来发布的现代处理器,如果它们在 CPUID 中有 ERMS 位,则具有所谓的“增强型 rep movsb”,因此对于大内存复制,可能会使用“rep movsb”——复制会非常快,即使比使用 ymm 寄存器更快,并且可以正确使用缓存。然而,这条指令的启动成本非常高——大约 35 个周期,所以它只在大内存块上付出代价(但是,这可能会在未来的处理器中改变)。见关于“对相对性能的解释” /sf/answers/3069166061/也看到/sf/answers/3068629511/对“代表MOVSB”的更多信息。
我希望您现在可以更轻松地选择或编写您的案例所需的最佳内存复制例程。
您甚至可以保留标准的 memcpy/memmove,但可以根据需要获得自己的特殊 largememcpy()。
| 归档时间: |
|
| 查看次数: |
10849 次 |
| 最近记录: |