比memcpy更快的内存拷贝技术叫什么?
摘要:本文来自博客园,作者:T-BARBARIANS,博文严禁转载,转载必究! 前言 朋友们有想过居然还有比memcpy更快的内存拷贝吗? 讲道理,在这之前我没想到过,我也一直觉得memcpy就是最快的内存拷贝方法了。 也不知道老板最近是咋了,天
本文来自博客园,作者:T-BARBARIANS,博文严禁转载,转载必究!
前言
朋友们有想过居然还有比memcpy更快的内存拷贝吗?
讲道理,在这之前我没想到过,我也一直觉得memcpy就是最快的内存拷贝方法了。
也不知道老板最近是咋了,天天开会都强调:“我们最近的目标就一个字,性能优化!”
一顿操作猛如虎,也没提高5%。感觉自己实在是黔驴技穷,江郎才尽,想到又要被老板骂立马滚蛋,心里就很不是滋味。
所谓车到山前必有路,船到桥头自然直。嘿,有一天我刚好注意到我们的业务代码里有大量的memcpy,正一筹莫展之时,突然灵光一现,脑海里闪过一个想法:memcpy还可以优化吗?
我想说,正是这个想法又让我可以在老板面前暂时苟且偷生一段时间,实在是不得不佩服自己!
一、SIMD技术简介
这一小节介绍的内容跟小节标题很契合,就是介绍一下SIMD(Single Instruction Multiple Data,单指令多数据)。啥意思呢,就是一条指令并发处理多条数据。形象一点讲就是老板在桌上放了很多钱让你拿,有同学喜欢一张一张的拿,还说我喜欢这种慢慢富有的感觉;SIMD就是,老子一把拿,我踏马喜欢暴富!没错,它就是可以提升memcpy性能的关键核心技术。引用大佬画的一张图:
图1
Scalar Operation就是指的SISD(Single Instruction Single Data,单指令单数据),这种方式完成上图所有C[i]的计算需要串行执行八次,因为每个时间点,CPU的一条指令只能执行一份数据。
SIMD,就是一次运算就可以得到上述SISD的多次运算结果,即一条指令可以并发执行多份数据,因此SIMD也称为向量化计算。
到底是什么奇技淫巧使得SIMD具有并发执行多份数据的能力呢?
其实就是CPU增加了专门用于向量化计算的向量寄存器,这些寄存器跟普通的寄存器不太一样,它们的位宽都比较大,比如有128bit,256bit,甚至512bit,也就是说这些寄存器可以分别一次存储16byte,32byte,64byte的数据。比如上图的加法运算,SISD一条指令只能完成一次两个8byte数据的加法运算。但是SIMD,一条指令就可以完成a[0:7] + b[0:7] = c[0:7],两组数据的加法运算。
CPU除了增加向量寄存器,还为向量寄存器配套了专门的指令集,比如Intel的MMX,SSE(MMX的升级版),AVX(SSE的升级版)指令集。CPU运算时,识别到指令集命令,就会采用指令集对应的SIMD计算方法完成并发运算。Intel指令集查询链接:http://kntan.top/#!=undefined
二、memcpy_fast方法
带着memcpy是否还可以继续优化的疑问,一通搜索,真找到了采用SIMD技术的memcpy方法:memcpy_fast,链接:https://github.com/skywind3000/FastMemcpy
分析了一下源码实现。
(1)SSE指令集实现的fast拷贝
1、使用_mm_loadu_si128指令,从src + 0的位置取走128bit,即16字节,然后依次类推,src + 1,...,直至src + 7,一共取走16byte * 8=128byte,取出的内容分别储存到向量寄存器c0,c1,...,c7;
2、使用_mm_prefetch实现数据预取,提前把数据从内存加载到cache,保证CPU对数据的快速读取;
3、使用_mm_store_si128指令,将c0,c1,...,c7寄存器的内容分别存储至目的地址dst+ 0,dst + 1,...,dst + 7的八个位置。
利用指令集、向量寄存器、数据预取技术实现了每次16byte的并发,128byte的批次拷贝。
图2
(2)AVX指令集实现的fast拷贝
与SSE指令集实现内存拷贝逻辑一致。
1、由AVX指令集的_mm256_loadu_si256,实现每次256byte的数据加载;
2、由AVX指令集的_mm256_storeu_si256,实现每次256byte数据的存储。
可以预料,当然是寄存器位宽越大,性能会越好,也就是从理论上说使用AVX指令集会比SSE指令集更快。
图3
三、memcpy VS memcpy_fast
我们一起来看看memcpy与使用了SIMD技术的memcpy_fast的性能对比吧。
