1 / 24

Hack the Cell 2009 反省会の反省

小寺春樹. Hack the Cell 2009 反省会の反省. に書いておきます。. 口頭で説明した概要を. バイナリアン風味. Z80,68k,SH2,R3000, R4300,ARM7,PowerPC. ※なにはともあれ objdump. 色々なCPUを使ってきました。 Cellはまぁ、今回位では使った内には入らないですね。. ビット転置(スライス)実装. 基本的な事はおいておいて、変わってるところ. レジスタ幅を一杯に使って演算(実は致命傷). 623循環で組まなかった言い訳. 最初期の簡略化で思考固定化. 状態空間を 2^n サイズにして、

salim
Download Presentation

Hack the Cell 2009 反省会の反省

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 小寺春樹 Hack the Cell 2009反省会の反省 に書いておきます。 口頭で説明した概要を

  2. バイナリアン風味 Z80,68k,SH2,R3000, R4300,ARM7,PowerPC ※なにはともあれ objdump 色々なCPUを使ってきました。 Cellはまぁ、今回位では使った内には入らないですね。

  3. ビット転置(スライス)実装 基本的な事はおいておいて、変わってるところ レジスタ幅を一杯に使って演算(実は致命傷) 623循環で組まなかった言い訳

  4. 最初期の簡略化で思考固定化 状態空間を 2^n サイズにして、 EN = 1023; // > N y = (mt[ idx & EN ]&UPPER_MASK) | (mt[ (idx+1)& EN ] & LOWER_MASK); y = mt[ (idx+M)& EN ] ^ (y >> 1) ^ ((y&1)?MATRIX_A:0); mt[ (idx+N)&EN ] = y; インデクス計算時の mod 624 処理、idx == N での比較分岐なりが削れる。 mt 状態空間サイズは ・624ワード以上の任意 ・コアループ内の処理数もそれに応じて適当に変動 全部アンロールするとか考えてなかった時は、2^nに 状態空間拡張するのが単純でそこそこ速い。

  5. レジスタ幅をいっぱいに使わないと? 処理単位はレジスタサイズの128bit 状態空間サイズが624(623+1)だと、端数が出る 処理単位毎の処理が均一じゃなくなる ループ当たり処理要素数は少なくとも 624/640 になる。 コードサイズがでかくなる(後述) ビットスライス実装にしても2^nの方がレジスタにはまるし、 なんとなく効率良いと思っちゃってそれっきり。

  6. 0 396 623 +1 +M 時間 状態空間更新のイメージ 赤横線が読み出しで、計算して、青に書き込む感じ。

  7. 0 396 623 +1 +M 時間 実際は矢印部分はレジスタで引き渡しますので、 メモリのロード&ストアはライン当たり32ずつで済んでます。

  8. 0 396 623 +1 +M 時間 に割り当てられるレジスタが1ライン毎に変わる -> コアループは偶数ラインで構成

  9. even/odd のバランス調整 基本的にevenが重いので、ステップ数増加を抑えつつ odd側に振れる仕事を振っていきます。

  10. 0 396 623 +1 +M 時間 +Mの値を取得するところ、2つのレジスタを結合して 回す処理のところで調整を行います。

  11. even*1,odd*2 odd*4 A B A B shufb dst,A,B,shufc1 sel dst,A,B,mask B A = B A rotqbii tmp,B,4 B B rotqbii dst,dst,4 B B A rotqbyi dst,dst,#14 rotqbii dst,dst,#4 A B shufb dst,dst,tmp,shufc2 even-1,odd+2となる代替処理の説明。 なんとなく出来る事が分かって 貰えればいいかなぁ。 A B

  12. tempering temperingも一応考えました

  13. n=[] def eor(a,b) puts "(#{a}^#{b})" "(#{a}^#{b})" end 0.upto(31){|i| n[i]="n#{i}" } 31.downto(11){|i| n[i]=eor(n[i],n[i-11]) } [0,3,4,5,7,10,12,13,17,19,21,22,24].each{|i| n[i] = eor(n[i],n[i+7]) } [0,1,2,4,5,6,7,8,9,13,14].each{|i| n[i] = eor(n[i],n[i+15]) } 31.downto(18){|i| n[i] = eor(n[i],n[i-18]) } こんなRubyスクリプトを書いて、各ビットに元ビットがどう 反映されているかを調べます。

  14. (n31^n20) (n30^n19) (n29^n18) (n28^n17) (n27^n16) (n26^n15) (n25^n14) (n24^n13) (n23^n12) (n22^n11) (n21^n10) (n20^n9) (n19^n8) (n18^n7) (n17^n6) (n16^n5) (n15^n4) (n14^n3) (n13^n2) (n12^n1) (n11^n0) (n0^n7) (n3^n10) (n4^(n11^n0)) (n5^(n12^n1)) (n7^(n14^n3)) (n10^(n17^n6)) ((n12^n1)^(n19^n8)) ((n13^n2)^(n20^n9)) ((n17^n6)^(n24^n13)) ((n19^n8)^(n26^n15)) ((n21^n10)^(n28^n17)) ((n22^n11)^(n29^n18)) ((n24^n13)^(n31^n20)) ((n0^n7)^(n15^n4)) (n1^(n16^n5)) (n2^((n17^n6)^(n24^n13))) ((n4^(n11^n0))^((n19^n8)^(n26^n15))) ((n5^(n12^n1))^(n20^n9)) (n6^((n21^n10)^(n28^n17))) ((n7^(n14^n3))^((n22^n11)^(n29^n18))) (n8^(n23^n12)) (n9^((n24^n13)^(n31^n20))) (((n13^n2)^(n20^n9))^(n28^n17)) ((n14^n3)^(n29^n18)) ((n31^n20)^(((n13^n2)^(n20^n9))^(n28^n17))) ((n30^n19)^((n12^n1)^(n19^n8))) ((n29^n18)^(n11^n0)) ((n28^n17)^(n10^(n17^n6))) ((n27^n16)^(n9^((n24^n13)^(n31^n20)))) ((n26^n15)^(n8^(n23^n12))) ((n25^n14)^((n7^(n14^n3))^((n22^n11)^(n29^n18)))) (((n24^n13)^(n31^n20))^(n6^((n21^n10)^(n28^n17)))) ((n23^n12)^((n5^(n12^n1))^(n20^n9))) (((n22^n11)^(n29^n18))^((n4^(n11^n0))^((n19^n8)^(n26^n15)))) (((n21^n10)^(n28^n17))^(n3^n10)) ((n20^n9)^(n2^((n17^n6)^(n24^n13)))) (((n19^n8)^(n26^n15))^(n1^(n16^n5))) ((n18^n7)^((n0^n7)^(n15^n4))) 出力はこんな感じ。一番左側がターゲットビット。 これをよく睨むと…

  15. (n31^n20) (n30^n19) (n29^n18) (n28^n17) (n27^n16) (n26^n15) (n25^n14) (n24^n13) (n23^n12) (n22^n11) (n21^n10) (n20^n9) (n19^n8) (n18^n7) (n17^n6) (n16^n5) (n15^n4) (n14^n3) (n13^n2) (n12^n1) (n11^n0) (n0^n7) (n3^n10) (n4^(n11^n0)) (n5^(n12^n1)) (n7^(n14^n3)) (n10^(n17^n6)) ((n12^n1)^(n19^n8)) ((n13^n2)^(n20^n9)) ((n17^n6)^(n24^n13)) ((n19^n8)^(n26^n15)) ((n21^n10)^(n28^n17)) ((n22^n11)^(n29^n18)) ((n24^n13)^(n31^n20)) ((n0^n7)^(n15^n4)) (n1^(n16^n5)) (n2^((n17^n6)^(n24^n13))) ((n4^(n11^n0))^((n19^n8)^(n26^n15))) ((n5^(n12^n1))^(n20^n9)) (n6^((n21^n10)^(n28^n17))) ((n7^(n14^n3))^((n22^n11)^(n29^n18))) (n8^(n23^n12)) (n9^((n24^n13)^(n31^n20))) (((n13^n2)^(n20^n9))^(n28^n17)) ((n14^n3)^(n29^n18)) ((n31^n20)^(((n13^n2)^(n20^n9))^(n28^n17))) ((n30^n19)^((n12^n1)^(n19^n8))) ((n29^n18)^(n11^n0)) ((n28^n17)^(n10^(n17^n6))) ((n27^n16)^(n9^((n24^n13)^(n31^n20)))) ((n26^n15)^(n8^(n23^n12))) ((n25^n14)^((n7^(n14^n3))^((n22^n11)^(n29^n18)))) (((n24^n13)^(n31^n20))^(n6^((n21^n10)^(n28^n17)))) ((n23^n12)^((n5^(n12^n1))^(n20^n9))) (((n22^n11)^(n29^n18))^((n4^(n11^n0))^((n19^n8)^(n26^n15)))) (((n21^n10)^(n28^n17))^(n3^n10)) ((n20^n9)^(n2^((n17^n6)^(n24^n13)))) (((n19^n8)^(n26^n15))^(n1^(n16^n5))) ((n18^n7)^((n0^n7)^(n15^n4))) この辺なんか無駄っぽい。(n18^n7)は最後にしか出て来ないのに、 n7は結局打ち消されてたり。

  16. (n31^n20) (n30^n19) (n29^n18) (n28^n17) (n27^n16) (n26^n15) (n25^n14) (n24^n13) (n23^n12) (n22^n11) (n21^n10) (n20^n9) (n19^n8) (n18^n7)->x (n17^n6) (n16^n5) (n15^n4) (n14^n3) (n13^n2) (n12^n1) (n11^n0) (n0^n7)->x (n3^n10) (n4^(n11^n0)) (n5^(n12^n1)) (n7^(n14^n3)) (n10^(n17^n6)) ((n12^n1)^(n19^n8)) ((n13^n2)^(n20^n9)) ((n17^n6)^(n24^n13)) ((n19^n8)^(n26^n15)) ((n21^n10)^(n28^n17)) ((n22^n11)^(n29^n18)) ((n24^n13)^(n31^n20)) ((n0^n7)^(n15^n4)) -> (n0^(n15^n4)) , ((n0^(n15^n4))^n7) (n1^(n16^n5)) (n2^((n17^n6)^(n24^n13))) ((n4^(n11^n0))^((n19^n8)^(n26^n15))) ((n5^(n12^n1))^(n20^n9)) (n6^((n21^n10)^(n28^n17))) ((n7^(n14^n3))^((n22^n11)^(n29^n18))) (n8^(n23^n12)) (n9^((n24^n13)^(n31^n20))) (((n13^n2)^(n20^n9))^(n28^n17)) ((n14^n3)^(n29^n18)) ((n31^n20)^(((n13^n2)^(n20^n9))^(n28^n17))) ((n30^n19)^((n12^n1)^(n19^n8))) ((n29^n18)^(n11^n0)) ((n28^n17)^(n10^(n17^n6))) ((n27^n16)^(n9^((n24^n13)^(n31^n20)))) ((n26^n15)^(n8^(n23^n12))) ((n25^n14)^((n7^(n14^n3))^((n22^n11)^(n29^n18)))) (((n24^n13)^(n31^n20))^(n6^((n21^n10)^(n28^n17)))) ((n23^n12)^((n5^(n12^n1))^(n20^n9))) (((n22^n11)^(n29^n18))^((n4^(n11^n0))^((n19^n8)^(n26^n15)))) (((n21^n10)^(n28^n17))^(n3^n10)) ((n20^n9)^(n2^((n17^n6)^(n24^n13)))) (((n19^n8)^(n26^n15))^(n1^(n16^n5))) ((n18^n7)^((n0^n7)^(n15^n4))) -> (n18^(n0^(n15^n4))) こう変形すると、1ステップだけ減ります。 これ以上減らないの?わかりません。

  17. コード生成(並び替え)

  18. e cntb $r14,$r14 e cntb $r30,$r30 e sumb $r14,$r30,$r14 r $r30 e cntb $r15,$r15 e cntb $r31,$r31 e sumb $r15,$r31,$r15 r $r31 o shufb $r0,$r0,$r8,shufc r $r8 e a %0,%0,$r0 r $r0 ・発行順依存関係調べます ・発行可能な中では単純に先着優先。あとはベースコード側の工夫でなんとかします。 ・r っていうのはレジスタのリリース。まぁ、自動化するまでもないかなぁ、と。

  19. レジスタの動的割り当てによる再利用 参照完了直後に再利用。 999ステップ目等はdual issue で参照完了と同時にターゲットになってたり。

  20. 仕上げ

  21. 結果加算は8本の累積レジスタで処理 0.upto(15){ |x| i = (x&1)*8+(x/2) @asm<<"e cntb $r#{i},$r#{i}" @asm<<"e cntb $r#{i+16},$r#{i+16}" @asm<<"e sumb $r#{i},$r#{i+16},$r#{i}" } 0.upto(7){|i| @asm<<"o shufb $r#{i},$r#{i},$r#{i+8},shufc" @asm<<"e a %#{i},%#{i},$r#{i}" } ※shufc = {1,17,3,19, 5,21,7,23, 9,25,11,27, 13,29,15,31} ライン当たりコスト: cntb*32, sumb*16, shufb*8, a*8 even56,odd8と、合計ステップ数64でもoddに8振れているのがポイント

  22. 例)bit0,8,16,24の集計 cntb cntb bit8 bit24 + + sumb bit0,8,16,24 累積レジスタ shufb a sumb + + cntb bit0 cntb bit16 8ビット間隔の重みのデータをcntb,sumb,shufbで組み上げる事で、 SIMDワードとしてそのまま加算出来ますね、という話なのですが これもあまり説明うまくなかったですね。 ※bit0 = MSB

  23. その他 MT状態空間の3/32をレジスタに常駐 連続メモリアクセスストールの回避 端数の処理もSIMD化している 1回限りのビット転置も高速化している カウンタをoddパイプで実装 実行後のmtは問われないから、端数の処理を先にやる様に するとビット転置は1回で済んで楽ですよね。ん、そうでもない? rotqbiiで7bitカウンタを作る話

  24. おしまい

More Related