SSE2命令(movdqu)を使用した128ビット単位のメモリ間転送プログラム
SSE2では、128ビット整数演算のSIMD命令の拡張が行われており、演算だけでなく、movdqa・movdquという命令を使うことで128ビット単位でメモリ間のデータコピーを高速に行うことができます。movdqaは転送対象のメモリのアドレスが16バイトの境界(アライメン ト)に揃ってる必要があります(アドレス値が16で割り切れる)。これに対して、movdquでは16バイトのアライメント制約はなく、どのアドレス値からでも読み書きできます。ただ、アライメントが揃っている分、CPUが処理しやすいため、movdqa命令の方が実行速度が速いです。速さを追求するならば、mallocや配列の確保時に16バイトのアライメントを意識する必要があります。各命令の基本的な実行速度はIntelから以下の資料が出ていますが、この資料上ではmovdqa・ movdquのスループットとレイテンシは同じになってますね・・・。ちょっとこのあたりは不明です。
・Intel技術資料 「IA-32命令のレイテンシとスループット」 (PDF)
この資料にはMMXやSSEの拡張命令も載っています。ちなみにざっくり分けると、MMXは64ビットのSIMD命令の拡張で、SSEは128ビットの浮動小数点演算のSIMD命令拡張だったと思います。
とりあえず、movdquを使ってメモリ間のデータ転送を行うサンプルは以下のようになります。 Linux+gccの環境で動きます。srcとdstにポインタを渡し、転送サイズをsizeで指定するだけです。SSE2非対応の場合を考えて、normalcalcの部分を追加してます。
ソースコード
// SSE2のmovdqu命令を用いてメモリ間転送
void memcpy_sse2(void *src, void *dst, size_t size)
{
asm ("\n"
" mov %0, %%eax\n"
" lea (%%esi, %0), %%ebx\n"
" ssecalc:\n"
" movdqu (%%esi),%%xmm0\n"
" lea 16(%%esi), %%esi \n"
" movdqu %%xmm0,(%%edi)\n"
" lea 16(%%edi), %%edi\n"
" sub $16, %%eax\n"
" cmp $16, %%eax\n"
" jge ssecalc\n"
" cmp %%ebx, %%esi\n"
" je end\n"
" normalcalc:\n"
" mov (%%esi), %%al\n"
" lea 1(%%esi), %%esi\n"
" mov %%al, (%%edi)\n"
" lea 1(%%edi), %%edi\n"
" cmp %%ebx, %%esi\n"
" jne normalcalc\n"
" end:\n"
" emms" :: "r" (size), "S" (src), "D" (dst));
}
(ファイル)
・memcpy_SSE2.h
・memcpy_SSE2.c
(参考URL)
・Programming Lab
・Advanced Optimization
トラックバック(0)
トラックバックURL: http://kirihari.net/mt/mt-tb.cgi/5
Programming Lab は移転しました。
移転先: http://krypton.pv.land.to/
ご連絡ありがとうございます! リンク修正しました。