FastMemcpy
FastMemcpy copied to clipboard
一些小小的问题
和现在的 MCFCRT 比较了一下,因为 MCFCRT 不打算支持 AVX 就只测试了 SSE 的(实际上是懒得改,其实比较简单,目前的复制操作都是两个连续 movups 打包的,这地方改改就能支持 AVX):

https://github.com/lhmouse/MCF/blob/master/MCFCRT/src/stdc/string/_memcpy_impl.h#L292
gcc (gcc-7-branch HEAD with MCF thread model, built by LH_Mouse.) 7.3.1 20180125
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
处理器是 Intel Xeon E3 1230v3 ,Haswell 架构。
你这个测试我看了下,有几个小问题:
- #1 里面提过的。这个二次函数调用的开销对 32 字节的复制测试的影响比较大,大概有十几个毫秒。
- 只有 32 64 512 等尺寸的复制,没有带余数的。
-
timeGetTime()太不精确了(误差经常在十几个毫秒),建议用QuertPerformanceCounter(), 还不用链接winmm。
实现的问题也有一些:
- 全部用
static函数涉嫌利用编译器对 internal linkage 的函数的 aggressive optimization 造假。(逃) -
memcpy_fast()最后的memcpy_tiny()实际上没有必要:因为上面if (size <= 128) {条件不成立的缘故,直接用_mm_storeu_si128()处理最后的 xmmword 就行。 - prefetching 实测意义不大。
- 不建议用整数的 sse 指令。它要求 SSE2,指令长度更大所以 cache locality 不好。相比之下,
_mm_{loadu,load,storeu,store,stream}_ps()仅要求 SSE 支持,并且指令长度更小。(由于 Core2 上存在延迟问题, GCC 会将movups优化为movlps和movhps的拼合。然而这是后话,Haswell 上已经没有这延迟问题了。)
呵呵,现在这些 crt 也进步不小啊,
- memcpy_tiny 最终应是按照 inline 进 memcpy_fast 中的,你可以试试 -O3 选项,如果 -O2 的话,很多地方没法优化。
- timeGetTime 只是测试个大概,QFP 写起来代码更长,懒得写了,因为本身循环数较多,误差也是毫秒级别的。
- static 问题,你可以改做函数指针,实测还是比 memcpy 快。
- 针对你说的最后一次 memcpy_tiny 可以避免的问题,这是避免不了的,因为中间块拷贝部分,步常是128字节,也就是说最多可能剩下 127 个字节来,你的 _mm_storeu_si128() 一次只能拷贝16个字节,你要展开写,它也还是一次 memcpy_tiny。
- prefetching 根据机器不同,至少一半机器上的确有效果的。
- movups 问题,有空可以试试。
- 至于尺寸,我另外一个版本的代码里测试过不对齐的尺寸,测试结果类似,篇幅问题,我把那些测试删除了,有兴趣你可以加上去。
-
-O3比-O2慢。 - 你不是封装成函数了么,应该不差太多。返回的时间建议用
double不建议用unsigned。 - 不评论。
- 不会把指针退一个字节变成不对齐的再复制? 567 同 3。
QFP长也是醉了.c.jpg 还有都Haswell了还纠结这点指令长度嘛……?
QFP长也是醉了.c.jpg 还有都Haswell了还纠结这点指令长度嘛……?
不过,实际测下来的速度 movupd > movups = lddqu ,虽然 movupd 是 SSE2 而且比 movups 好多一个 operand size override prefix 。