インテル® Software Development Emulator を使ってみよう

インテル® Software Development Emulator

インテル® Software Development Emulator (インテル® SDE) は、ソフトウェア開発者向けにインテル社から公開されているインテル® プロセッサーのソフトウェア・エミュレーターです。2019 年 5 月時点の最新バージョンは 8.35 で、開発コード名 Ice Lake-Client と開発コード名 Ice Lake-Server までのプロセッサーがサポートされています。

前の記事で紹介したように、インテル® C/C++ および Fortran コンパイラー 19 Update 4 は、開発コード名 Ice Lake-Client と開発コード名 Ice Lake-Server でサポートされるインテル® アドバンスト・ベクトル・エクステンション 512 (インテル® AVX-512) 命令セットを生成することができます。発表前のプロセッサーは、一部のメーカーや恵まれた人々しか利用できないため、私たちはエミュレーションが唯一の検証手段です。

エミュレーション環境でプログラム全体を実行すると、もちろん実行時間は数十倍から数百倍遅くなります。しかし、独自にプロセッサーを判定して実行するコードを切り分けるコードの動作を確認したり、アルゴリズムの設計段階で特定の機能のみに新しい命令セットを使用して単体検証するようなケースでは十分に利用できるかもしれません。

この記事ではインテル® SDE の Windows* 版を使用していくつかの利用例を紹介します。インテル® SDE は、https://software.intel.com/en-us/isa-extensions から無料で入手できます。ダウンロードしたパッケージを展開すると、インストールすることなく実行できます。システムにウイルス対策ツールが導入されている場合、インテル® SDE を実行すると保護対象として保護される可能性があります。展開先のディレクトリーを保護から除外することでこの問題は解決できるでしょう。

Windows* 環境では、ダウンロードしたバージョン 8.35 のパッケージを展開すると、sde-external-8.35.0-2019-03-11-win というディレクトリーが作成されました。ディレクトリーの内容を確認すると次のような構造です。このディレクトリーを環境変数 PATH に手動で追加します (例: set PATH=%PATH%; C:\sde-external-8.35.0-2019-03-11-win)。

通常起動に使用するファイルは、sde.exesde-win.bat です。

sde を直接起動

sde はインテル® SDE の本体です。このコマンドを使用する場合、次の形式でコマンドを入力します。sde のコマンドオプションとアプリケーションは、– で分離する必要があります。

$ sde <sde のオプション> -- <実行するアプリケーション> <.アプリケーションの引数>

例えば、icl pi.c /QxICELAKE-CLIENT で開発コード名 Ice Lake-Client でサポートされるインテル® AVX-512 命令セットを使用したバイナリーを生成すると、現在利用可能なプロセッサーでは実行できませんが、

$ sde –icl –- pi    ここで、-icl は開発コード名 Ice Lake-Client をエミュレーション・ターゲットにするオプション

を実行すると、バイナリーをエミュレーションして実行できます。以下は、実際にインテル® Core™ i7-9700K プロセッサー上で実行した例です。

実行時間は、インテル® AVX2 を使用してインテル® Core™ i7-9700K プロセッサーで実行したバイナリーよりも、インテル® AVX-512 をエミュレーションしたバイナリーのほうが 20 倍程度遅くなっています。エミュレーション速度の低下は、実際にエミュレーションされる命令数よって異なります。

インテル® SDE は単にバイナリーをエミュレーションするだけではなく、エミュレーションしたバイナリーの統計情報を生成できます。

$ sde –icl –mix –- pi    -mix オプションを追加

-mix オプションを追加して実行すると統計情報ファイル sde-mix-out.txt が現在のディレクトリーに生成されます。

ファイルの一部を見てみます。

