イベント・ベース・サンプリング (EBS) を使用した FLOPS の推定

インテル® VTune™ プロファイラー

この記事は、インテル® ソフトウェア・ネットワークに掲載されている「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) を使用してプロセッサー・イベントのサンプリングを行います。また、いくつかのプロセッサー・イベントを使って、実行時の浮動小数点演算数を統計的にサンプリングできます。

fig1.png
図 1: スカラー処理と SIMD (Single Instruction Multiple Data) 処理の比較

fig2.png

図 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 を設定できます。

fig3.png

x87 レジスターの使用

サンプル・アプリケーションを Windows* 上の Microsoft* Visual Studio* を使用してリリースモードでコンパイル (最適化レベルは 0x に設定) してみましょう。 このアプリケーションをインテル® VTune™ Amplifier XE で解析したところ、次のような結果が得られました。

fig4.png

以下の解析結果から、コンパイラーによってどのようにコードが生成されたのかが分かります。この実行では、x87 を使用して FP 演算のサンプルだけを収集していることが明らかです。

fig5.png

それぞれの式に値を代入してみましょう。

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 で解析したところ、次のような結果が得られました。

fig6.png

fig7.png

まず、サンプリングされた関数名が違うことが分かります。x87 レジスターの結果では matrixMultiply 関数でサンプルを収集していますが、ここでは threadPool 関数でサンプルを収集しています。これは、インライン展開が行われたためで (詳細は、ウィキペディアを参照)、 threadPool をドリルダウンするとこのことがよく分かります。

fig8.png

それぞれの式に値を代入してみましょう。ここでは、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 値を求める方法を紹介しました。

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