6月
28
Golden Cove(Alder Lake の P コア)で、同じ scale のロードを連続で 3 回?繰り返すと、3 回目がものすごく遅くなっているように見える、という観測をしました。Gracemont(Alder Lake の E コア)ではそうはなっていないようです。
UtVideo のハフマンデコードのアセンブラルーチンには以下のような部分が存在します。
movzx eax, byte ptr [rbx + %c[offsetof_cslen] + r11*2] add cl, byte ptr [rbx + %c[offsetof_cslen] + r11*2 + 1] .if %c[sizeof_combined_t] == 4 mov r11d, dword ptr [rbx + %c[offsetof_sym] + r11*4] .elseif %c[sizeof_combined_t] == 8 mov r11, qword ptr [rbx + %c[offsetof_sym] + r11*8] .else .err .endif
で、圧縮比が低いクリップのために、combined_t
を uint16_t
にしたらどうなるか、というのを試すために、以下のようにしました。
movzx eax, byte ptr [rbx + %c[offsetof_cslen] + r11*2] add cl, byte ptr [rbx + %c[offsetof_cslen] + r11*2 + 1] .if %c[sizeof_combined_t] == 2 movzx r11d, word ptr [rbx + %c[offsetof_sym] + r11*2] ; <- これ(uint16_t 用)を増やした .elseif %c[sizeof_combined_t] == 4 mov r11d, dword ptr [rbx + %c[offsetof_sym] + r11*4] .elseif %c[sizeof_combined_t] == 8 mov r11, qword ptr [rbx + %c[offsetof_sym] + r11*8] .else .err .endif
圧縮比が非常に低い場合、uint16_t
が一番早いはずですが、予想に反して猛烈に遅くなってしまいました。
で、シンボル部分のロード方法をいろいろと変えてみたところ、以下のようになりました。
movzx r11d, word ptr [rbx + %c[offsetof_sym] + r11*2] ; 遅い mov r11w, word ptr [rbx + %c[offsetof_sym] + r11*2] ; 遅い mov r11d, dword ptr [rbx + %c[offsetof_sym] + r11*2] ; 遅い movzx r11d, word ptr [rbx + %c[offsetof_sym] + r11*4] ; 遅くない(デコード結果は正しくないが速度は変わらないはず)
なんで!?と思いつつ、そこは元に戻しつつ HUFFMAN_DECODE_TABLE
の中の cslen
のサイズが4バイトになるように変更してみました。
struct { uint8_t symlen; uint8_t codelen; uint16_t reserved; // <- 追加 } cslen[1 << LOOKUP_BITS];
movzx eax, byte ptr [rbx + %c[offsetof_cslen] + r11*4] add cl, byte ptr [rbx + %c[offsetof_cslen] + r11*4 + 1]
そしたら uint16_t
は遅くならず、代わりに uint32_t
の方が猛烈に遅くなりました。同様に8バイトになるように変更したら、uint64_t
のが遅くなりました。
じゃあってんで symlen
や codelen
がバイト配列になる(scale が 1 になる)ように変更したところ、uint16_t
uint32_t
uint64_t
のいずれも遅くなりませんでした。
uint8_t symlen[1 << LOOKUP_BITS]; uint8_t codelen[1 << LOOKUP_BITS];
というわけで「同じ scale で3回連続してロードすると猛烈に遅い」という風に見えるわけですが、最適化マニュアルを見てもそんなことは書いてないわけで、全く謎です。
なお、遅くならないケースであっても、uint16_t
を使うのは有意点がなかったので、ボツになりました。
no comment untill now