HPC/並列プログラミングポータルでは、HPC(High Performance Computing)プログラミングや並列プログラミングに関する情報を集積・発信しています。 |
[記事一覧を見る]
さて、ここではSSEを使用した場合と使用しない場合でのパフォーマンス差をチェックしたが、実はVisual Studioでもオプション設定を行うことでSSEを利用するコードを出力できる。Visual Studio 2005/2008ではMMX/SSE/SSE2命令を使用した最適化が、Visual Studio 2010ではAVXを使用した最適化がサポートされている。たとえばSSE2を利用する場合、「/arch:sse2」オプションを使用すればよい。実際にVisual Studio 2010でSSE2を利用するように設定して生成したアセンブラコードが次のリスト4だ。
; 142 : d = 0.0; xorps xmm0, xmm0 ; 143 : for (i = 0; i 128; i++) { xor eax, eax npad 3 $LL3@main: ; 144 : d += a[i] * b[i]; movss xmm1, DWORD PTR _b$[esp+eax+1088] movss xmm2, DWORD PTR _a$[esp+eax+1088] cvtps2pd xmm1, xmm1 cvtss2sd xmm0, xmm0 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 addsd xmm1, xmm0 movss xmm2, DWORD PTR _b$[esp+eax+1092] xorps xmm0, xmm0 cvtpd2ps xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1092] cvtps2pd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 addsd xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1096] movss xmm2, DWORD PTR _b$[esp+eax+1096] cvtpd2ps xmm0, xmm0 cvtss2sd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 movss xmm2, DWORD PTR _b$[esp+eax+1100] addsd xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1100] cvtpd2ps xmm0, xmm0 cvtss2sd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 movss xmm2, DWORD PTR _b$[esp+eax+1104] addsd xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1104] cvtpd2ps xmm0, xmm0 cvtss2sd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 movss xmm2, DWORD PTR _b$[esp+eax+1108] addsd xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1108] cvtpd2ps xmm0, xmm0 cvtss2sd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 movss xmm2, DWORD PTR _b$[esp+eax+1112] addsd xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1112] cvtpd2ps xmm0, xmm0 cvtss2sd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 mulsd xmm1, xmm2 movss xmm2, DWORD PTR _b$[esp+eax+1116] addsd xmm0, xmm1 movss xmm1, DWORD PTR _a$[esp+eax+1116] cvtpd2ps xmm0, xmm0 cvtss2sd xmm0, xmm0 cvtps2pd xmm1, xmm1 cvtps2pd xmm2, xmm2 add eax, 32 mulsd xmm1, xmm2 addsd xmm0, xmm1 cvtpd2ps xmm0, xmm0 cmp eax, 512 jl $LL3@main ; 145 : } ; 146 : ; 147 : printf("%f\n", d); sub esp, 8 cvtss2sd xmm0, xmm0 movsd QWORD PTR [esp], xmm0 push OFFSET $SG5712 call _printf
こちらの場合、「xmm0」~「xmm2」があることからも分かるとおり、確かにSSEを利用したコードが出力されている(太字がSSE命令)。ただし、インテル C++ Composer XE 2011で生成されたコードとは異なり、乗算/加算にはパックド命令は使用されておらず、同時に1つのデータしか処理していない。実行時間も9.800秒と、SSE2を利用しない場合よりもわずかではあるが劣る結果となった。
なお、Visual StudioではSSE/SSE2、およびインテル AVXのみがサポートされているが、インテル C++ Composer XE 2011ではSSE2/SSE3/SSSE3/SSE4.1/SSE4.2およびインテル AVXがサポートされている。インテル AVXが実装されたCPUはまだリリースされていないものの、コードの生成自体は可能だ。実際にリスト1のコードをインテル AVX対応CPU向けの設定でコンパイルして生成されたアセンブラコードが次のリスト5である。
;;; d = 0.0; ;;; for (i = 0; i 128; i++) { ;;; d += a[i] * b[i]; lea eax, DWORD PTR [1184+esp] and eax, 31 mov DWORD PTR [128+esp], edi mov esi, eax mov edi, edx .B1.7: mov ecx, esi .B1.12: vxorps ymm0, ymm0, ymm0 vxorpd ymm1, ymm1, ymm1 .B1.13: vmovupd xmm2, XMMWORD PTR [136+esp+ecx*8] vmovupd xmm5, XMMWORD PTR [168+esp+ecx*8] vinsertf128 ymm3, ymm2, XMMWORD PTR [152+esp+ecx*8], 1 vinsertf128 ymm6, ymm5, XMMWORD PTR [184+esp+ecx*8], 1 vmulpd ymm4, ymm3, YMMWORD PTR [1184+esp+ecx*8] vmulpd ymm7, ymm6, YMMWORD PTR [1216+esp+ecx*8] vmovupd xmm2, XMMWORD PTR [200+esp+ecx*8] vmovupd xmm5, XMMWORD PTR [232+esp+ecx*8] vaddpd ymm0, ymm0, ymm4 vaddpd ymm1, ymm1, ymm7 vinsertf128 ymm3, ymm2, XMMWORD PTR [216+esp+ecx*8], 1 vinsertf128 ymm6, ymm5, XMMWORD PTR [248+esp+ecx*8], 1 vmulpd ymm4, ymm3, YMMWORD PTR [1248+esp+ecx*8] vmulpd ymm7, ymm6, YMMWORD PTR [1280+esp+ecx*8] vaddpd ymm0, ymm0, ymm4 vaddpd ymm1, ymm1, ymm7 add ecx, 16 cmp ecx, 128 jb .B1.13 .B1.14: vaddpd ymm0, ymm0, ymm1 vextractf128 xmm1, ymm0, 1 vaddpd xmm2, xmm0, xmm1 vhaddpd xmm3, xmm2, xmm2 .B1.18: ;;; } ;;; ;;; printf("%f\n", d); mov DWORD PTR [esp], OFFSET FLAT: ??_C@_03A@?$CFf?6?$AA@ vmovsd QWORD PTR [4+esp], xmm3 vzeroupper call _printf
アセンブラ中で「v」で始まる命令(リスト中太字の部分)がインテル AVX命令、「ymm0」~「ymm7」はインテル AVXで新たに追加された256ビット長のYMMレジスタである。現在ではAVX対応CPUがないためパフォーマンスは測定できないが、AVX命令を駆使したコードが出力されていることは確認できる。
Linux/Windows環境で広く使われているコンパイラの1つに、GCCがある。最新版のGCC(GCC 4.5.0)ではSSEサポートが行われており、たとえば「-march=core2 -msse4 -mfpmath=sse」といったオプションを指定することで、SSEを使用するコードを出力できる。たとえば次のリストAは、リスト1のコードを上記のオプション付きでGCCでコンパイルして生成したアセンブラコードである。
このコードではxmm0、xmm1レジスタや「movss」「「mulss」「addss」といったSSE命令が使用されていることが分かる。ただし、こちらもVisual Studioの例と同じくパックド命令は使用されておらず、インテル C++ Composer XE 2011のようなベクトル化は行われていない。
L26: movl $0x00000000, %eax movl %eax, 1560(%esp) movl $0, 1564(%esp) jmp L24 L25: movl 1564(%esp), %eax movss 1044(%esp,%eax,4), %xmm1 movl 1564(%esp), %eax movss 532(%esp,%eax,4), %xmm0 mulss %xmm1, %xmm0 movss 1560(%esp), %xmm1 addss %xmm1, %xmm0 movss %xmm0, 1560(%esp) incl 1564(%esp) L24: cmpl $127, 1564(%esp) setle %al testb %al, %al jne L25 cvtss2sd 1560(%esp), %xmm0 movsd %xmm0, 4(%esp) movl $LC1, (%esp) call _printf incl 1556(%esp) L23: cmpl $999999, 1556(%esp) setle %al testb %al, %al jne L26 movl $0, %eax leave
[PageInfo]
LastUpdate: 2011-01-11 18:51:56, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members