Linux* の perf を使用したインテル® トランザクショナル・シンクロナイゼーション・エクステンション (インテル® TSX) のプロファイリング

その他

この記事は、インテル® デベロッパー・ゾーンに掲載されている「*Intel(r) Transactional Synchronization Extensions (Intel(r) TSX) profiling with Linux perf」(http://software.intel.com/en-us/blogs/2013/05/03/intelr-transactional-synchronization-extensions-intelr-tsx-profiling-with-linux-0) の日本語参考訳です。


インテル® TSX は、ロックのパフォーマンスを向上できるように、スペキュレーティブ・エグゼキューション・モードを提供します。スペキュレーションのチューニングは、PMU プロファイラーに大きな負担がかかります。この記事では、新しい Linux* システムに統合されている perf (または “perf イベント”) プロファイラーを用いたインテル® TSX のプロファイリングについて説明します。インテル® TSX についての詳細は、Wikipedia (英語)、LWN サイトの記事 (英語) および『インテル® 64 アーキテクチャーおよび IA-32 アーキテクチャー最適化リファレンス・マニュアル』 12 章「インテル® TSX の推奨事項を参照してください。

準備

この記事で紹介する手法では、インテル® TSX と Haswell アーキテクチャーに対応するバージョンの perf が必要です。perf は Linux* カーネルに統合されているため、未対応であれば新しいカーネルに更新する必要があります。3.13 以降のカーネルには、この記事で説明するすべての機能が含まれています。カーネルは http://www.kernel.org/pub/linux/kernel/v3.x からダウンロードできます (2013 年 5 月時点では RC プレリリースがダウンロード可能)。3.11 および 3.12 カーネルには一部の機能しか含まれていません。最適な結果を得るには、3.13 以降を使用してください。

カーネルツリーをダウンロードしたら、インストールしてリブートします。次に、(tools/perf に含まれる) perf バイナリーをビルドしてインストールします。使用する perf の機能によっては、ライブラリー・パッケージを追加でインストールしなければいけないことがあります。ビルド・プロシージャーではパッケージ名を示しています。

一部の Linux* ディストリビューションでは、更新されたカーネルと perf パッケージが用意されています。例えば、Fedora 19/20 は (2013 年 5 月時点で) 3.12 ですが、RawHide から 3.13 にアップデートできます。3.13 が正式にリリースされた後は、自動アップデートされます。

基本サイクル・サンプリングでプログラムを理解する

次に、プログラムでインテル® TSX を有効にします。インテル® TSX を有効にしてプログラムを実行すると、perf でプロファイルすることができます。

通常のサイクル・サンプリングはトランザクションをアボートするため、インテル® TSX のパフォーマンスに影響します。一部の初期サイクル・サンプリング (perf record ; perf report) はコストの大きいワークロード部分を見つける有効な方法ですが、インテル® TSX のパフォーマンスに影響することに注意してください。

perf record -e cycles:pp -g program
perf report

レポートをブラウザーで参照するか、ファイルに出力します (perf report > ファイル)。

インテル® TSX をサンプリングする場合、サイクルに :pp 修飾子を使用して PEBS を有効にすることが重要です。これを使用しないと、サンプルがトランザクションにヒットしたとき、サンプリング命令ポインターが常にアボートハンドラー (または HLE のロック命令の近く) に位置することになります。

perf stat -T で基本トランザクションの成功を測定する

インテル® TSX を有効にしてプログラムを実行した後、まず perf stat -T を用いて基本トランザクションの成功を測定します。

perf stat -T program

別のターミナルからプログラムが定常状態で長く並列実行している場合は、次のように指定します。

perf stat -T -a sleep 1

-a オプションを使用するには、root になるか、/proc/sys/kernel/perf_paranoid を -1 に設定します。-a オプションを指定すると、マシン全体を測定します。-p を指定して特定の pid にアタッチすることもできます。

-T オプションは、トランザクション・サイクルの数をレポートします。サイクル数が少ない場合、プログラムがロックで時間を費やしていないか、あるいはロックがインテル® TSX の HLE (Hardware Lock Elision) に対して有効になっていません。

-T オプションは、アボートしたサイクル、つまりコミットしなかったトランザクションで費やされたサイクルもレポートします。インテル® TSX のチューニングの目標は、サイクル数をできるだけ小さくする (トランザクションのコミットレートをできるだけ大きくする) ことです。

これらのサイクル数は、比較的長く実行するプロセスでのみ信頼すべきです。スタートアップには、後で消滅するさまざまな一時アボート (例えば、ワーキングセットのフォルト) が含まれます。アプリケーションのスタートアップ・フェーズにコストがかかる場合、-a または -p を並列に使用し、プログラムのスタートアップ・フェーズが終わった後に測定すると良いでしょう。

新しいバージョンの perf には、インターバル・サンプリングを行う -I オプションも用意されています。さまざまなフェーズを持つプログラムでは、このオプションを -T オプションとともに指定して、異なるフェーズを個別に測定できます。

-T オプションは、HLE (el) と RTM (tx)、およびそれらの平均トランザクション数もレポートします。一般に、トランザクションが極端に短くない場合は、このレポートが役立ちます。

perf stat -T のカウントのオーバーヘッドは一般に小さく、プログラムの実行時間に大きく影響することはありません。perf stat -T は、カーネルのトランザクションとユーザーのトランザクションの両方をカウントします。RTM が有効なカーネルでユーザー・プログラムのみを測定する場合、手動で perf stat -e と :u 修飾子 (ring 3 についてのみカウント) を使用して、-T オプションで使われるイベントを指定できます。さまざまな比率の計算が行われます。

不明なロックのプロファイリング

-T オプションでレポートされたトランザクションのサイクル数が低い場合、すべてのロックが無効になっていない可能性があります。これを確認するには、MEM_UOPS_RETIRED.LOCK_LOADS イベントをカウントして RTM_RETIRED.START または HLE_RETIRED.START と比較します。

perf stat -e '{r21d0,tx-start,el-start,cycles}' program

ロックの数が、開始したトランザクションの数よりも大幅に多い場合、すべてのロックが無効にされていない可能性があります。この場合、共通のロックをサンプリングして、共通のロックがすべて無効にされていることを確認します。

perf record -g -e r21d0:p …
perf report

perf レコード・サンプリングを用いたアボートのサンプリング

stat -T によるレポートでアボートしたサイクルの数が多い場合、サンプリングを用いてアボートの場所をプロファイルします。サンプリングしたときトランザクションはすでにアボートしているため、アボートのサンプリングはトランザクション・コミット・レートに影響しません (ただし、多少のオーバーヘッドは発生します)。

HLE と RTM は異なるサンプリング・イベントを使用します。perf stat -T は、HLE または RTM が使用されているかどうか (el-starts または tx-starts) をレポートします。el-starts が高い場合は el-aborts がアボートイベントで、tx-starts が高い場合は tx-aborts がアボートイベントです。両方を同時にサンプリングすることも可能ですが、必要ないイベントは指定しないことを推奨します。次の例は RTM アボートをサンプリングしています。

perf record -e cpu/tx-abort/pp program # measure program
perf record -e cpu/tx-abort/pp -a sleep 1 # measure whole system for 1 second
perf report # display samples

PEBS モニタリングは pp を指定して明示的に有効にする必要があります (そうでない場合はアボートハンドラーのみサンプリングされます)。アボートの場所を正確にプロファイルするには、この処理が必要です。イベントを別の方法で指定する場合、(:pp または precise=2 を使用して) precise を 2 にする必要があります。PEBS レコードには明示的に有効にしなければ得られない追加情報が含まれます。アボートの重要な情報は、ウェイト (–weight)、トランザクション・フラグ、(–transaction)、コールチェーン (-g) です。

プログラム側ではデバッグ情報とシンボルテーブルを準備しておく必要があります。-g でコンパイルしてオブジェクト・ファイルを作成するか、ディストリビューション・プログラム向けのデバッグ情報パッケージをインストールします。これによりシンボルが表示され、個々の行でサンプル結果を参照できます。ソースコードがシステムで利用可能な場合、perf はソースリスト・レベルでサンプルをレポートできます。

デフォルトでは、アセンブラー・コードは AT&T 形式で表示されます。インテル形式で表示するには、perf record で -M intel を指定します。概要ではシンボル順でサンプルが表示されます。下記の sort 引数に srcline を追加すると、ソース行順にレポートすることもできます。

追加情報は、–sort コマンドで明示的に指定します。

perf record -g --transaction --weight -e cpu/tx-abort/pp program
perf report --sort symbol,transaction,weight

トランザクション・ウェイトは、アボート前にトランザクションが費やすサイクルのグローバルコストです。高いウェイトのアボートはよりコストがかかります。現在の perf バージョンはウェイト順でソートしないため、トップのエントリーのコストが最も高いとは限らないことに注意してください。ウェイトのグローバルな合計である global_weight と、サンプルの平均ウェイトである local_weight があります。デフォルトのウェイトは global です。

perf は現在ウェイトでサンプルを分割しているため、エントリーは多くなります。ウェイトを確認した後、ソートキーから削除すると出力を減らせます。

トランザクション・フラグはアボートタイプを示します。チューニング手法はアボートタイプに応じて異なります。

名前

説明

EL

HLE トランザクションでアボート。

TX

RTM トランザクションでアボート。

SYNC

同期アボート。アボートは指定された命令 (例えば、システムコールやその他の不正な命令) によって発生しました (仕様の 15.3.8.1 を参照)。

ASYNC

非同期アボート。アボートは別のスレッドによって発生し、ポイントされた命令はそのときにたまたま実行されていたものです。

RETRY

トランザクションはリトライ可能。

CON

競合: アボートは書き込み競合によって発生しました。通常は別のスレッドによって発生します。発生する場所はトランザクション中でランダムですが、競合が発生するパターンに近い場所でしばしば発生します。

CAP-WRITE

処理能力: アボートはトランザクションの最大書き込みバッファー処理能力を超えたローカル・トランザクションによって発生しました。

CAP-READ

処理能力: アボートはトランザクションの最大読み込みバッファー処理能力を超えたローカル・トランザクションによって発生しました。まれに、別のアボートタイプによって発生することもあります。

   

:NUMBER

アボートコード。プログラムは XABORT 命令で明示的にアボートしました (コード NUMBER)。一般的なコードは 0xff (ロックがロック・ライブラリーでビジー、つまりロックが長時間無効にされていない) です。

プログラムのコンテキストを理解するにはコールチェーンが役立ちます。レコードのコールチェーン (-g) オプションを使用するには、-fno-omit-frame-pointer を指定してプログラムおよびライブラリーをコンパイルするか、perf で -g dwarf を使用します (dwarf2 のアンワインド情報が利用可能な場合)。dwarf2 を使用すると、フレームポインターを用いる場合よりも遅くなります。また、アンワインド・ライブラリーを使って perf ツールをコンパイルする必要があります。

アボートのコールチェーンは、トランザクションが (通常はロック・ライブラリーで) アボートした後にのみ記録されます。サンプルヒットは実際のアボートポイントです。このため、コールチェーンは不連続であり、アボートポイントで始まり、ロック・ライブラリーのロック関数のコールグラフに続きます。これは、トランザクションをヒットしていないサンプルとは異なるため、コールグラフを見るときは注意が必要です。

非同期 (および処理能力への影響が小さい) アボートは、特定のアボートポイントではなく、クリティカル・セクション全体を見ると良いでしょう。アボートは別のプロセッサー・コアによってトリガーされ、トランザクションでランダムに表示されるため、サンプルでレポートされる命令はアボートの原因と関係がないこともあります。トランザクション全体のメモリーアクセスを行うには、読み取り-書き込みまたは書き込み-読み取りのメモリー共有を最小限に抑えます。アボートのリターン IP をサンプリングするか、tx-aborts-count や el-aborts-count をコールグラフとともに使用してください。インライン展開されていないロックの場合、通常はロック・ライブラリー外部の最初の呼び出し元がクリティカル・セクションを定義します。非 PEBS * カウントイベントは、ウェイトとトランザクション・フラグをサポートしません。これらのイベントでリターン IP が必要な場合は、これらのアボートイベントの非 eventingrip PEBS バージョン、r4c8:p (HLE アボート) または r4c9:p (RTM アボート) を使用します。現在はロー形式のみ存在しますが、将来の perf バージョンでは変更される可能性があります。

LBR (Last Branch Records: 最終分岐レコード) によるトランザクション内部の確認

アボートの原因となるトランザクション内部の制御フローを確認するには、LBR を使用します。LBR が有効な場合、プロセッサーは最後の 16 の分岐を LBR レジスターにストアします。perf record でアボートの LBR をサンプリングするには、-b オプションを指定します。デフォルト表示は、基本ブロック・ヒストグラムが使用され、すべてのパスが折りたたまれているため、個々のアボートサンプルの解析には適していません。回避策は、perf report -D を用いてサンプルから LBR を手動で抽出し、addr2line でアドレスを変換することです。将来の perf バージョンではこの処理が改善される見込みです。

更新情報: perf report に –branch–call-graph オプションを追加するパッチキット (http://comments.gmane.org/gmane.linux.kernel/1626721) が提供されています。

追加のインテル® TSX イベントと修飾子

perf には、インテル® TSX 向けの組込みイベントがいくつかあります。カウントイベントは HLE と RTM では別です。利用可能なすべての組込みイベントは “perf list” でリストできます。アボートイベントを除いて、これらのイベントは precise ではありません。これらは、perf report でトランザクションにヒットしたとき、アボート後の命令をレポートするため、ほとんどの場合有用ではありません。

RTM イベント

HLE イベント

説明

cpu/tx-abort/pp

cpu/el-abort/pp

サンプリングの precise アボートイベント。アボートの場所をプロファイルするときに使用します。

tx-abort

el-abort

PEBS を使用しないカウントのアボートイベント。このイベントは、precise バージョンの代わりに perf stat で使用します。アボートポイントではなく、HLE のアボートハンドラーまたはオリジナルロックのポイントをサンプリングします。

tx-capacity

el-capacity バッファー処理能力を超えたトランザクション。precise ではありません。カウントに使用します。

tx-commit

el-commit

成功したトランザクション・コミット。

tx-start

el-start

トランザクション開始。カウントにのみ使用します。

tx-conflict

el-conflict

メモリー競合によるアボート。カウントにのみ使用します。

cycles-t

トランザクション・サイクル数。カウントにのみ使用します。

cycles-ct

トランザクション・サイクル数 – アボートしたトランザクションのサイクル数 (コミットしたサイクル数)。カウントにのみ使用します。

cpu/instructions,in_tx=1/

トランザクション命令数。カウントにのみ使用します。

cpu/instructions,in_tx=1,in_tx_cp=1/

トランザクション命令数 – アボートした命令数 (コミットした命令数)。カウントにのみ使用します。

処理能力と競合のアボートを解析する場合、–transaction を使用してアボートをサンプリングし、サンプルブラウザーでトランザクション・アボート・タイプを調べます。これらのイベントの多くは、追加のアボートが発生しないカウント (perf stat) で有用です。

perf でローイベントを指定する

perf には限られた組込みイベントリストしかありません。その他のイベントはロー 16 進形式で指定します。

rUUEE

EE は 16 進のイベント修飾子、UU はユニットマスクです。Haswell アーキテクチャーの有効なイベントのリストは、『Intel® 64 and IA-32 Architectures Software Developer’s Manual』を参照してください。追加の修飾子はマスクに追加できます。例えば、0x100000000 はトランザクション内のみのイベントをカウントし、0x200000000 は checkpointed イベントを設定します (詳細は 『Intel® 64 and IA-32 Architectures Software Developer’s Manual』のセクション 18.10.5 を参照)。ローマスクは、パフォーマンス・カウンターの制御レジスターに直接マップされます。

perf のいくつかのフロントエンドは、この複雑なプロシージャーを回避する、フル・シンボリック・イベント・リスト (pmu-tools の ocperf など) を提供します。ocperf は、後で使用するローイベント文字列も生成できます。

perf は、4 つ (非ハイパースレッディングの場合は 8 つ) 以上のカウンターを並列に実行するため、イベントの多重化をサポートしています。イベントが互いに依存する式で使用される場合、式のすべてのイベントを同時に実行することは重要です。一度に複数のグループを実行するには、{} でイベントグループを指定して多重化します。

perf stat -e '{cycles,cycles-t,cycles-ct}' program
perf stat -e '{r154,r254,r21d0},{r1c9,r1c8,4c8,r4c9}' -p PID

新しい perf バージョンでは、より情報の多い構文も利用できます。

perf stat -e 'cpu/event=0x12,umask=0x34,intx=1,intx_cp=1/' -a sleep 1

イベントがプログラムで事前に処理される場合、perf stat (-x,) で CSV モードを有効にできます。

さまざまなアボート条件を診断するインテル® TSX 向けのローイベント

これらのイベントのほとんどは投機的で、多めにカウントされます。また、precise ではなく、アボート後の IP のみレポートします。特定のアボートの原因をカウントするのに使用できます。ほとんどの場合、tx-abort/el-abort PEBS サンプリングからアボートを解析するための優れた代案であり、ソース行で実行できます。HLE イベントは、新しい HLE が有効なロック・ライブラリーをデバッグするときに特定の HLE コミット問題を確認するのに便利です。

SDM 名

perf ローイベント

説明

tx_exec.misc4

r85d

HLE を RTM 内部で実行しました。あるいはその他の稀なアボートが発生しました。

tx_exec.misc3

r45d

トランザクションの入れ子の制限を超えました。あるいはその他の稀なアボートが発生しました。

tx_mem.abort_hle_elision_buffer_full

r4054

HLE の入れ子が深すぎます。

tx_mem.abort_hle_elision_buffer_unsupported_alignment

r2054

サポートされていないアライメントを使用して HLE 領域内部のロックの値を読み取りました。

tx_mem.abort_hle_elision_buffer_mismatch

r1054

XRELEASE のアドレスまたは値が XACQUIRE と一致しません。

tx_mem.abort_hle_elision_buffer_not_empty

r854

一致する XACQUIRE がない HLE XRELEASE です。

tx_mem.abort_hle_store_to_elided_lock

r454

HLE 領域内部のロックへのストアです。

この他にも便利な perf イベントがあります。ソフトウェア・トレース・ポイントを使用するには、root として実行するか、/proc/sys/kernel/debug/tracing を読み取り可能にする必要があります。また、カーネルがシステムコールのトレースをサポートしていなければいけません。利用可能なイベントの詳細は、“perf list” で確認できます。

名前

perf イベント

説明

syscalls:sys_enter_futex

syscalls:sys_enter_futex

futex syscalls をカウントします。スリープしている futex ロック(例: pthread mutex) がブロックされる頻度を概算できます。別のスレッドが待機している場合、アンロックのロック・ウェイクアップもカウントします。アダプティブ pthread mutex では、競合を少なくカウントします。

mem_uops_retired.lock_loads

r21d0

アトミック操作をカウントします。無効にされていないロックを調べるときに便利です。サンプリングに PEBS イベント (:p) として使用できます。

多重化と一緒に使用しないでください。

コンパイラーの最適化に関する詳細は、最適化に関する注意事項を参照してください。

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