最近チューニングでgather intrinsicを使ってみている。
vgather命令は、配列のbaseアドレスを渡し、更にindexが入ったベクトルレジスタを渡し、
ベクトルレジスタ長分のメモリ上のデータを一個一個indexを見ながら一気に取得する命令。
これは凄い便利!!!と使ってみたのだが、あまり性能が出ない。
分岐のmiss predictionは増えるし、ロード命令数もなんか凄い増えるなと、不思議に思ってた。
そんなわけで、最近ずっと悩んでたんだけど、やっと分かった気がする。
この「一気」というのが間違いだった。
正確には、一命令で一度に取得できるのは1ベクトルロードで取得できる範囲内だけで、
離れたメモリ位置上のデータ全てを取得するには、vgather命令を複数回実行する必要があった。
内部でマイクロコードでループしてるのかなって思ってたら、実はコンパイラが1つのintrinsicを、
アセンブラレベルでループにしてぶんまわしてた。そりゃmiss prediction増えますわwww
例えばAVX512だと、32ビットのデータを扱う場合、ベクトル長は16。
なので、indexには16個の添字が入ったベクトルレジスタを渡すのだけど、
その値がバラバラだと、最悪16回ループを回ることになる。これはあかん……。
明日はgatherを使わずに取得するコード(ループアンロールされる)と、
asmを使ってvgatherを手でアンロールして16回vgatherするコードにして、
比べてみよ。
そして比べた結果、遅くなってたので、泣く泣く諦めましたw
コンパイラちゃんのintrinsicのほうが速かった。
もうちょっといいコードが作れそうなのだけど、今回は無理でした。
0 件のコメント:
コメントを投稿