- 主题:最佳memcpy实现
x86汇编是domain knowledge。面试时用这种题去测试,只能测出一个人是否知道这些知识,无法准确衡量他解决问题的能力。这虽然满足了面试官自身的优越感,却大概率错失合适的人才,还浪费双方时间。我觉得并不值得推荐。
你说的和汇编比除了无法用SSE,这句是不对的。主流编译器通过intrinsic函数把几乎所有SIMD指令都提供给C/C++用户了,你可以自己确认一下。不要低估本版深度。
【 在 wushu (武术) 的大作中提到: 】
: 这实现已经相当好了,版上绝大部分人应该是写不出来的,不知道上面说不好的仔细看过没。跟汇编比除了没法用SSE,该做的优化都做到了。
: 1. 4字节拷贝。没按8字节优化可能是追求代码简洁。
: 2. dest的4字节对齐。
: 3. 主循环内4条指令超标量同时拷贝32字节,一般处理器也够了。
: 4. 纯C,可移植性好,而且写的简洁美观。
: ps,我面试时coding基本必问memset或memcpy,十几年目前没遇到过能考虑到超过三条的人。
--
FROM 114.84.111.*
根据实际硬件不同,也有可能这个是最佳的。
如果瓶颈在ddr ram上,比如极端情况用DDR-400搭配主频很高的cpu,那四次*s++=*d++和一次movq很可能是一样快的。movq可以空出一些流水线给超线程用。至于是否用得上那也不保证。反正单线程benchmark很可能看上去差不多。
intel的cpu对我们程序员来说是个黑盒子。厂家不会公开说它是怎么优化的。没准它的decoder认识连续四条*s++=*d++,会自动翻译成和movq一样的微码。这是完全可以做到,而且很可能已经做了的。唯一确保最佳性能的办法就是做实验测,摸清每个指令的延迟多少,对流水线的影响多大,对cache的影响多大。。。慢慢把黑盒的内部结构给逆向工程出来。(做JIT编译器的人主要就是做这些工作)
我见过有一个网站专门测试并公开这些数据的,回头收藏夹里看看,如果能找到就贴上来给你们。
【 在 hgoldfish (老鱼) 的大作中提到: 】
: 这个不可能是最佳实现。。在现代处理器上面,单字节访问非常慢。
: 你发的这种实现无非是朴素实现的简单推广:
: 1. 没考虑内存地址对齐
: 2. 至少用个戴夫设备吧。
: 3. 用 simd 指令集一次复制 32 字节才是王道啊。
: edit: 有内存地址对齐。
--
FROM 114.84.111.*
我前面写完以后删掉了一段“如果瓶颈在sram cache上,那肯定是simd快”的描述,因为我觉得写罗嗦了,删了也不影响我的观点。现在你给我补充回来了。。。
【 在 ilovecpp (cpp) 的大作中提到: 】
: 中间隔着cache呢,哪能这么比。
: 这种通用实现也不追求最优。具体平台上用movsq乃至avx512的实现都有。
--
FROM 114.84.111.*
我觉得就是你总结的:glibc兜底的平台无关memcpy差不多也长这样
然后前面wushu查了说这是musl的代码。
从编程、汇编角度来说这样就可以结贴啦。再往下挖要不就聊聊总线协议和dma呗。
【 在 ilovecpp (cpp) 的大作中提到: 】
: 中间隔着cache呢,哪能这么比。
: 这种通用实现也不追求最优。具体平台上用movsq乃至avx512的实现都有。
--
FROM 114.84.111.*
DMA是一类操作的统称,搞嵌入式编程的可能比较熟悉。
假设有一个任务:
memcpy(dst=0x1000, src=0x0, size=0x1000);
这个操作用一般memcpy的实现,就是类似楼主那种方式,cpu从头忙到尾,忙完了就copy完了。
但是,这个操作本质很简单,很多外设并不需要cpu辅助也可以自己实现。cpu只要告诉外设src和dst的地址,然后知道多少个时钟之后完成就行了。在很多硬件平台上,这种操作的实现可能是:
============================================================
dma_req dst, src, size
mov ecx, 0x200 #具体等待时间要根据实际情况算,这里假设等1024个时钟周期
_wait:
dec ecx
jnz _wait
============================================================
从上面可以看出cpu大部分时候是闲着的,编译器或者程序员可以自行利用这段空闲时间干别的工作。
-- DMA可以内存到内存吗?
要根据具体CPU、总线、外设的种类来判断,大多数情况可以内存到内存,可以外设到内存,可以内存到外设。
-- dma比cpu快吗?
不一定,但是dma设计没有浪费的话,一般情况下都可以达到总线的最大传输速度(扣除协议损耗)。常用总线协议有x86的pci-e和arm的axi,还有ddr接口的标准,感兴趣可以搜下它们的拓扑图和传输速率。我提到dma其实也就是因为这是memcpy理论上能达到的最快速度。
-- 内存到内存不影响cpu吗?
会影响cpu的cache的正确性。程序员需要根据情况打开/关闭cache。
-- 允许用户态使用dma吗?
要看操作系统有没有放开这个口子。技术上没有大问题。
这些知识在芯片ISA设计时会用到,学电子工程的人会熟悉一点。写游戏机模拟器的时候也会遇到。
【 在 ilovecpp (cpp) 的大作中提到: 】
: dma这个真不太懂
: dma可以内存到内存吗?
: dma比cpu快吗?内存到内存不影响cpu吗?
: 允许用户态使用dma吗?
: 另外glibc留了个口子,对齐到页时可以操作页表作拷贝。如果内核有这个调用,那应该是大块拷贝最快的了。
--
修改:javaboy FROM 114.84.111.*
FROM 114.84.111.*