优化内存 在C++中有更快的备选备忘录()吗?p>
对于一个非常类似的问题(关于优化内存 在C++中有更快的备选备忘录()吗?p>,c++,optimization,memcpy,C++,Optimization,Memcpy,对于一个非常类似的问题(关于memset())的回答也适用于这里 它基本上是说编译器为memcpy()/memset()-生成一些非常优化的代码,并根据对象的性质(大小、对齐方式等)生成不同的代码 >记住,只有代码> MycPy.()/Cudio> C++中的POD. 不可能。您的编译器/标准库可能会有一个非常高效和定制的memcpy实现。memcpy基本上是用于将内存的一部分复制到另一部分的最低api 如果您想要进一步的加速,请找到一种不需要任何内存复制的方法。这取决于您尝试执行的操作
memset()
)的回答也适用于这里
memcpy()
/memset()
-生成一些非常优化的代码,并根据对象的性质(大小、对齐方式等)生成不同的代码
<> >记住,只有<>代码> MycPy.()/Cudio> C++中的POD.
不可能。您的编译器/标准库可能会有一个非常高效和定制的memcpy实现。memcpy基本上是用于将内存的一部分复制到另一部分的最低api
如果您想要进一步的加速,请找到一种不需要任何内存复制的方法。这取决于您尝试执行的操作。。。如果它是一个足够大的memcpy,并且您只对副本进行少量写入,那么使用mmap_PRIVATE创建写时拷贝映射的mmap可能会更快。根据您的平台,可能会有特定的用例,例如,如果您知道源和目标与缓存线对齐,并且大小是缓存线大小的整数倍。一般来说,大多数编译器都会为memcpy生成相当优化的代码 首先,一句忠告。假设编写标准库的人并不愚蠢。 如果有一种更快的方法来实现通用memcpy,他们早就做到了 第二,是的,有更好的选择
- 或者,你可以利用你对具体情况的卓越知识。memcpy的实现者必须编写它,这样它在任何情况下都能很好地执行。如果您有关于需要它的情况的特定信息,您可能可以编写一个更快的版本。例如,您需要复制多少内存?它是如何对齐的?这可能会让您为这种特定情况编写更高效的memcpy。但在大多数其他情况下,它都不会那么好(如果它能奏效的话)
不过,一般来说,优化memcpy是在浪费时间,因为毫无疑问,在应用程序中会有许多更容易加速的代码。优化专家Agner Fog发布了优化内存函数:。不过这是GPL下的 不久前,Agner说这些函数应该取代GCC内置函数,因为它们速度更快。
我不知道从那以后是否已经做过了。为了找到或编写一个快速内存复制例程,我们应该了解处理器是如何工作的 英特尔奔腾Pro之后的处理器执行“无序执行”。如果指令没有依赖关系,它们可能并行执行许多指令。但是,只有当指令仅与寄存器一起运行时,才会出现这种情况。如果它们使用内存运行,则会使用额外的CPU单元,称为“加载单元”(从内存读取数据)和“存储单元”(将数据写入内存)。大多数CPU有两个加载单元和一个存储单元,即它们可以并行执行两条从内存读取的指令和一条写入内存的指令(同样,如果它们彼此不影响的话)。这些单元的大小通常与最大寄存器大小相同——如果CPU有XMM寄存器(SSE)——它是16字节,如果它有YMM寄存器(AVX)——它是32字节,依此类推。所有读取或写入内存的指令都被转换为微操作(micro ops),这些微操作进入到micro ops的公共池,并在那里等待加载和存储单元能够为它们提供服务。一个加载或存储单元一次只能为一个微操作服务,而不管它需要加载或存储的数据大小是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
hplbsh之前发布的Google代码不是很好,因为他们在开始写回数据之前使用了所有8个xmm寄存器来保存数据,而这并不需要——因为我们只有两个加载单元和一个存储单元。因此,只有两个寄存器才能给出最佳结果。使用这么多寄存器并不能提高性能
内存复制例程还可以使用一些“高级”技术,如“预取”来指示处理器提前将内存加载到缓存中,以及“非时态写入”(如果要复制非常大的内存块,并且不需要立即读取输出缓冲区中的数据)、对齐写入与未对齐写入等
自2013年发布的现代处理器,如果在CPUID中有ERMS位,则具有所谓的“增强的rep movsb”,因此对于大内存拷贝,可以使用“rep movsb”–拷贝速度非常快,甚至比ymm寄存器更快,并且可以与缓存正常工作。然而,这条指令的启动成本非常高——大约35个周期,所以它只在大内存上支付