我正在寻找一个结果的解释,我在循环中看到每次迭代64次移动,从一些源内存位置移动到某个目标内存位置,使用x86 movdqu指令(movdqu指令支持从/移动16byte数据)到xmm寄存器到/从未对齐的存储器位置寄存器)。这是实现类似于memcpy()/ java.lang.System.arraycopy()
的函数的代码的一部分我尝试使用以下两种不同的模式实现副本:
0x30013f74: prefetchnta BYTE PTR [rsi]
0x30013f77: prefetchnta BYTE PTR [rdi]
0x30013f7a: movdqu xmm3, XMMWORD PTR [rsi+0x30]
0x30013f7f: movdqu xmm2, XMMWORD PTR [rsi+0x20]
0x30013f84: movdqu XMMWORD PTR [rdi+0x30],xmm3
0x30013f89: movdqu XMMWORD PTR [rdi+0x20],xmm2
0x30013f8e: movdqu xmm1, XMMWORD PTR [rsi+0x10]
0x30013f93: movdqu xmm0, XMMWORD PTR [rsi]
0x30013f97: movdqu XMMWORD PTR [rdi+0x10], xmm1
0x30013f9c: movdqu XMMWORD PTR [rdi], xmm0
在此模式中,rsi保存源(src)地址,rdi保存目标(dst)地址,xmm寄存器用作临时寄存器。此代码的迭代次数与copylen_in_bytes / 64相同。如您所见,此处遵循ld-ld-st-st-ld-ld-st-st加载存储模式。
0x30013f74: prefetchnta BYTE PTR [rsi]
0x30013f77: prefetchnta BYTE PTR [rdi]
0x30013f7a: movdqu xmm3, XMMWORD PTR [rsi+0x30]
0x30013f7f: movdqu XMMWORD PTR [rdi+0x30], xmm3
0x30013f84: movdqu xmm2, XMMWORD PTR [rsi+0x20]
0x30013f89: movdqu XMMWORD PTR [rdi+0x20], xmm2
0x30013f8e: movdqu xmm1, XMMWORD PTR [rsi+0x10]
0x30013f93: movdqu XMMWORD PTR [rdi+0x10], xmm1
0x30013f98: movdqu xmm0, XMMWORD PTR [rsi]
0x30013f9c: movdqu XMMWORD PTR [rdi], xmm0
在pattern2中,遵循ld-st-ld-st-ld-st-ld-st模式。
运行此代码几百次,其中src和dst在不同的8字节边界对齐,我观察到以下内容:
Pattern1表现出非常高的运行间差异。
Pattern2几乎没有变化。
Pattern2上的最小时间(最快观察时间)比Pattern1上的最小时间更高(约8%)。
Pattern1表现出非常高的运行间差异。
Pattern2几乎没有变化。
Pattern2上的最小时间比Pattern1上的最小时间高(~20%)。
Pattern1不会表现出非常高的逐次运行差异。
Pattern2几乎没有变化。
Pattern2上的最小时间比Pattern1上的最小时间高(~20%)。
奇怪的是,在Westmere和Ivybridge上,src / dest的对齐与坏结果之间似乎没有相关性(导致高方差)。我看到相同的src / dest对齐的好坏数字。
据我所知,跨越高速缓存行的movdqu将比非高速缓存行跨越的movdqu表现更差,但我不明白以下内容:
1)为什么Pattern1在Westmere和Ivybridge上表现出很高的差异?装货商的订单如何产生差异?
2)为什么在不同的架构上,Pattern2上的最小时间比Pattern1慢?
感谢您花时间阅读这篇长篇文章。
Karthik