我试图在L1缓存中获得全部带宽,以便在Intel处理器上实现以下功能
float triad(float *x, float *y, float *z, const int n) {
float k = 3.14159f;
for(int i=0; i<n; i++) {
z[i] = x[i] + k*y[i];
}
}
Run Code Online (Sandbox Code Playgroud)
这是STREAM的三合一功能.
使用具有此功能的SandyBridge/IvyBridge处理器可获得约95%的峰值(使用NASM组装).但是,除非我展开循环,否则使用Haswell I仅达到峰值的62%.如果我展开16次,我得到92%.我不明白这一点.
我决定使用NASM在汇编中编写我的函数.装配中的主循环看起来像这样.
.L2:
vmovaps ymm1, [rdi+rax]
vfmadd231ps ymm1, ymm2, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
Run Code Online (Sandbox Code Playgroud)
在示例12.7-12.11 中的Agner Fog的优化组装手册中,他y[i] = y[i] +k*x[i]对Pentium M,Core 2,Sandy Bridge,FMA4和FMA3 做了几乎相同的事情(但是).我设法或多或少地自己重现了他的代码(实际上他在广播时在FMA3示例中有一个小错误).除FMA4和FMA3外,他为每个处理器的表格提供指令大小计数,融合操作,执行端口.我曾试图为FMA3制作这张桌子.
ports
size ?ops-fused 0 1 2 3 4 5 6 7
vmovaps 5 1 ½ ½ …Run Code Online (Sandbox Code Playgroud) 我使用英特尔®架构代码分析器(IACA)发现了一些意想不到的东西(对我而言).
以下指令使用[base+index]寻址
addps xmm1, xmmword ptr [rsi+rax*1]
Run Code Online (Sandbox Code Playgroud)
根据IACA没有微熔丝.但是,如果我用[base+offset]这样的
addps xmm1, xmmword ptr [rsi]
Run Code Online (Sandbox Code Playgroud)
IACA报告它确实融合了.
英特尔优化参考手册的第2-11节给出了以下"可以由所有解码器处理的微融合微操作"的示例
FADD DOUBLE PTR [RDI + RSI*8]
Run Code Online (Sandbox Code Playgroud)
和Agner Fog的优化装配手册也给出了使用[base+index]寻址的微操作融合的例子.例如,请参见第12.2节"Core2上的相同示例".那么正确的答案是什么?