siraishi発表

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
ご清聴ありがとうございました。