C++ 中是否有比 memcpy() 更快的替代方法?

有帮助吗?

解决方案

不太可能。您的编译器/标准库可能会有一个非常有效和量身定制的memcpy实现。而memcpy基本上是将一部分内存复制到另一部分的最低api。

如果您想进一步加速,请找到一种不需要任何内存复制的方法。

其他提示

首先,提一句建议。假设编写标准库的人并不愚蠢。如果有更快的方法来实现通用 memcpy,他们就会这么做。

其次,是的,还有更好的选择。

  • 在 C++ 中,使用 std::copy 功能。它做同样的事情,但它 1) 更安全,2) 在某些情况下可能更快。它是一个模板,这意味着它可以专门用于特定类型,使其可能比一般的 C memcpy 更快。
  • 或者,您可以利用您的高级知识 你的 具体情况。memcpy 的实现者必须编写它,以便它在以下环境中表现良好 每一个 案件。如果您有关于需要的情况的具体信息,您也许能够编写更快的版本。例如,您需要复制多少内存?它是如何对齐的?这可能会让你编写一个更有效的 memcpy 具体案例。但在大多数其他情况下它不会那么好(如果它能起作用的话)

优化专家Agner Fog发布了优化的记忆功能: http://agner.org/optimize/#asmlib 。它虽然在GPL之下。

前段时间,Agner表示这些功能应该取代GCC内置,因为它们的速度要快得多。 我不知道从那以后它是否已经完成。

这个答案针对一个非常相似的问题(关于 memset()) 也适用于此处。

它基本上说编译器生成了一些非常优化的代码 memcpy()/memset() - 根据对象的性质(大小、对齐方式等)而使用不同的代码。

请记住,仅 memcpy() C++ 中的 POD。

为了找到或编写快速内存复制例程,我们应该了解处理器的工作原理。

自英特尔奔腾Pro以来的处理器执行“无序执行”。如果指令没有依赖关系,它们可以并行执行许多指令。但仅当指令仅使用寄存器操作时才会出现这种情况。如果它们与内存一起运行,则使用额外的CPU单元,称为“负载单元”和#8220; (从内存中读取数据)和“存储单元” (将数据写入内存)。大多数CPU具有两个加载单元和一个存储单元,即它们可以并行执行从存储器读取的两个指令和一个写入存储器的指令(同样,如果它们不相互影响)。这些单位的大小通常与最大寄存器大小相同–如果CPU有XMM寄存器(SSE)–它是16个字节,如果它有YMM寄存器(AVX)–它是32个字节,依此类推。所有读取或写入存储器的指令都被转换为微操作(微操作),这些微操作进入公共微操作池并等待加载和存储单元能够为它们提供服务。单个加载或存储单元一次只能为一个微操作服务,无论加载或存储所需的数据大小,无论是1字节还是32字节。

因此,最快的内存复制将移入和移出具有最大大小的寄存器。对于支持AVX的处理器,复制内存的最快方法是重复以下序列,循环展开:

vmovdqa     ymm0,ymmword ptr [rcx]
vmovdqa     ymm1,ymmword ptr [rcx+20h]
vmovdqa     ymmword ptr [rdx],ymm0
vmovdqa     ymmword ptr [rdx+20h],ymm1

之前由hplbsh发布的Google代码并不是很好,因为它们在开始写回数据之前使用所有8个xmm寄存器来保存数据,而不需要这些数据–因为我们只有两个装载单元和一个存储单元。所以只需两个寄存器即可获得最佳结使用那么多寄存器绝不会提高性能。

存储器复制例程也可以使用一些“高级”例程。像“ prefetch”指示处理器预先将存储器加载到高速缓存中并且“非临时写入“ (如果你要复制非常大的内存块,并且不需要立即读取输出缓冲区中的数据),对齐与未对齐写入等等。

自2013年发布的现代处理器,如果它们在CPUID中具有ERMS位,则具有所谓的增强型rep movsb”,因此对于大型存储器复制,“ rep movsb&#8221 ;可能会被使用–副本将非常快,甚至比使用ymm寄存器更快,并且它可以正常使用缓存。但是,这条指令的启动成本非常高–大约35个周期,所以它只在大内存块上支付。

我希望您现在可以更轻松地选择或编写案例所需的最佳内存复制例程。

你甚至可以保留标准的memcpy / memmove,但是根据你的需要获得你自己的特殊largememcpy()。

取决于你要做什么...如果它是一个足够大的memcpy,并且你只是稀疏地写入副本,那么使用MMAP_PRIVATE来创建写时复制映射的mmap可能会更快

根据您的平台,可能存在特定用例,例如,如果您知道源和目标与高速缓存行对齐并且大小是高速缓存行大小的整数倍。一般来说,大多数编译器都会为memcpy生成相当优化的代码。

我不确定使用默认的memcpy始终是最佳选择。我看过的大多数memcpy实现都倾向于在开始时尝试对齐数据,然后执行对齐的副本。如果数据已经对齐,或者非常小,那么这就是浪费时间。

有时使用专门的文字复制,半字复制,字节复制memcpy是有益的,只要它对缓存没有太大的负面影响。

此外,您可能希望更好地控制实际分配算法。在游戏行业中,人们编写自己的内存分配例程是非常常见的,无论工具链开发人员在开发它时花费了多少精力。我见过的游戏几乎总是倾向于使用 Doug Lea的Malloc

一般来说,你会浪费时间去尝试优化memcpy,因为毫无疑问,你的应用程序中的代码会更加容易加速。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top