Hack The Cell 2009 を振り返って 白石 匡央 2009/3/28 スコア ▼最終提出版の結果 ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: sum=3c927c56, sum=3c927c56, sum=2e987a4d, sum=2e987a4d, sum=ef1b6aef, sum=ef1b6aef, sum=eedd2516, sum=eedd2516, sum=f7e967a8, sum=f7e967a8, sum=1f37a7db, sum=1f37a7db, sum=c7d41f36, sum=c7d41f36, sum=aa9d2e9f, sum=aa9d2e9f, sum=8abd398a, sum=8abd398a, sum=a374bd58, sum=a374bd58, cf. 小寺さん 294950998 ticks 2448310 ticks 425483257 ticks 3531709 ticks 313079651 ticks 2598780 ticks 290962965 ticks 2415205 ticks 14411793 ticks 119837 ticks 214886708 ticks 1783769 ticks 295887479 ticks 2456073 ticks 260377511 ticks 2161355 ticks 251629392 ticks 2088731 ticks 6129418 ticks 51100 ticks ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: ORIGNAL: MINE: sum=3c927c56, sum=3c927c56, sum=2e987a4d, sum=2e987a4d, sum=ef1b6aef, sum=ef1b6aef, sum=eedd2516, sum=eedd2516, sum=f7e967a8, sum=f7e967a8, sum=1f37a7db, sum=1f37a7db, sum=c7d41f36, sum=c7d41f36, sum=aa9d2e9f, sum=aa9d2e9f, sum=8abd398a, sum=8abd398a, sum=a374bd58, sum=a374bd58, 294032966 ticks 2435961 ticks 424158954 ticks 3513919 ticks 312105208 ticks 2585719 ticks 290057342 ticks 2403032 ticks 14366933 ticks 119478 ticks 214217873 ticks 1774866 ticks 294966530 ticks 2443734 ticks 259567100 ticks 2150455 ticks 250846200 ticks 2078200 ticks 6110333 ticks 51035 ticks ※ http://longlong.way-nifty.com/blog/2009/03/post-7872.html より転載 Copyright © 2009 Masao Shiraishi bitslice ▼ mt転置 レジスタ r0 r1 r2 r3 mt[1] mt[0] mt[2] mt[127] ・・・ ・・・ r31 shuffle + gb + shift の組み合わせで生成。割と重い処理。 ▼ mt[624] の配置 mt[]インデックス: 1 128 129 256 128bit×32 128bit×32 mt[0]はバッファに乗せない : 別のワーク変数 257 384 385 512 513 623 128bit×32 128bit×32 128bit×32 余り分は0 Copyright © 2009 Masao Shiraishi mt[]更新 ▼ mt更新 1 128 129 256 257 384 385 512 513 623 128bit×32 128bit×32 128bit×32 128bit×32 128bit×32 ブロック単位で更新 624 751 752 更新式 : mt[kk+624] 879 880 1007 1008 1135 1136 1246 = f(mt[kk],mt[kk+1]) mt[kk+1]を軸に見ると計算量が減る (mt[kk]は1bitしか関わらないので) mt[kk+624] = f(mt[kk+1]) とみなす。 ※ mt[kk+M] は別途 Copyright © 2009 Masao Shiraishi (y>>1)^mag01[y&0x1UL]までの計算 ▼ y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); a00 = spu_sel( a00, prev, 0x1 ); a00 = spu_rlqwbyte( a00, 15 ); a00 = spu_rlqw( a00, 7 ); 0 最上位ビット: prev 128 1 a00 ▼ (y >> 1) ^ mag01[y & 0x1UL]; a02 a03 a06 a11 a15 a17 a18 a23 a24 a26 a27 a28 a29 a30 = = = = = = = = = = = = = = spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( spu_xor( a02, a03, a06, a11, a15, a17, a18, a23, a24, a26, a27, a28, a29, a30, a31 a31 a31 a31 a31 a31 a31 a31 a31 a31 a31 a31 a31 a31 ); ); ); ); ); ); ); ); ); ); ); ); ); ); mag01[2]={0x0UL, 0x9908b0df}; 「a31,a00,・・・,a30」の組に 結果が入る Copyright © 2009 Masao Shiraishi mt[]更新とtempering計算 ▼ mt更新とtempering計算のパイプライン ループ 128 1 mt更新: 129 0-31 256 32-63 128 1 tempering: 257 0-31 :レジスタ・セットA 32レジスタ :レジスタ・セットB 32レジスタ 384 64-95 129 256 32-63 mt更新 385 512 513 95-127 257 384 623 624 128-159 385 64-95 : odd命令が多い tempering : even命令が多い 0-31 512 513 95-127 751 623 128-159 互いに依存関係がなければ ペアリングしやすい ◎ ループの終端で“0-31” のレジスタセットが異なる → ループ内を10セット分(上図の倍)にアンロール (※ 時間切れで実装できず。セットBからセットAへの代入コストを払っている。) Copyright © 2009 Masao Shiraishi mt[kk+M]の算出 128 129 1 256 257 384 385 512 513 623 mt: ブロックをまたがる mt[kk+M]: 397 ・ 2つのブロックに対する selb + rot で求める。 ・ 理想的には,32個のレジスタを2セット使ってメモリロードを減らしたい。 → レジスタが足りない ・ レジスタ8個(8ビット分)×5セット を うまく回すことで対処 31 一つ前のブロック: 次のブロック(ロード): A 24 23 16 15 8 7 0 A B C D + + + + E A B C B C D y と xor → 空き y と xor → 空き y と xor → 空き E y と xor → 空き 次の計算へ A B 次へ 次へ mt[513]~mt[623] では 特異処理となる。 => 最適化が不十分で遅い・・・ C 次へ Copyright © 2009 Masao Shiraishi tempering ▼ tempering計算 y ^= (y >> 11) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 y ^= (y << 7) & 0x9d2c5680UL 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 7 10 11 12 14 17 19 20 24 26 28 29 31 1 0 0 1 1 1 0 1 0 0 1 0 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0 0 0 0 0 0 y ^= (y << 15) & 0xefc60000UL 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 15 16 17 19 20 21 22 23 24 28 29 1 1 1 0 1 1 1 1 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 y ^= (y >> 18) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 Copyright © 2009 Masao Shiraishi 合計値 ▼ tempering計算値の合計 各ビットごとに集計 s0 s1 s2 s3 r0 r1 r2 r3 ・・・ ・・・ ・・・ r31 s31 spu_cntb が使える さらに,ブロックごとにs0~s31を集計 total0 total1 total2 total3 += += += += s0 s1 s2 s3 total0 ~ totoal15(上位ビット)は short で集計 total16 ~ totoal31(下位ビット)は int で集計 → 6レジスタ使用 ・・・ total31 += s31 最終結果は,最後に各ビットをシフトしながら合計する SUMコスト: cntb×32,sumb×20,shuffle×12,a×6 (even=58,odd=12) Copyright © 2009 Masao Shiraishi アセンブラ関数 128個のレジスタを全て使うためにオールアセンブラの関数を記述 ▼ エントリポイント ラベル + extern で記述 extern RESULT_SUM sum_rand_asm( UINTV loop_cnt, UINTV preve ); __asm__ ( "sum_rand_asm:\n\t" ▼ prologue レジスタ $80~$127 を退避 "stqd "stqd "stqd ・・・ "stqd $80,-16($sp)\n\t" $81,-32($sp)\n\t" $82,-48($sp)\n\t“ $127,-768($sp)\n\t" Copyright © 2009 Masao Shiraishi アセンブラ関数 ▼ 引数 $3 から(引数の数だけ)順番に格納される。 $0 = $lr 戻りアドレス $1 = $sp スタックポインタ $2 環境ポインタ(フレームポインタ?) ▼ 戻り値 $3 に入れる。構造体の場合は,メンバの数だけ$3から順番に格納する。 ▼ epilogue 退避したレジスタ $80~$127 を戻して,戻りアドレスへジャンプ "hbr FUNCTION_END,$lr\n\t" "lqd $80,-16($sp)\n\t" "lqd $81,-32($sp)\n\t“ ・・・ "lqd $127,-768($sp)\n\t" "FUNCTION_END:\n\t" "bi $lr\n\t" Copyright © 2009 Masao Shiraishi End ご清聴ありがとうございました。
© Copyright 2024 ExpyDoc