memcpy会消耗 CPU 资源! 消耗主要是两个方面: CPU 核心的计算开销; 内存系统的带宽和延迟开销。 memcpy 消耗CPU,最直观的就是CPU核心 必须执行一系列具体的指令来完成数据复制。 在最低层面,memcpy本质是一个循环的数据 搬运过程。
CPU的工作包括: 1.加载指令:CPU执行MOV指令,从源内存 地址读取数据到寄存器。 2.存储指令:CPU执行MOV指令,把寄存器 的数据写入目标内存地址。 3.地址计算:每次复制后,CPU要递增源地址 和目标地址指针。 4.循环控制:CPU要维护循环计数器,检查是 否完成所有字节的复制。 5.条件跳转:基于循环计数器的值,CPU决定 是继续循环还是退出。 虽然是很简单的操作,处理大量字节还是会产 生明显的CPU开销。 复制1MB数据,如果用最基本的单字节复制, CPU要执行超过100万次的加载、存储、地址 递增和循环检查指令。

现代memcpy 实现肯定不会真的逐字节复制 会采用很多种优化策略,但这些优化本身也要 CPU计算。 (1)对齐加速。 CPU访问对齐的内存地址(地址是字长的整数 倍)比访问非对齐地址要快得多。

memcpy的优化实现包含对齐处理逻辑: 1.头部对齐处理:先逐字节复制,直到目标地 址对齐到合适的边界。 2.主体块复制:然后用宽位操作复制大部分数 据。 3.尾部处理:最后处理剩余的未对齐尾部数 据。 这个逻辑要额外的分支判断和计算,但总体收 益是正的。 (2)SIMD向量化。 现代CPU支持SIMD指令,可以一次性处理更 多数据:

CPU在SIMD复制中的额外工作: 1.循环展开:为了减少循环控制开销, memcpy 展开循环,一次处理多个向量。 2.流水线调度:CPU要调度这些宽指令,确保 执行单元被充分利用。 3.数据对齐检查:就算用SIMD,还是要处理 非对齐的起始和结束部分。 4.寄存器压力管理:用多个向量寄存器要精细 的寄存器分配策略。 优化带来的差异:

向量化优化可以大幅提升吞吐量,但就算是最 优的向量化实现,CPU还是要执行相当数量的 指令。如果据量很小,函数调用开销和设置开 销就会占大头! 前面说到还只是消耗的一部分,还不是最昂贵 的那部分。现代 CPU 的性能严重依赖内存子 系统,一个由多级缓存、内存控制器和 DRAM 组成的复杂层次结构。memcpy 在这个子系统 里引发的连锁反应,会以一种更隐蔽、更具破 坏性的方式“消耗”CPU。 CPU缓存是为了弥补CPU 高速和内存低速之 间巨大鸿沟而设的缓冲。 理想情况:复制很小或刚访问过的数据时,源 数据和目标数据都在 L1 或 L2缓存。这时, CPU 核心可以全速运转,数据在寄存器和缓存 之间快速流转,延迟非常低,消耗主要表现为 纯粹的计算指令开销。 问题出现在复制超过缓存容量的大块数据。 1. CPU 从内存把一块源数据加载到缓存。

2.把这块数据写入目标地址,同样占用缓存。 3.缓存空间有限,新数据块进来时,必须把一 些旧数据块移出缓存,写回内存或直接丢 弃。 4. CPU要复制下一块数据,或程序要访问之前 被移除的数据时,发现缓存失效了,必须再 次访问慢速的主内存。 这个过程称为缓存颠簸。这时,CPU 核心的流 水线会频繁停顿,因为它必须等待数百个时钟 周期,从内存抓取数据。从系统性能计数器 看,memcpy 的指令退休率(IPC)会下降, 而 Cache Miss+E 的计数会飙升。

memcpy 占据大量缓存空间时,就会挤走其他 正在运行的、更需要缓存来提高性能的程序代 码和数据。就算 memcpy 本身执行完毕,那些 被挤走的程序也要花时间重新加载自己的工作 集,导致它们在memcpy 之后的一段时间内性 能下降。这种性能波及,是 memcpy 消耗系统 资源的另一种隐形方式。
【瓜分奖池】memcpy到底会不会消耗cpu?memcpy 是如 第5张插图
【瓜分奖池】memcpy到底会不会消耗cpu?memcpy 是如 第6张插图
【瓜分奖池】memcpy到底会不会消耗cpu?memcpy 是如 第7张插图
【瓜分奖池】memcpy到底会不会消耗cpu?memcpy 是如 第8张插图
【瓜分奖池】memcpy到底会不会消耗cpu?memcpy 是如 第9张插图