この記事は、インテル® ソフトウェア・ネットワークに掲載されている「Estimating FLOPS using Event Based Sampling (EBS)」(http://software.intel.com/en-us/articles/estimating-flops-using-event-based-sampling-ebs/) の日本語参考訳です。
FLOPS (flops や flop/s ともいう) は floating point operations per second の略語で、ハイパフォーマンス・コンピューティングの分野でよく使われる測定単位です。FLOPS はマイクロプロセッサーのパフォーマンスと計算能力を測定する一般的な方法です。
ここでは、ハードウェアのイベント・ベース・サンプリング (EBS) 機能を使って、アプリケーションで 1 秒間に実行される浮動小数点演算命令の数を推定する方法を紹介します。FLOPS は 32 ビットおよび 64 ビットの浮動小数点の加算または乗算命令数を表します。
インテル® VTune™ Amplifier XE は、ソフトウェア開発者がアプリケーションを解析し、アルゴリズムとマイクロアーキテクチャーのパフォーマンス問題の特定を支援するパフォーマンス解析ツールです。プロセッサーのパフォーマンス・モニタリング・ユニット (PMU) を使用してプロセッサー・イベントのサンプリングを行います。また、いくつかのプロセッサー・イベントを使って、実行時の浮動小数点演算数を統計的にサンプリングできます。
図 1: スカラー処理と SIMD (Single Instruction Multiple Data) 処理の比較
図 2: インテル® アーキテクチャーの整数、浮動小数点、MMX、SSE (ストリーミング SIMD 拡張命令) レジスター
注: この図では、最新の AVX 命令レジスターは省略されています。
図 1 と 2 は、コンパイラーのコードの生成方法に応じて、レガシー x87 レジスターや SSE レジスターに対して浮動小数点演算を実行できることを示しています。SSE レジスターに対して浮動小数点命令を実行する場合は、スカラー演算またはパックド演算でなければなりません。
表 1 (下を参照) にハードウェアによって実行される浮動小数点演算を統計的に推定する際に使用される PMU イベント名を示します。アーキテクチャーの投機的な性質上、実行される命令 (これらのイベントによってカウントされる命令) はすべてリタイアされるわけではありません。つまり、これらのイベント数は実際よりも多いことがあります。
プロセッサー世代 |
プロセッサー・イベント名 |
||
---|---|---|---|
レガシー x87 を使用した FP 演算 |
SIMD を使用した FP 演算 |
||
インテル® Core™2 プロセッサー・ファミリー (インテル® Core™2 Duo/Quad プロセッサーなど) |
X87_OPS_RETIRED.ANY |
パックド 64 ビット | SIMD_COMP_INST_RETIRED.PACKED_DOUBLE |
パックド 32 ビット | SIMD_COMP_INST_RETIRED.PACKED_SINGLE | ||
スカラー 64 ビット | SIMD_COMP_INST_RETIRED.SCALAR_DOUBLE | ||
スカラー 32 ビット | SIMD_COMP_INST_RETIRED.SCALAR_SINGLE | ||
インテル® Core™ アーキテクチャー Nehalem (インテル® Core™ i7/i5/i3 プロセッサー) |
FP_COMP_OPS_EXE.x87 |
パックド 64 ビット | FP_COMP_OPS_EXE.SSE_DOUBLE_PRECISION |
パックド 32 ビット | FP_COMP_OPS_EXE.SSE_SINGLE_PRECISION | ||
スカラー 64 ビット | FP_COMP_OPS_EXE.SSE_FP_SCALAR | ||
スカラー 32 ビット | FP_COMP_OPS_EXE.SSE_FP_SCALAR | ||
インテル® Core™ アーキテクチャー SandyBridge |
FP_COMP_OPS_EXE.X87 |
パックド 64 ビット | FP_COMP_OPS_EXE.SSE_PACKED_DOUBLE |
パックド 32 ビット | FP_COMP_OPS_EXE.SSE_PACKED_SINGLE | ||
スカラー 64 ビット | FP_COMP_OPS_EXE.SSE_SCALAR_DOUBLE | ||
スカラー 32 ビット | FP_COMP_OPS_EXE.SSE_SCALAR_SINGLE |
表 1: 実行時の浮動小数点演算数の推定に使用される PMU イベント
注: この表では AVX の FP 演算のサンプリングに使用されるイベント名は示していません。
インテル® VTune™ Amplifier XE は、これらのイベントのうち任意のものだけ、あるいはすべてを同時に使用してアプリケーションの FLOPS を推定できます。経過時間の測定には、CPU_CLK_UNHALTED (クロック数) イベントを使用します。測定期間中プロセッサーの周波数が一定の場合は、クロック数イベントを使って経過したウォールクロック時間を計算できます。プロセッサー・アーキテクチャーによって CPU_CLK_UNHALTED イベント名は異なることがあるので注意が必要です。
別の方法として、参照サイクル数をカウントし、スレッド周波数の変更に影響されない CPU_CLK_UNHALTED.REF を使用することもできます。参照クロック数イベントとクロック数イベントの違いは、スレッドが停止状態になっても (HLT 命令を実行しても)、参照クロック数イベントはスレッドが最大周波数で実行し続けているかのようにカウントを継続することです。
FLOPS の推定
次の数式を使用して FLOPS を計算できます。
FLOPS = ((FP 演算数 / クロック数) * FP 演算数の合計) / 経過時間 経過時間 = CPU_CLK_UNHALTED / プロセッサーの周波数 / コア数
注: この式には、CPU_CLK_UNHALTED イベントカウントが 0 でないコアを使用します。
ここではマルチスレッド化された簡単な行列乗算を行うサンプル・アプリケーションを使用して、EBS 機能により FLOPS を推定する方法を説明します。このアプリケーションでは、スレッドプールの各スレッドが次のコードを実行します。
double a[NUM][NUM]; double b[NUM][NUM]; double c[NUM][NUM]; ... slice = (unsigned int) tid; from = (slice * NUM) / NUM_THREADS; to = ((slice + 1) * NUM) / NUM_THREADS; for(i = from; i < to; i++) { for(j = 0; j< NUM; j++) { for(k = 0; k < NUM; k++) { // 2 fp 演算 / 反復回数: 加算 1、乗算 1 c[i][j] += a[i][k] * b[k][j]; } } } ...
このアプリケーションは、FP 演算数の合計を経過時間で割った FLOPS (= 2 / 反復回数 * NUM * NUM * NUM) も出力します。経過時間には行列乗算部分のみ含まれ、初期化とスレッドの生成にかかったオーバーヘッドは含まれません。 また、関連するコード領域のサンプルを収集するため、__itt_pause() (収集の一時停止) API と __itt_resume() (収集の再開) API を使用しています。ユーザー API の使用方法は、インテル® VTune™ Amplifier XE のドキュメントを参照してください。
インテル® Core™ i7 (x980) ベースのシステム (3.33GHz、6 コア + ハイパースレッディング有効) では、次のようにインテル® VTune™ Amplifier XE を設定できます。
x87 レジスターの使用
サンプル・アプリケーションを Windows* 上の Microsoft* Visual Studio* を使用してリリースモードでコンパイル (最適化レベルは 0x に設定) してみましょう。 このアプリケーションをインテル® VTune™ Amplifier XE で解析したところ、次のような結果が得られました。
以下の解析結果から、コンパイラーによってどのようにコードが生成されたのかが分かります。この実行では、x87 を使用して FP 演算のサンプルだけを収集していることが明らかです。
それぞれの式に値を代入してみましょう。
MFLOPS = FP_COMP_OPS_EXE.FP / 1x106 / 経過時間 経過時間 = CPU_CLK_UNHALTED.THREAD / プロセッサーの周波数 / コア数
経過時間 = 607,652,000,000.00 / 3.33 x 109 / 12 = 15.206 秒 MFLOP = 18,470,000,000.00 / 1x106/ 15.206 秒 =1,214.652 MFLOPS
SSE レジスターの使用
同じサンプル・アプリケーションで SSE レジスターを使ったケースを見てみましょう。インテル® コンパイラー 12.0 でアプリケーションをコンパイルし、インテル® VTune™ Amplifier XE で解析したところ、次のような結果が得られました。
まず、サンプリングされた関数名が違うことが分かります。x87 レジスターの結果では matrixMultiply 関数でサンプルを収集していますが、ここでは threadPool 関数でサンプルを収集しています。これは、インライン展開が行われたためで (詳細は、ウィキペディアを参照)、 threadPool をドリルダウンするとこのことがよく分かります。
それぞれの式に値を代入してみましょう。ここでは、128 ビットの XMM レジスターでは 1 クロックにつき 2 つのパックド倍精度浮動小数点演算を行うことができるため、FP_COMP_OPS_EXE.SSE_DOUBLE_PRECISION イベントに 2 を掛けています。単精度浮動小数点演算では、パックド単精度浮動小数点演算の合計数に 4 を掛ける必要があります。
MFLOPS = 2 * FP_COMP_OPS_EXE.SSE_DOUBLE_PRECISION / 1x106 / 経過時間 経過時間 = CPU_CLK_UNHALTED.THREAD / プロセッサーの周波数 / コア数
経過時間 = (66,178,000,000 / 3.33 x109 / 12 ) = 1.656 秒 MFLOPS = 2 * FP_COMP_OPS_EXE.SSE_DOUBLE_PRECISION / 1 x 106/ 1.656 秒 = 11,053.140 MFLOPS
インテル® Vtune™ Amplifier XE は、統計的なイベントサンプリングを行うため、ここで求めた FLOPS 値は実際の値と若干異なります。しかし、理論値ではなく実際に実行した性能値ですので、信頼性の高い結果であるといえます。以上、インテル® Vtune™ Amplifier XE を利用して、FLOPS 値を求める方法を紹介しました。
インテル® ソフトウェア製品のパフォーマンス/最適化に関する詳細は、最適化に関する注意事項 (英語) を参照してください。