アトミックDMAコマンド(LL/SC)を使った同期処理を行う
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
前述のMFCアトミック更新コマンド(DMA LL/SCコマンド)を用いた複数SPEの同期処理を行います。 例としてはいささか簡単すぎるのですが、ここではある整数値を5つのSPEを使って同時にカウントアップし、PPEで最終的な整数値を表示させます。 初期値0からSPE 5個で1000回ずつカウントアップすると合計は5000になるはずですが、適切に同期処理を行なわないとうまくいきません。
ではやってみましょう。
単なるDMA転送を使った場合
DMA LL/SCコマンドを使う前に普通のDMAを使って実装しました。
SPEではvalue値を+1するために下記の手順でread-modefy-write操作を行います。
spu_mfcdma32 (&value,
value_ea,
sizeof(value),
0,
MFC_GET_CMD);
spu_writech(MFC_WrTagMask, 1<<0);
spu_mfcstat(MFC_TAG_UPDATE_ALL);
value += 1;
spu_mfcdma32 (&value,
value_ea,
sizeof(value),
0,
MFC_PUT_CMD);
spu_writech(MFC_WrTagMask, 1<<0);
spu_mfcstat(MFC_TAG_UPDATE_ALL);
ごく普通のDMA転送を行っていることに注意してください。
このプログラムを実行しすると下記の結果が得られました。
$ ./ppe.out Sarah: setup 5 spe threads spe: start spe: start Sarah: waiting all spe threads end... spe: start spe: start spe: start spe: end, count up = 1000 spe: end, count up = 1000 spe: end, count up = 1000 spe: end, count up = 1000 spe: end, count up = 1000 Sarah: close image Sarah: delete all spe threads value = 4068
このようにvalueは期待される値の5000ではなく4068が得られました(結果は毎回異なります)。 これはSPEで行ったvalue値の一連のread-modefy-write操作が排他的に行われておらず SPE間で競合したためと考えられます。
MFCアトミック更新コマンドを使った場合
次にSPE間で同期をとりながらカウントアップする正しい手順を提示します。MFCアトミック更新コマンド(DMA LL/SCコマンド)を使います。
SPEではvalue値の+1するのに下記の手順でread-modefy-write操作を行います。
do
{
spu_mfcdma32 (&value,
value_ea,
sizeof(value),
0,
MFC_GETLLAR_CMD); // (1)
if (!spu_readch (MFC_RdAtomicStat)) // (2)
break;
value += 1;
spu_mfcdma32 (&value,
value_ea,
sizeof(value),
0,
MFC_PUTLLC_CMD); // (3)
} while (spu_readch (MFC_RdAtomicStat)); // (4)
手順は下記の通りです。
- リザベーションつきでロード
- ステータスをチェックし成功したことを確認
- 条件つきストア
- ステータスをチェックし成功したら抜け、失敗したら再度(1)からやり直す
(1)でリザベーション付のロードを行い、(1)から(3)の間に他のSPEからvalue値に対する書き込みがあると自分が参照していたリザベーションを失い、(3)のPUTLLCコマンドが失敗します。これはvalue値に対する競合的な更新があったと考えられ、自分が参照しているvalue値は古く無効とすべきです。従って再度始めからやり直さなければなりません。一般的にLL/SCを使った操作はリトライを伴います。
実行結果を示します。
$ ./ppe.out Sarah: setup 5 spe threads spe: start spe: start spe: end, count up = 1000 spe: end, count up = 1000 Sarah: waiting all spe threads end... spe: start spe: start spe: start spe: end, count up = 1000 spe: end, count up = 1000 spe: end, count up = 1000 Sarah: close image Sarah: delete all spe threads value = 5000
このように今度は期待した値のvalue = 5000が得られました。

