この質問は、ここでの私の質問に続きます(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 FPopsであると予想されます。
重み係数の動きを考慮に入れると(それを指摘してくれてありがとう)、スケジュールは次のようになります。
movss
スカラーの重み値をXMMレジスタに移動し、shufps
このスカラー値をベクトル全体にコピーするために使用する操作の後に追加の命令がありますが、スケジュールは変更されていないようです。mulps
負荷から浮動小数点ドメインへの切り替え待ち時間を考慮に入れると、重みベクトルをしばらくの間使用する準備ができているようです。したがって、これによって余分な待ち時間が発生することはありません。
movaps
(移動を詰め、整列)、 addps
&mulps
これはどちらかの余分な遅延を招くべきではありませんので(アセンブリコードで確認)このカーネルで使用されている命令は、そのスカラーバージョンと同じレイテンシー&スループットを持っています。
このカーネルが取得できる最大パフォーマンスがサイクルあたり6.4FP 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サイクルを追加するのですか?」ということだと思います。それはタフな1 ...だ