Rob*_*bon 18 c python performance sse
我正在考虑更改一些目前需要16字节对齐数组的代码高性能代码,并用于_mm_load_ps放宽对齐约束和使用_mm_loadu_ps.关于SSE指令的内存对齐的性能影响有很多神话,所以我做了一个小的测试用例,它应该是一个内存带宽限制的循环.使用对齐或未对齐的加载内在函数,它通过大型数组运行100次迭代,使用SSE内在函数对元素求和.源代码在这里.https://gist.github.com/rmcgibbo/7689820
带有Sandy Bridge Core i5的64位Macbook Pro的结果如下.数字越小表示性能越快.当我阅读结果时,我发现在未对齐的内存上使用_mm_loadu_ps基本上没有性能损失.
我觉得这很令人惊讶.这是一个公平的测试/合理的结论吗?在哪些硬件平台上有区别?
$ gcc -O3 -msse aligned_vs_unaligned_load.c && ./a.out 200000000
Array Size: 762.939 MB
Trial 1
_mm_load_ps with aligned memory: 0.175311
_mm_loadu_ps with aligned memory: 0.169709
_mm_loadu_ps with unaligned memory: 0.169904
Trial 2
_mm_load_ps with aligned memory: 0.169025
_mm_loadu_ps with aligned memory: 0.191656
_mm_loadu_ps with unaligned memory: 0.177688
Trial 3
_mm_load_ps with aligned memory: 0.182507
_mm_loadu_ps with aligned memory: 0.175914
_mm_loadu_ps with unaligned memory: 0.173419
Trial 4
_mm_load_ps with aligned memory: 0.181997
_mm_loadu_ps with aligned memory: 0.172688
_mm_loadu_ps with unaligned memory: 0.179133
Trial 5
_mm_load_ps with aligned memory: 0.180817
_mm_loadu_ps with aligned memory: 0.172168
_mm_loadu_ps with unaligned memory: 0.181852
Run Code Online (Sandbox Code Playgroud)
cre*_*hen 17
你的结果中有很多噪音.我在运行Debian 7的Xeon E3-1230 V2 @ 3.30GHz上重新运行它,在200000000阵列上进行12次运行(丢弃第一次计算虚拟内存噪声),i在基准函数内进行10次迭代,显式noinline为您提供的功能,以及三个基准测试中的每个基准测试:https: //gist.github.com/creichen/7690369
这与gcc 4.7.2.
在noinline确保第一基准未进行优化的.
确切的电话是
./a.out 200000000 10 12 $n
Run Code Online (Sandbox Code Playgroud)
为$n从0到2.
结果如下:
load_ps对齐
min: 0.040655
median: 0.040656
max: 0.040658
Run Code Online (Sandbox Code Playgroud)
loadu_ps对齐
min: 0.040653
median: 0.040655
max: 0.040657
Run Code Online (Sandbox Code Playgroud)
loadu_ps未对齐
min: 0.042349
median: 0.042351
max: 0.042352
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,这些是一些非常严格的界限,表明loadu_ps在未对齐访问时速度较慢(减速约5%)但在对齐访问时没有.显然,在特定的机器上,loadu_ps对对齐的内存访问不会有任何损失.
查看程序集,load_ps和loadu_ps版本之间的唯一区别是后者包含一条movups指令,重新排序其他一些指令以进行补偿,并使用稍微不同的寄存器名称.后者可能完全不相关,前者可以在微代码转换期间得到优化.
现在,很难说(不是英特尔工程师可以访问更详细的信息)是否/如何movups优化指令,但考虑到CPU芯片只需使用对齐数据路径,如果低位加载地址为零,否则为未对齐的数据路径,这对我来说似乎是合理的.
我在我的Core i7笔记本电脑上尝试了同样的效果,得到了非常相似的结果
总而言之,我会说是的,你确实为未对齐的内存访问支付了一个惩罚,但它足够小,它可以被其他效果淹没.在您报告的运行中,似乎有足够的噪音来允许假设它对您来说也较慢(请注意,您应该忽略第一次运行,因为您的第一次试用将为预热页表和缓存付出代价.)
这里有两个问题:给定相同的对齐地址,未对齐的负载是否比对齐的负载慢?并且具有未对齐地址的加载比具有对齐地址的加载慢吗?
与具有新地址的对齐加载相比,较旧的Intel CPU(在这种情况下"较旧"仅在几年前)对于使用具有对齐地址的未对齐加载指令确实具有轻微的性能损失.较新的CPU往往没有这个问题.
较旧和较新的Intel CPU都会因未加载地址的加载而受到性能损失,特别是在超过缓存行时.
由于细节因处理器型号而异,因此您需要单独检查每个型号以获取详细信息.
有时性能问题可能会被掩盖.用于测量的简单指令序列可能无法揭示未对齐加载指令使得加载 - 存储单元比对齐加载指令更加繁忙,因此如果在前一种情况下尝试某些附加操作但不会导致性能下降在后者.
请参阅英特尔® 64 位和 IA-32 架构优化参考手册中的“§2.4.5.1 Efficient Handling of Alignment Hazards” :
缓存和内存子系统处理每个工作负载中很大比例的指令。不同的地址对齐方案会对内存和缓存操作产生不同的性能影响。例如,L1 的 1 周期吞吐量(参见表 2-25)通常适用于来自 L1 缓存的自然对齐加载。但是使用未对齐的加载指令(例如 MOVUPS、MOVUPD、MOVDQU 等)访问来自 L1 的数据将经历不同数量的延迟,具体取决于特定的微架构和对齐场景。
这里的表格我复制不了,基本显示对齐和未对齐的L1负载为1个周期;拆分缓存线边界为 ~4.5 个周期。
小智 5
这取决于架构,最近几代人已经显着改进了.另一方面,在较旧的Core2架构上:
$ gcc -O3 -fno-inline foo2.c -o a; ./a 1000000
Array Size: 3.815 MB
Trial 1
_mm_load_ps with aligned memory: 0.003983
_mm_loadu_ps with aligned memory: 0.003889
_mm_loadu_ps with unaligned memory: 0.008085
Trial 2
_mm_load_ps with aligned memory: 0.002553
_mm_loadu_ps with aligned memory: 0.002567
_mm_loadu_ps with unaligned memory: 0.006444
Trial 3
_mm_load_ps with aligned memory: 0.002557
_mm_loadu_ps with aligned memory: 0.002552
_mm_loadu_ps with unaligned memory: 0.006430
Trial 4
_mm_load_ps with aligned memory: 0.002563
_mm_loadu_ps with aligned memory: 0.002568
_mm_loadu_ps with unaligned memory: 0.006436
Trial 5
_mm_load_ps with aligned memory: 0.002543
_mm_loadu_ps with aligned memory: 0.002565
_mm_loadu_ps with unaligned memory: 0.006400
Run Code Online (Sandbox Code Playgroud)