在C ++中有没有更快的memcpy()替代品?
答案 0 :(得分:19)
首先,提出建议。假设编写标准库的人并不愚蠢。 如果有更快的方法来实现一般的memcpy,他们就已经完成了。
第二,是的,有更好的选择。
std::copy
函数。它做了同样的事情,但它更安全,2)在某些情况下可能更快。它是一个模板,意味着它可以专门用于特定类型,使其可能比一般的C memcpy更快。答案 1 :(得分:18)
不太可能。您的编译器/标准库可能会有一个非常有效和定制的memcpy实现。而memcpy基本上是将一部分内存复制到另一部分的最低api。
如果您想进一步加速,请找到一种不需要任何内存复制的方法。
答案 2 :(得分:9)
优化专家Agner Fog发布了优化的记忆功能:http://agner.org/optimize/#asmlib。它虽然在GPL之下。
前段时间,Agner表示这些功能应该取代GCC内置,因为它们的速度要快得多。 我不知道从那以后它是否已经完成。
答案 3 :(得分:7)
这个非常类似问题的答案(约memset()
)也适用于此。
它基本上说编译器会为memcpy()
/ memset()
生成一些非常优化的代码 - 根据对象的性质(大小,对齐等)生成不同的代码。
请记住,C ++中只有memcpy()
个POD。
答案 4 :(得分:3)
为了找到或编写快速内存复制例程,我们应该了解处理器的工作原理。
自Intel Pentium Pro以来的处理器执行“无序执行”。如果指令没有依赖关系,它们可以并行执行许多指令。但仅当指令仅使用寄存器操作时才会出现这种情况。如果它们与存储器一起工作,则使用额外的CPU单元,称为“加载单元”(从存储器读取数据)和“存储单元”(将数据写入存储器)。大多数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寄存器来保存数据,而不需要 - 因为我们只有两个加载单元和一个商店单元。所以只需两个寄存器即可获得最佳结使用那么多寄存器绝不会提高性能。
内存复制例程也可以使用一些“高级”技术,如“预取”,指示处理器预先将内存加载到缓存中,以及“非临时写入”(如果您正在复制非常大的内存块而不是需要立即读取输出缓冲区中的数据),对齐与未对齐写入等等。
自2013年发布的现代处理器,如果它们在CPUID中具有ERMS位,则具有所谓的“增强型rep movsb”,因此对于大型存储器复制,可以使用“rep movsb” - 副本将非常快速,甚至比使用ymm寄存器更快,它可以正常使用缓存。但是,这条指令的启动成本非常高 - 大约35个周期,所以它只能在大内存块上支付。
我希望您现在可以更轻松地选择或编写案例所需的最佳内存复制例程。
你甚至可以保留标准的memcpy / memmove,但是根据你的需要获得你自己的特殊largememcpy()。
答案 5 :(得分:1)
取决于你要做什么...如果它是一个足够大的memcpy,并且你只是稀疏地写入副本,那么使用MMAP_PRIVATE来创建写时复制映射的mmap可能会更快
答案 6 :(得分:1)
根据您的平台,可能存在特定用例,例如,如果您知道源和目标与高速缓存行对齐,并且大小是高速缓存行大小的整数倍。一般来说,大多数编译器都会为memcpy生成相当优化的代码。
答案 7 :(得分:1)
我不确定使用默认的memcpy始终是最佳选择。我看过的大多数memcpy实现都倾向于在开始时尝试对齐数据,然后执行对齐的副本。如果数据已经对齐,或者非常小,那么这就是浪费时间。
有时使用专门的文字复制,半字复制,字节复制memcpy是有益的,只要它对缓存没有太大的负面影响。
此外,您可能希望更好地控制实际分配算法。在游戏行业中,人们编写自己的内存分配例程是非常常见的,无论工具链开发人员在开发它时花费了多少精力。我见过的游戏几乎总是倾向于使用Doug Lea's Malloc。
一般来说,你会浪费时间去尝试优化memcpy,因为毫无疑问,你的应用程序中的代码会更加容易加速。