# ==============================================
# STATS FOR TID 0  OS-TID  1344 EMIT# 1
# ==============================================
# EMIT_TOP_BLOCK_STATS FOR TID 0  OS-TID 1344 EMIT # 1 EVENT=ICOUNT
BLOCK:     0   PC: 00007ff7e9fe10df   ICOUNT: 968750000   EXECUTIONS:  31250000   #BYTES: 178   %:  99.6   cumltv%:  99.6  FN: .text  IMG: C:\Users\kiyo\Desktop\2019\FTF_expert\code\pi\pi.exe  OFFSET: 10df
XDIS 00007ff7e9fe10df: BASE 83C020                   add eax, 0x20
XDIS 00007ff7e9fe10e2: AVX512EVEX 62C17E48E6C6       vcvtdq2pd zmm16, ymm14
XDIS 00007ff7e9fe10e8: AVX512EVEX 62A1E54858C8       vaddpd zmm17, zmm3, zmm16
XDIS 00007ff7e9fe10ee: AVX512EVEX 62A1DD4859D1       vmulpd zmm18, zmm4, zmm17
XDIS 00007ff7e9fe10f4: AVX512EVEX 62E2ED40A8D0       vfmadd213pd zmm18, zmm18, zmm0
XDIS 00007ff7e9fe10fa: AVX512EVEX 62A1F5485EDA       vdivpd zmm19, zmm1, zmm18
XDIS 00007ff7e9fe1100: AVX512EVEX 6221854858DB       vaddpd zmm27, zmm15, zmm19
XDIS 00007ff7e9fe1106: AVX2 C50DFEFA                 vpaddd ymm15, ymm14, ymm2
XDIS 00007ff7e9fe110a: AVX512EVEX 62C17E48E6E7       vcvtdq2pd zmm20, ymm15
XDIS 00007ff7e9fe1110: AVX512EVEX 62A1E54858EC       vaddpd zmm21, zmm3, zmm20
XDIS 00007ff7e9fe1116: AVX512EVEX 62A1DD4859F5       vmulpd zmm22, zmm4, zmm21
XDIS 00007ff7e9fe111c: AVX512EVEX 62E2CD40A8F0       vfmadd213pd zmm22, zmm22, zmm0
XDIS 00007ff7e9fe1122: AVX512EVEX 62A1F5485EFE       vdivpd zmm23, zmm1, zmm22
XDIS 00007ff7e9fe1128: AVX512EVEX 6231D54858F7       vaddpd zmm14, zmm5, zmm23
XDIS 00007ff7e9fe112e: AVX2 C585FEEA                 vpaddd ymm5, ymm15, ymm2
XDIS 00007ff7e9fe1132: AVX512EVEX 62615528FEEA       vpaddd ymm29, ymm5, ymm2
XDIS 00007ff7e9fe1138: AVX512EVEX 62617E48E6C5       vcvtdq2pd zmm24, ymm5
XDIS 00007ff7e9fe113e: AVX512EVEX 6201E54858C8       vaddpd zmm25, zmm3, zmm24
XDIS 00007ff7e9fe1144: AVX512EVEX 6201DD4859D1       vmulpd zmm26, zmm4, zmm25
XDIS 00007ff7e9fe114a: AVX512EVEX 6262AD40A8D0       vfmadd213pd zmm26, zmm26, zmm0
XDIS 00007ff7e9fe1150: AVX512EVEX 6201F5485EE2       vdivpd zmm28, zmm1, zmm26
XDIS 00007ff7e9fe1156: AVX512EVEX 6211A54058FC       vaddpd zmm15, zmm27, zmm28
XDIS 00007ff7e9fe115c: AVX512EVEX 62017E48E6F5       vcvtdq2pd zmm30, ymm29
XDIS 00007ff7e9fe1162: AVX512EVEX 6201E54858FE       vaddpd zmm31, zmm3, zmm30
XDIS 00007ff7e9fe1168: AVX512EVEX 6291DD4859EF       vmulpd zmm5, zmm4, zmm31
XDIS 00007ff7e9fe116e: AVX512EVEX 62F2D548A8E8       vfmadd213pd zmm5, zmm5, zmm0
XDIS 00007ff7e9fe1174: AVX512EVEX 6261F5485EF5       vdivpd zmm30, zmm1, zmm5
XDIS 00007ff7e9fe117a: AVX512EVEX 62918D4858EE       vaddpd zmm5, zmm14, zmm30
XDIS 00007ff7e9fe1180: AVX512EVEX 62711520FEF2       vpaddd ymm14, ymm29, ymm2
XDIS 00007ff7e9fe1186: BASE 3D00CA9A3B               cmp eax, 0x3b9aca00
XDIS 00007ff7e9fe118b: BASE 0F824EFFFFFF             jb 0x7ff7e9fe10df
…

実行された命令のアセンブリー・リストが表示されていますが、このリストで、「XDIS 00007ff7e9fe10e2: VX512EVEX」のように AVX512EVEX と示されている命令がインテル® AVX-512 命令でエミュレーションされた命令です。このアセンブリーは、数値積分を使用して PI を計算する以下のループ、

for (i=0;i< num_steps; i++){
    x = (i+0.5)*step;
    sum = sum + 4.0/(1.0+x*x);
}

です。ここで使用するデータ型は double であるため、インテル® AVX-512 では 8 個の要素を SIMD 計算できます。また、4 つの vfmadd213pd 命令が生成され、ループは 4 回アンロールされていることから、ループ・インデックスは、4 x 8 = 32 (0x20) でインクリメントされていることが分かります (先頭の add eax, 0x20 命令)。

これ以外に命令のカテゴリー別の実行回数を見ることもできます。

# END_TOP_BLOCK_STATS
# EMIT_DYNAMIC_STATS FOR TID 0  OS-TID 1344 EMIT #1
#
# $dynamic-counts
#
# TID 0
#       opcode                 count
#
*mem-atomic                                                         1753
*stack-read                                                        61484
*stack-write                                                      115261
*iprel-read                                                        13114
*iprel-write                                                        1237
*mem-read-1                                                       322865
*mem-read-2                                                       302421
*mem-read-4                                                        47228
*mem-read-8                                                        92692
*mem-read-16                                                        6379
*mem-read-32                                                           2
*mem-read-64                                                          88
*mem-write-1                                                      106294
*mem-write-2                                                       15132
*mem-write-4                                                       43894
*mem-write-8                                                       82703
*mem-write-16                                                      13235
*mem-write-64                                                          1
*mem-write-512                                                         1
*mem-read                                                         771675
*mem-write                                                        261260
*mem                                                             1024189
*isa-ext-3DNOW                                                        83
*isa-ext-AVX                                                          84
*isa-ext-AVX2                                                   62500000
*isa-ext-AVX512EVEX                                            812500016
*isa-ext-BASE                                                   97353540
*isa-ext-FMA                                                          14
…

