我终于明白了这一点(并且死在 Sente 的答案是正确的,谢谢)
在下面,dst 和 src 是 512 MByte std::vector。我正在使用 Intel 10.1.029 编译器和 CRT。
在 64 位上
memcpy(&dst[0],&src[0],dst.size())
和
memcpy(&dst[0],&src[0],N)
其中 N 是先前声明的const size_t N=512*(1<<20);
调用
__intel_fast_memcpy
其中大部分包括:
000000014004ED80 lea rcx,[rcx+40h]
000000014004ED84 lea rdx,[rdx+40h]
000000014004ED88 lea r8,[r8-40h]
000000014004ED8C prefetchnta [rdx+180h]
000000014004ED93 movdqu xmm0,xmmword ptr [rdx-40h]
000000014004ED98 movdqu xmm1,xmmword ptr [rdx-30h]
000000014004ED9D cmp r8,40h
000000014004EDA1 movntdq xmmword ptr [rcx-40h],xmm0
000000014004EDA6 movntdq xmmword ptr [rcx-30h],xmm1
000000014004EDAB movdqu xmm2,xmmword ptr [rdx-20h]
000000014004EDB0 movdqu xmm3,xmmword ptr [rdx-10h]
000000014004EDB5 movntdq xmmword ptr [rcx-20h],xmm2
000000014004EDBA movntdq xmmword ptr [rcx-10h],xmm3
000000014004EDBF jge 000000014004ED80
并以 ~2200 MByte/s 的速度运行。
但是在 32 位
memcpy(&dst[0],&src[0],dst.size())
来电
__intel_fast_memcpy
其中大部分包括
004447A0 sub ecx,80h
004447A6 movdqa xmm0,xmmword ptr [esi]
004447AA movdqa xmm1,xmmword ptr [esi+10h]
004447AF movdqa xmmword ptr [edx],xmm0
004447B3 movdqa xmmword ptr [edx+10h],xmm1
004447B8 movdqa xmm2,xmmword ptr [esi+20h]
004447BD movdqa xmm3,xmmword ptr [esi+30h]
004447C2 movdqa xmmword ptr [edx+20h],xmm2
004447C7 movdqa xmmword ptr [edx+30h],xmm3
004447CC movdqa xmm4,xmmword ptr [esi+40h]
004447D1 movdqa xmm5,xmmword ptr [esi+50h]
004447D6 movdqa xmmword ptr [edx+40h],xmm4
004447DB movdqa xmmword ptr [edx+50h],xmm5
004447E0 movdqa xmm6,xmmword ptr [esi+60h]
004447E5 movdqa xmm7,xmmword ptr [esi+70h]
004447EA add esi,80h
004447F0 movdqa xmmword ptr [edx+60h],xmm6
004447F5 movdqa xmmword ptr [edx+70h],xmm7
004447FA add edx,80h
00444800 cmp ecx,80h
00444806 jge 004447A0
并且仅以 ~1350 MByte/s 的速度运行。
然而
memcpy(&dst[0],&src[0],N)
其中 N 先前声明const size_t N=512*(1<<20);
编译(在 32 位上)直接调用
__intel_VEC_memcpy
其中大部分包括
0043FF40 movdqa xmm0,xmmword ptr [esi]
0043FF44 movdqa xmm1,xmmword ptr [esi+10h]
0043FF49 movdqa xmm2,xmmword ptr [esi+20h]
0043FF4E movdqa xmm3,xmmword ptr [esi+30h]
0043FF53 movntdq xmmword ptr [edi],xmm0
0043FF57 movntdq xmmword ptr [edi+10h],xmm1
0043FF5C movntdq xmmword ptr [edi+20h],xmm2
0043FF61 movntdq xmmword ptr [edi+30h],xmm3
0043FF66 movdqa xmm4,xmmword ptr [esi+40h]
0043FF6B movdqa xmm5,xmmword ptr [esi+50h]
0043FF70 movdqa xmm6,xmmword ptr [esi+60h]
0043FF75 movdqa xmm7,xmmword ptr [esi+70h]
0043FF7A movntdq xmmword ptr [edi+40h],xmm4
0043FF7F movntdq xmmword ptr [edi+50h],xmm5
0043FF84 movntdq xmmword ptr [edi+60h],xmm6
0043FF89 movntdq xmmword ptr [edi+70h],xmm7
0043FF8E lea esi,[esi+80h]
0043FF94 lea edi,[edi+80h]
0043FF9A dec ecx
0043FF9B jne ___intel_VEC_memcpy+244h (43FF40h)
并以 ~2100MByte/s 的速度运行(证明 32 位不受带宽限制)。
我撤回了我自己的类似 memcpy 的 SSE 代码在 32 位构建中遭受类似的 ~1300 MByte/限制的说法;我现在在 32 位或 64 位上获得 >2GByte/s 没有任何问题;诀窍(如上述结果提示)是使用非临时(“流式”)存储(例如_mm_stream_ps
内在)。
dst.size()
32 位“ ”memcpy 最终不会调用更快的“ ”版本似乎有点奇怪movnt
(如果您进入 memcpy,则会有最令人难以置信的CPUID
检查和启发式逻辑,例如将要复制的字节数与缓存大小等进行比较在它接近您的实际数据之前),但至少我现在了解观察到的行为(而且它与 SysWow64 或硬件无关)。