Intel AVX simulator is now available

by syoyo

http://softwarecommunity.intel.com/articles/eng/3848.htm

http://softwareblogs.intel.com/2008/08/11/emulation-of-new-instructions/

http://softwarecommunity.intel.com/articles/eng/3849.htm
(download)

Intel has released the functional simulator(i.e., not a cycle-aculate simulator) for AVX, which can also simulate full x86 instruction sets.

The emulator, Intel SDE(Software Development Emulator) is built on top of Pin: A binary instrumentation tool for x86.

Any realtime raytracing program targeting for x86 SIMD should use this simulator to accurately and statistically analyze the efficiency of the algorithm.

You can see some of my trials about the tool among the following Japanese text.

[Ja]

Intel から x86 シミュレータである SDE がリリースされました.
既存の x86 命令すべてに加えて、AVX 命令もシミュレーションすることができます.
SSE 命令ももちろんシミュレートすることができますので、既存の SSE アプリの解析にも使うことができます.
ただし、シミュレータは機能シミュレータです(サイクルアキュレートシミュレータではない).

SDE は Pin と呼ばれる x86 用のバイナリインストゥルメンテーションツールを利用して構築されていて、Pin だけでも役に立ちそうなツールです.

たとえばインストラクション数をカウントする命令を x86 バイナリに挿入して、実行時にトレースし、いくらインストラクションが実行されるか調べたり、ブランチの taken, not taken の率をカウントする命令を挿入することができます(試してないけどできるはず).
また、キャッシュシミュレーションなどもできるみたい.
drace のような仕組みのバイナリ版みたいな感じと言えるでしょうか.

使ってみる

まずはこんなコードを用意し、シミュレータにかけてみました.


#include 

void
mudatest()
{
    __m128 a, b, c;

    a = _mm_set_ps(1.0f, 2.0f, 3.0f, 4.0f);
    b = _mm_set_ps(0.1f, 0.2f, 0.3f, 0.4f);

    c = _mm_add_ps(a, b);
}

int
main()
{
    mudatest();
    return 0;
}


$ gcc -msse main.c
$ sde -mix -- ./a.out
$ cat mix.out

...
# TID 0
#       opcode                 count-unpredicated    count-predicated
#
     5 ADC                                     31                0
     6 ADD                                  11989                0
     8 ADDPS                                    1                0
    19 AND                                   1613                0
...

addps 命令が 1 個カウントされています.
これは期待どうりなのですが、つづいてログファイルにはアセンブラのトレース結果が記録されているのだけれども、そこには mudatest() の部分が見当たらない. どうもバイナリ実行のブートストラップ部分の命令数が多すぎて、そこでトレースするインストラクション数を越えてしまったようだ(デフォルトは 0xffff 個の命令をトレースするみたい).

mudatest 関数のアドレスを objdump で求めて、トレースを始める場所を指定するようにしてみる.


$ sde -mix -start-address 0x08048344 -- ./a.out
$ cat mix.out
...
XDIS 080483a6:  SSE 0F294588                 movaps xmmword ptr ss[ebp-0x78], xm
m0
XDIS 080483aa:  SSE 0F284D88                 movaps xmm1, xmmword ptr ss[ebp-0x7
8]
XDIS 080483ae:  SSE 0F284598                 movaps xmm0, xmmword ptr ss[ebp-0x6
8]
XDIS 080483b2:  SSE 0F58C1                   addps xmm0, xmm1
XDIS 080483b5:  SSE 0F2945C8                 movaps xmmword ptr ss[ebp-0x38], xmm0
...

今度はトレースの結果に mudatest() 部分がきちんと記録されている.

-debugtrace を指定すると、より詳細なインストラクショントレースができる.



$ spe -debugtrace -- ./a.out
...
0x080483ae /home/syoyo/src/sde-avx/a.out:mudatest+0x006a movaps xmm0, xmmword pt
r ss[ebp-0x68]
                XMM0 := 3f800000_40000000_40400000_40800000
                XMM0 (doubles) := 0.0078125 32
                XMM0 (floats)  := 1 2 3 4
0x080483b2 /home/syoyo/src/sde-avx/a.out:mudatest+0x006e addps xmm0, xmm1
                XMM0 := 3f8ccccd_400ccccd_40533333_408ccccd
                XMM0 (doubles) := 0.0140625 76.8
                XMM0 (floats)  := 1.1 2.2 3.3 4.4
...