これらの情報は新しい命令セットがどれくらい実行されているか判断するのに役立ちます。

sde.exe では実行時に次のようにプロセッサーを明示的に指定することができます。

次のようなプロセッサーを手動で判定する処理を考えてみます。

#define  KNL  ( _FEATURE_AVX512F | _FEATURE_AVX512ER | _FEATURE_AVX512PF | _FEATURE_AVX512CD )
#define  CAS  ( _FEATURE_AVX512DQ | _FEATURE_AVX512F | _FEATURE_AVX512CD | _FEATURE_AVX512BW | _FEATURE_AVX512VL )
#define  ICL  ( _FEATURE_AVX512DQ | _FEATURE_AVX512F | _FEATURE_AVX512CD | _FEATURE_AVX512BW | _FEATURE_AVX512VL | _FEATURE_AVX512IFMA52 | _FEATURE_AVX512VBMI | _FEATURE_AVX512_VPOPCNTDQ | _FEATURE_AVX512_BITALG |  _FEATURE_AVX512_VBMI2 | _FEATURE_GFNI | _FEATURE_VAES | _FEATURE_VPCLMULQDQ | _FEATURE_AVX512_VNNI | _FEATURE_RDPID )

int main(int argc, char *argv[]) {

if ( _may_i_use_cpu_feature( (unsigned long) ICL ) )
printf("この CPU は、AVX-512F+DQ+CD+BW+VL 命令セットをサポートする IceLake Client プロセッサーです。\n");
else if ( _may_i_use_cpu_feature( (unsigned long) CAS ) )
printf("この CPU は、AVX-512F+DQ+CD+BW+VL 命令セットをサポートする CascadeLake プロセッサーです。\n");
else if ( _may_i_use_cpu_feature( (unsigned long) KNL ) )
printf("この CPU は、AVX-512F+CD+ER+PF 命令セットをサポートする Knights Landing プロセッサーです。\n");
else
printf("この CPU は AVX-512 命令セットをサポートしていません。\n");
}

このコードを icl cupid.c でコンパイルして、インテル® Core™ i7-9700K プロセッサーで実行してみます。

当然、define 文で指定される CPUID の機能ビットはサポートされないため、上記のメッセージが出力されます。では、インテル® SDE によるエミュレーションで、開発コード名 Ice Lake-Client (-icl)、開発コード名 Cascade Lake (-clx)、そして開発コード名 Kights Landing (-knl) のチェック機能をそれぞれ確認してみます。

インテル® SDE はエミュレートする機能を特定するため CPUID を照合します。また、エミュレートされた機能をチェックするコンパイル済みアプリケーションに対し、それらが存在することを通知するため CPUID の出力を変更します。これにより、チェックが正しく行われていることが確認できました。

sde-win.bat を使用する

このバッチファイルの中身は、sde –- cmd.exe です。Linux* や macOS* 環境でも sde –- ksh のようにシェルをインテル® SDE 環境下で起動することができます。このバッチファイルを起動すると、Windows* ではコマンドプロンプトが開き、この中で実行されるコマンドはすべてインテル® SDE のエミュレーション環境で実行されます。エミュレーション対象のプロセッサーを変更する場合、前述のオプションをバッチファイルに加えると良いでしょう (sde –clx –- cmd.exe のように)。

cupid のプロセッサー・チェックをこの環境で実行すると次のようになります。

このウィンドウで起動されるすべてのバイナリーは、インテル® SDE の制御下で実行されるため、エミュレーションが行われなくても実行速度は遅くなります。次の例は、インテル® AVX2 命令セットの最適化オプションを指定して生成したプログラムですが、描画性能は 86FPS であると示されています (プログラム・ウィンドウの上部)。

通常のコマンドプロンプトで実行すると、1452FPS ですのでほぼ 1/120 のパフォーマンスであることが分かります。

sde-win.bat やシェルのエミュレーション環境を使用すると、簡単に異なるプロセッサー環境を用意することができます。

インテル® SDE の使い方や、Windows*、Linux* および macOS* での詳しい導入方法については、こちらの記事をご覧ください。このエミュレーターは、プロセッサーのリリースが計画されると随時更新されているようなので、今後登場するさたに未知のプロセッサーのエミュレーションも利用できるようになるでしょう。

発表済みの開発コード名 Cascade Lake をまだ入手できない、または開発コード名 Ice Lake にいち早く対応したい、と思われている開発者の方は是非このツールを活用してみてください。

タイトルとURLをコピーしました