DMA転送のパフォーマンスを測る 2 アライメントの問題
出典: PS3 Linux Information Site / Cell/B.E.のパワーを体験しよう
DMA転送を行なうにはアドレスとサイズに制限がありました。少なくとも16バイトアライメントが必要で、ベストパフォーマンスを得るためには128バイトアライメントにする必要がある、というのがこれまで見てきました。 ここではより深くDMA転送とアドレスアライメントの問題をパフォーマンスを実際に計測しながら見ていきます。
Media:dma-perform-align.tar.gz
目次 |
実験
DMAの転送サイズを4*1024バイトに固定してアライメントを変えながら、DMA転送にかかった時間を計測しました。試したアライメントは下記の4種類です。
- ppe-128, spe-128
- ppe-128, spe-16
- ppe-16, spe-16 (その1)
- ppe-16, spe-16 (その2)
おおよその手順は下記のとおりです。
- 1回目のDMA転送(結果は捨てる)
- 2回目から10回DMA転送を行ない、結果を平均する
1回目のDMA転送の結果を捨てるのは、1回目のDMA転送ではPTE(ページテーブルエントリー)の入れ替えに余計な時間を必要とするためです。詳しくは CBE_Architecture をご覧ください。 核となるコードは下記のとおりです。
void* p = (char*)&buf + SPE_OFFSET;
unsigned int q = arg[0] + PPE_OFFSET;
printf ("ppe addr = %x\n", q);
printf ("spe addr = %p\n", p);
printf ("size = %d\n", SIZE);
// ignore first dma
spu_mfcdma32 (p,
q,
SIZE,
0,
MFC_GET_CMD);
spu_writech(MFC_WrTagMask, 1<<0);
spu_mfcstat(MFC_TAG_UPDATE_ALL);
// mesure avg. of second dma and later
const int loop = 10;
for (int i = 0; i < loop; i++)
{
t1 = spu_readch (SPU_RdDec);
spu_mfcdma32 (p,
q,
SIZE,
0,
MFC_GET_CMD);
spu_writech(MFC_WrTagMask, 1<<0);
spu_mfcstat(MFC_TAG_UPDATE_ALL);
t2 = spu_readch (SPU_RdDec);
t3 += t1 - t2;
}
t3 /= loop;
printf ("decrementer = %d\n", t3);
printf ("cpu cycle = %d\n", (int)(t3*3192/79.8f)); // see /proc/cpu
結果
(1) ppe-128, spe-128
ppe側とspe側の両方が128バイトに整列しているときです。このときがベストパフォーマンスが得られます。
ppe addr = 10013380 spe addr = 0x2c00 size = 4096 decrementer = 32 cpu cycle = 1280
4096バイトgetするのに1280サイクルかかりました。
(2) ppe-128, spe-16
ppe側が128バイト、spe側が16バイトに整列しているときです。
ppe addr = 10013380 spe addr = 0x2b10 size = 4096 decrementer = 66 cpu cycle = 2640
4096バイトgetするのに(1)の倍近い2640サイクルかかりました。
(3) ppe-16, spe-16 その1
ppe側が16バイト、spe側が16バイトに整列しているときです。ただし意図的に両者の下位7ビットが一致しないようにしています。つまり128バイト境界から数えたオフセット値が一致しないようにしています。
ppe addr = 10013390 spe addr = 0x2b20 size = 4096 decrementer = 67 cpu cycle = 2680
4096バイトgetするのに(2)と同じぐらいの2680サイクルかかりました。
(4) ppe-16, spe-16 その2
(3)と同じようにppe側が16バイト、spe側が16バイトに整列しているときです。ただし意図的に両者の下位7ビットが一致するようにしています。つまり128バイト境界から数えたオフセット値が一致します。
ppe addr = 10013390 spe addr = 0x2b10 size = 4096 decrementer = 35 cpu cycle = 1400
この場合は(3)の半分で(1)と同じぐらいの1400サイクルで転送できました。
まとめ
(1)から(4)の結果をまとめると、
- ppe側とspe側のアドレスが両者とも128バイト境界に整列しているときベストパフォーマンスが得られる((1)のケース)
- そうでないときは2倍ぐらいの時間がかかる((2)のケース)
- ただし128バイト境界に整列しているとは両方のアドレスの下位7ビットが0である必要はなく、同じであれば良い((4)のケース)
基本的には __attribute__((aligned(128)))をつけておけば問題ありません。 不安な時は実際にDMA転送にかかっている時間を計測してベストパフォーマンスが出ているかどうか確認してください。
