【发布时间】:2012-04-17 22:22:27
【问题描述】:
这个问题在我的问题上继续(根据 Mystical 的建议):
继续我的问题,当我使用压缩指令而不是标量指令时,使用内在函数的代码看起来非常相似:
for(int i=0; i<size; i+=16) {
y1 = _mm_load_ps(output[i]);
…
y4 = _mm_load_ps(output[i+12]);
for(k=0; k<ksize; k++){
for(l=0; l<ksize; l++){
w = _mm_set_ps1(weight[i+k+l]);
x1 = _mm_load_ps(input[i+k+l]);
y1 = _mm_add_ps(y1,_mm_mul_ps(w,x1));
…
x4 = _mm_load_ps(input[i+k+l+12]);
y4 = _mm_add_ps(y4,_mm_mul_ps(w,x4));
}
}
_mm_store_ps(&output[i],y1);
…
_mm_store_ps(&output[i+12],y4);
}
该内核的测量性能约为每个周期 5.6 次 FP 操作,尽管我希望它恰好是标量版本性能的 4 倍,即每个周期 4.1,6=6,4 FP 操作。
考虑到权重因素的移动(感谢您指出),时间表如下:
看起来时间表没有改变,尽管在movss 操作之后有一条额外的指令将标量权重值移动到 XMM 寄存器,然后使用shufps 将此标量值复制到整个向量中.考虑到从负载到浮点域的切换延迟,权重向量似乎已准备好及时用于mulps,因此这不会产生任何额外的延迟。
此内核中使用的movaps(对齐、打包移动)、addps 和mulps 指令(通过汇编代码检查)具有与其标量版本相同的延迟和吞吐量,因此不应该这样做也会产生任何额外的延迟。
假设这个内核可以获得的最大性能是每个周期 6.4 FP ops 并且它以每个周期 5.6 FP ops 运行,是否有人知道每 8 个周期的额外周期花费在哪里?
顺便说一下,这里是实际组装的样子:
…
Block x:
movapsx (%rax,%rcx,4), %xmm0
movapsx 0x10(%rax,%rcx,4), %xmm1
movapsx 0x20(%rax,%rcx,4), %xmm2
movapsx 0x30(%rax,%rcx,4), %xmm3
movssl (%rdx,%rcx,4), %xmm4
inc %rcx
shufps $0x0, %xmm4, %xmm4 {fill weight vector}
cmp $0x32, %rcx
mulps %xmm4, %xmm0
mulps %xmm4, %xmm1
mulps %xmm4, %xmm2
mulps %xmm3, %xmm4
addps %xmm0, %xmm5
addps %xmm1, %xmm6
addps %xmm2, %xmm7
addps %xmm4, %xmm8
jl 0x401ad6 <Block x>
…
【问题讨论】:
-
所以我想现在的问题是:“为什么
shufps指令每 1.6 次迭代增加 1 个周期?”这是一个艰难的... -
我希望它没有开销,因为
shufps的输出应该可以直接用于multps操作,因为它都是 FP 域 -
很容易找到。确保权重向量不包含任何非规范化的值。尝试不使用 shuffle 指令的循环。它不会产生任何有用的结果,但也许您发现哪条指令确实花费了您额外的周期(当然,我怀疑是洗牌)。
-
@Mystical:我看到每个循环迭代增加了 0.75 个周期。 (难道不是我对使用 5 个周期而不是 4 个周期的评论导致您在那里找到答案... :-))
-
一方面,现在您需要 4 倍的缓存带宽。数据量有多大?它们适合 L1 缓存吗?
标签: c performance intel instructions assembly