見出し画像

アンローリング|行列積高速化#13

この記事は、以下の記事を分割したものです。
[元の記事]行列積計算を高速化してみる
一括で読みたい場合は、元の記事をご覧ください。

この記事では、私が昔考えた高速化手順を辿っていますが、今回のアンローリングがとても重要なステップだと再認識しました。ここで間違えると、この先の高速化に行き詰まってしまいます。

実際、最初に書いた記事では、この先のステップで行き詰まってしまい、アンローリングからやり直しました。そこで、以前の記事は削除し、やり直したアンローリング方法について書き直します。

注意しなければいけない点は、下記の通りでした。

アンローリングの注意点
1. アンロール後のループに対してシーケンシャルアクセスできなければならない
2. ベクトル処理のために、アンロールループはKループが外側でなければならない
3. 行列積カーネル関数とコピー関数でアンロール段数が同じでなければならない

13-1. アンロール段数の設定

AVX拡張命令セットでは、倍精度浮動小数が4つ保有できる(=ベクトル長が4の)YMMレジスタが使用できます。そのため、アンロール段数(=ループ展開する幅)は4の倍数にしておくと、この先の高速化でアセンブラ化した際に、アルゴリズムを容易に組むことが可能になります。

しかし、x86_64アーキテクチャでは、YMMレジスタは16本までと制限があるため、アンロール段数はあまり大きな値にもできません。大まかに、ymm0~ymm3を行列Aに、ymm4~ymm7を行列Bに、ymm12~ymm15を行列Cに割り当てるとすると、行列A,B,Cはいずれも4要素×4レジスタ=16要素ずつであれば、レジスタの本数内で計算できそうです。行列AはM×K行列、行列BはK×N行列、行列CはM×N行列なので、M×N×Kのループは4×4×4でアンロールして、これを一塊とします。

今回は、K方向にもう一塊作ることにして、4×4×8でアンロールすることにしました。塊を2つにするのは、レジスタに若干の余裕(ymm8~ymm11が未使用)なため、2つの塊を混ぜることで、パイプラインハザードを起こりにくくできるかもしれないからです。

アンロール段数の決め方
1、ベクトル長(=4)の倍数で考える
2、使用可能なレジスタに、計算に必要な行列を割り当てる
3、割り当てた要素数から、各辺(M N,K)の最小アンロール段数を決める
4、レジスタの余裕があれば、アンロール段数を少し多めにしておく

具体的な実装方法については、有料にさせていただきます。

次の記事


ここから先は

19,667字

¥ 100

この記事が気に入ったらサポートをしてみませんか?