レジスタの中身まで記録してくれる. これは便利ですね.
たとえば数値計算コードで、どこで Inf や NaN に計算結果が陥ってしまうかのデバッグに役立つと思います(gdb でもできるけどね).

AVX 命令のシミュレーション

では実際に AVX 命令のシミュレーションをやってみます.
現状まともに AVX 命令を吐ける C コンパイラはないので(gcc は svn から引っ張れば使えるかもしれない. icc は Q1/’09 リリース予定らしい),アセンブラ命令を書くことに.
最新 yasm は AVX 命令をサポートするので、yasm でアセンブルすることにしました.

1 からアセンブラを書くのもめんどくさいので、こんなコードをでっちあげました.


typedef double double4 __attribute__((vector_size(32)));

void
mudatest()
{
    double4 a, b, c;

    a = (double4){1.0, 2.0, 3.0, 4.0};
    b = (double4){0.1f, 0.2f, 0.3f, 0.4f};

    c = a + b;
}

int
main()
{
    mudatest();
    return 0;
}


これだと gcc が 2 個の addpd を吐くようにしてくれます. これを gcc でアセンブラに落としてから addpd の該当部分を vaddpd に書き換えるようにしてみました.


$ gcc -S avxtest.c
$ cat avxtest.s
...

...	movapd	-40(%ebp), %xmm1
	movapd	-72(%ebp), %xmm0
	movapd	%xmm1, %xmm2
	addpd	%xmm0, %xmm2
	movapd	-24(%ebp), %xmm1
	movapd	-56(%ebp), %xmm0
	addpd	%xmm1, %xmm0
	movapd	%xmm2, -104(%ebp)
	movapd	%xmm0, -88(%ebp)
...
$ vi avxtest.s      <- edit
$ cat avxtest.s
...
	vmovupd	-40(%ebp), %ymm1
	vmovupd	-72(%ebp), %ymm0
	vaddpd	%ymm0, %ymm1, %ymm1
	vmovupd	%ymm1, -104(%ebp)
...

これを yasm を通して elf 実行バイナリを作ります.


$ yasm -f elf -p gas -o avxtest.o avxtest.s
$ gcc avxtest.o

シミュレータでデバッグトレースさせてみます.


$ sde -debugtrace -- ./a.out
...
0x0804842a /home/syoyo/src/sde-avx/a.out:mudatest+0x00da vmovupd ymm1, ymmword p
tr ss[ebp-0x28]
                YMM1 := 40100000_00000000_40080000_00000000_40000000_00000000_3f
f00000_00000000
                YMM1 (doubles) := 4 3 2 1
                YMM1 (floats)  := 2.25 0 2.125 0 2 0 1.875 0
                                 Read 3fd99999_a0000000_3fd33333_40000000_3fc999
99_a0000000_3fb99999_a0000000 = *(UINT256)0xbf8711c0
0x0804842f /home/syoyo/src/sde-avx/a.out:mudatest+0x00df vmovupd ymm0, ymmword p
tr ss[ebp-0x48]
                YMM0 := 3fd99999_a0000000_3fd33333_40000000_3fc99999_a0000000_3f
b99999_a0000000
                YMM0 (doubles) := 0.4 0.3 0.2 0.1
                YMM0 (floats)  := 1.7 -1.0842e-19 1.65 2 1.575 -1.0842e-19 1.45
-1.0842e-19
0x08048434 /home/syoyo/src/sde-avx/a.out:mudatest+0x00e4 vaddpd ymm1, ymm1, ymm0
                YMM1 := 40119999_9a000000_400a6666_68000000_40019999_9a000000_3ff19999_9a000000
                YMM1 (doubles) := 4.4 3.3 2.2 1.1
                YMM1 (floats)  := 2.275 -2.64698e-23 2.1625 2.41785e+24 2.025 -2.64698e-23 1.8875 -2.64698e-23
...

ロードのアドレスを間違っているみたいで数値の並びがちょっとおかしい気がしますが、とりあえず add の値は期待するものなのでシミュレーション成功ということで.

まとめ

– 現状 C から AVX 命令を使うツールチェインがまだ確立されていないので、今 AVX 命令を試すならアセンブラで書くことに.
– AVX 以外でも、既存の x86 命令ももちろんシミュレートできるので、既存アプリのプロファイルツールとしても使える.
– リアルタイムレイトレとかで x86 実装をターゲットとしているのはこのようなシミュレータが提供されたことですから、シミュレータできちんとアルゴリズムの性能を測定すべきでしょう.

Advertisements