llvm-exegesis - LLVMマシン命令ベンチマーク¶
概要¶
llvm-exegesis [オプション]
説明¶
llvm-exegesisは、LLVMで利用可能な情報を使用して、レイテンシ、スループット、ポート分解などのホストマシン命令の特性を測定するベンチマークツールです。
LLVM opcode名とベンチマークモードが与えられると、llvm-exegesisは、命令のレイテンシ(それぞれ逆スループット/uop分解)を測定できるように、実行を可能な限りシリアル(それぞれ並列)にするコードスニペットを生成します。コードスニペットはJITコンパイルされ、要求されない限り、ホストサブターゲット上で実行されます。実行にかかった時間(それぞれリソース使用量)は、ハードウェアパフォーマンスカウンターを使用して測定されます。結果はYAMLとして標準出力に出力されます。
このツールの主な目標は、LLVMのTableDefスケジューリングモデルを自動的に検証(または無効化)することです。そのため、結果の分析も提供しています。
llvm-exegesisは、ユーザーが提供した任意のコードスニペットをベンチマークすることもできます。
対応プラットフォーム¶
llvm-exegesisは現在、ベンチマーク用にLinux上のX86(64ビットのみ)、ARM(AArch64のみ)、MIPS、およびPowerPC(PowerPC64LEのみ)をサポートしています。すべてのベンチマーク機能がすべてのプラットフォームで動作するとは限りません。llvm-exegesisには、LLVMがサポートされているすべてのプラットフォームでサポートされている別の分析モードもあります。
スニペットアノテーション¶
llvm-exegesisは、任意のアセンブリのスニペットのベンチマークをサポートしています。ただし、これらのスニペットをベンチマークするには、正しく実行できるようにセットアップが必要になることがよくあります。llvm-exegesisには、スニペットを適切にベンチマークできるようにするための5つのアノテーションといくつかの追加ユーティリティがあります。
LLVM-EXEGESIS-DEFREG <レジスタ名> - ベンチマーク対象のテキストアセンブリ スニペットにこのアノテーションを追加すると、レジスタが定義を必要とするものとしてマークされます。2番目のパラメータである16進値が渡されない限り、値は自動的に提供されます。これは、LLVM-EXEGESIS-DEFREG <レジスタ名> <16進値>形式で行われます。<16進値>は、レジスタを埋めるために使用されるビットパターンです。レジスタよりも小さい値の場合、レジスタのサイズに合わせて符号拡張されます。
LLVM-EXEGESIS-LIVEIN <レジスタ名> - このアノテーションを使用すると、ベンチマークの開始時に値を保持する必要があるレジスタを指定できます。場合によっては、レジスタを介してベンチマーク設定から値を渡すことができます。LLVM-EXEGESIS-LIVEINを使用してベンチマークスクリプトで利用できるレジスタとそれに割り当てられた値は次のとおりです。
スクラッチメモリレジスタ - この値が配置される特定のレジスタはプラットフォームに依存します(たとえば、X86 LinuxではRDIレジスタです)。このレジスタをライブインとして設定すると、スニペットで使用できるメモリブロック(1MB)へのポインタがこのレジスタ内に配置されます。
LLVM-EXEGESIS-MEM-DEF <値名> <サイズ> <値> - このアノテーションを使用すると、後でLLVM-EXEGESIS-MEM-MAPアノテーションを使用してスニペットの実行プロセスにマップできるメモリ定義を指定できます。各値には、<値名>引数を使用して名前が付けられ、後でマップアノテーション内で参照できます。サイズは10進数のバイト数で指定され、値は16進数で指定されます。値のサイズが指定されたサイズよりも小さい場合、メモリセクション全体が埋まるまで値が繰り返されます。このアノテーションを使用するには、サブプロセス実行モードを使用する必要があります。
LLVM-EXEGESIS-MEM-MAP <値名> <アドレス> - このアノテーションを使用すると、以前に定義されたメモリ定義をプロセスの実行コンテキストにマップできます。値名は以前に定義されたメモリ定義を参照し、アドレスはメモリ定義を開始するアドレスを指定する10進数です。単一のメモリ定義を複数回マップできることに注意してください。このアノテーションを使用するには、サブプロセス実行モードが必要です。
LLVM-EXEGESIS-SNIPPET-ADDRESS <アドレス> - このアノテーションを使用すると、実行されるスニペットの先頭がマップされるアドレスを設定できます。アドレスは16進数で指定されます。スニペットにはセットアップコードも含まれているため、指定されたアドレスにある命令がスニペットの最初の命令になるとは限らないことに注意してください。このアノテーションを使用するには、サブプロセス実行モードが必要です。これは、RIP相対アドレッシングのように、スニペットによってアクセスされるメモリがスニペットの場所に依存する場合に役立ちます。
LLVM-EXEGESIS-LOOP-REGISTER <レジスタ名> - このアノテーションは、ループ反復モードを使用する場合に現在の反復を追跡するために使用するループレジスタを指定します。 llvm-exegesisは、ループ反復モード内で現在のループ反復を効率的な方法(つまり、メモリアクセスなし)で追跡する必要があり、これを行うためにレジスタを使用します。このレジスタにはアーキテクチャ固有のデフォルト(たとえば、X86ではR8)がありますが、これは一部のスニペットと競合する可能性があります。このアノテーションを使用すると、ループインデックスレジスタとスニペット間の干渉を防ぐためにレジスタを変更できます。
例1:命令のベンチマーク¶
X86-64マシンがあるとします。単一命令のレイテンシを測定するには、次を実行します。
$ llvm-exegesis --mode=latency --opcode-name=ADD64rr
命令のuop分解または逆スループットの測定も同様に機能します
$ llvm-exegesis --mode=uops --opcode-name=ADD64rr
$ llvm-exegesis --mode=inverse_throughput --opcode-name=ADD64rr
出力はYAMLドキュメントです(デフォルトはstdoutに書き込みますが、–benchmarks-fileを使用して出力をファイルにリダイレクトできます)
---
key:
opcode_name: ADD64rr
mode: latency
config: ''
cpu_name: haswell
llvm_triple: x86_64-unknown-linux-gnu
num_repetitions: 10000
measurements:
- { key: latency, value: 1.0058, debug_string: '' }
error: ''
info: 'explicit self cycles, selecting one aliasing configuration.
Snippet:
ADD64rr R8, R8, R10
'
...
ホストアーキテクチャのすべての命令のレイテンシを測定するには、次を実行します
$ llvm-exegesis --mode=latency --opcode-index=-1
例2:カスタムコードスニペットのベンチマーク¶
カスタムコードのレイテンシ/ uopsを測定するには、snippets-fileオプションを指定します(-は標準入力から読み取ります)。
$ echo "vzeroupper" | llvm-exegesis --mode=uops --snippets-file=-
実際のコードスニペットは、通常、レジスタまたはメモリに依存します。 llvm-exegesisは、レジスタの活性度をチェックします(つまり、レジスタの使用には対応する定義があるか、「ライブイン」です)。コードが一部のレジスタの値に依存している場合は、スニペットアノテーションを使用してセットアップが正しく実行されるようにする必要があります。
たとえば、次のコードスニペットは、XMM1(ツールによって設定されます)とRDI(ライブイン)で渡されるメモリバッファの値に依存しています。
# LLVM-EXEGESIS-LIVEIN RDI
# LLVM-EXEGESIS-DEFREG XMM1 42
vmulps (%rdi), %xmm1, %xmm2
vhaddps %xmm2, %xmm2, %xmm3
addq $0x10, %rdi
例3:メモリアノテーションを使用したベンチマーク¶
一部のスニペットは、クラッシュせずに実行するために特定の場所にメモリを設定する必要があります。メモリのセットアップは、LLVM-EXEGESIS-MEM-DEFおよびLLVM-EXEGESIS-MEM-MAPアノテーションを使用して実行できます。次のスニペットを実行するには
movq $8192, %rax
movq (%rax), %rdi
0x2000から始まる少なくとも8バイトのメモリを割り当てる必要があります。スニペットに追加された次のアノテーションを使用して、必要な実行環境を作成できます
# LLVM-EXEGESIS-MEM-DEF test1 4096 7fffffff
# LLVM-EXEGESIS-MEM-MAP test1 8192
movq $8192, %rax
movq (%rax), %rdi
例4:分析¶
ファイル/tmp/benchmarks.yamlにYAMLとしてベンチマークされた命令のセット(レイテンシまたはuops)があると仮定すると、次のコマンドを使用して結果を分析できます
$ llvm-exegesis --mode=analysis \
--benchmarks-file=/tmp/benchmarks.yaml \
--analysis-clusters-output-file=/tmp/clusters.csv \
--analysis-inconsistencies-output-file=/tmp/inconsistencies.html
これにより、命令は同じパフォーマンス特性を持つクラスターにグループ化されます。クラスターは、次の形式で/tmp/clusters.csvに書き込まれます
cluster_id,opcode_name,config,sched_class
...
2,ADD32ri8_DB,,WriteALU,1.00
2,ADD32ri_DB,,WriteALU,1.01
2,ADD32rr,,WriteALU,1.01
2,ADD32rr_DB,,WriteALU,1.00
2,ADD32rr_REV,,WriteALU,1.00
2,ADD64i32,,WriteALU,1.01
2,ADD64ri32,,WriteALU,1.01
2,MOVSX64rr32,,BSWAP32r_BSWAP64r_MOVSX64rr32,1.00
2,VPADDQYrr,,VPADDBYrr_VPADDDYrr_VPADDQYrr_VPADDWYrr_VPSUBBYrr_VPSUBDYrr_VPSUBQYrr_VPSUBWYrr,1.02
2,VPSUBQYrr,,VPADDBYrr_VPADDDYrr_VPADDQYrr_VPADDWYrr_VPSUBBYrr_VPSUBDYrr_VPSUBQYrr_VPSUBWYrr,1.01
2,ADD64ri8,,WriteALU,1.00
2,SETBr,,WriteSETCC,1.01
...
llvm-exegesisはクラスターも分析して、スケジューリング情報における不整合を指摘します。出力はhtmlファイルです。たとえば、/tmp/inconsistencies.htmlには、次のようなメッセージが含まれます。

スケジューリングクラス名は、llvm-exegesisがデバッグモードでコンパイルされた場合にのみ解決され、それ以外の場合はクラスIDのみが表示されることに注意してください。ただし、これは分析結果のいずれも無効にしません。
オプション¶
- --help¶
コマンドラインオプションの概要を出力します。
- --opcode-index=<LLVM opcode index>¶
測定するopcodeをインデックスで指定します。-1を指定すると、既存のすべてのopcodeが測定されます。詳細は例1を参照してください。opcode-index、opcode-name、またはsnippets-fileのいずれかを設定する必要があります。
- --opcode-name=<opcode name 1>,<opcode name 2>,...¶
測定するopcodeを名前で指定します。複数のopcodeをカンマ区切りのリストとして指定できます。詳細は例1を参照してください。opcode-index、opcode-name、またはsnippets-fileのいずれかを設定する必要があります。
- --snippets-file=<filename>¶
測定するカスタムコードスニペットを指定します。詳細は例2を参照してください。opcode-index、opcode-name、またはsnippets-fileのいずれかを設定する必要があります。
- --mode=[latency|uops|inverse_throughput|analysis]¶
実行モードを指定します。一部のモードには追加の要件とオプションがあることに注意してください。
latencyモードでは、RDTSCまたはLBRを使用できます。 latency[LBR]は、X86(少なくともSkylake)でのみ使用できます。latencyモードで実行するには、x86-lbr-sample-periodに正の値を指定し、–repetition-mode=loopを指定する必要があります。
analysisモードでは、-analysis-clusters-output-file=と-analysis-inconsistencies-output-file=の少なくとも一方も指定する必要があります。
- --benchmark-phase=[prepare-snippet|prepare-and-assemble-snippet|assemble-measured-code|measure]¶
デフォルトでは、-mode= が指定された場合、生成されたスニペットは実行および測定されます。そのためには、スニペットが生成されたハードウェア上で実行し、パフォーマンス測定をサポートしている必要があります。ただし、測定前の段階で停止することも可能です。選択肢は以下のとおりです。 *
prepare-snippet
: 最小限の命令シーケンスのみを生成します。 *prepare-and-assemble-snippet
:prepare-snippet
と同じですが、シーケンスの一部(16進数エンコード)もダンプします。 *assemble-measured-code
:prepare-and-assemble-snippet
と同じですが、--dump-object-to-disk
を使用してファイルにダンプできる完全なシーケンスも作成します。 *measure
:assemble-measured-code
と同じですが、測定も実行します。
- --x86-lbr-sample-period=<分岐数/サンプル>¶
LBR サンプリング周期(サンプルを取得するまでの分岐数)を指定します。このオプションに正の値が指定され、モードが latency の場合、測定に LBR を使用します。「適切な」サンプリング周期を選択する場合、小さい値が推奨されますが、サンプリングが頻繁すぎるとスロットリングが発生する可能性があります。特定のブロックを常にスキップしないように、素数を使用する必要があります。
- --x86-disable-upper-sse-registers¶
上位 xmm レジスタ (xmm8-xmm15) を使用すると、命令エンコーディングが長くなり、フロントエンドのフェッチおよびデコードステージに大きな負荷がかかり、特に古いハードウェアでは、命令がバックエンドにディスパッチされる速度が低下する可能性があります。このモードを有効にした場合のベースライン結果と比較することで、フロントエンドの影響を判断し、レイテンシとスループットの推定値を改善するために使用できます。
- --repetition-mode=[duplicate|loop|min|middle-half-duplicate|middle-half-loop]¶
繰り返しモードを指定します。duplicate は、min-instructions 個の命令を持つ大きな直線的な基本ブロックを作成します(スニペットを min-instructions/snippet size 回繰り返します)。loop は、オプションで、ループ本体に少なくとも loop-body-size 個の命令が含まれるまでスニペットを複製し、結果を min-instructions 個の命令を実行するループでラップします(したがって、スニペットを min-instructions/snippet size 回繰り返します)。loop モードは、特にループ展開を使用すると、デコードされた命令をキャッシュするアーキテクチャでは CPU フロントエンドの影響を隠蔽するのに優れていますが、反復カウント用のレジスタを消費します。多くのオペコードに対して分析を実行する場合は、代わりに min モードを使用することをお勧めします。このモードでは、他の各モードを実行し、測定された最小の結果を生成します。中間半分繰り返しモードは、特定のモードに応じて、スニペットを複製するかループで実行します。中間半分繰り返しモードは、2つのベンチマークを実行します。1つは最初の2倍の長さで、次にそれらの差を差し引いてオーバーヘッドのない値を取得します。
- --min-instructions=<命令数>¶
実行される命令の目標数を指定します。スニペットの実際の繰り返し回数は min-instructions/snippet size になることに注意してください。値が大きいほど測定の精度が上がりますが、ベンチマークが長くなります。
- --loop-body-size=<推奨ループ本体サイズ>¶
-repetition-mode=[loop|min] の場合にのみ有効です。スニペットを直接ループする代わりに、最初に複製してループ本体に少なくともこの数の命令が含まれるようにします。これにより、ループ本体が CPU Op Cache / Loop Cache にキャッシュされる可能性があり、CPU デコーダよりも高いスループットを実現できます。
- --max-configs-per-opcode=<値>¶
各オペコードに対して生成できる最大構成数を指定します。デフォルトでは 1 です。これは、1回の測定でオペコードを特徴付けるのに十分であると想定していることを意味します。これはすべての命令に当てはまるとは限りません。たとえば、X86 の LEA 命令のパフォーマンス特性は、割り当てられたレジスタと即値の値に依存します。-max-configs-per-opcode に 1 より大きい値を設定すると、llvm-exegesis はより多くの構成を探索して、一部のレジスタまたは即値の割り当てが異なるパフォーマンス特性につながるかどうかを検出できます。
- --benchmarks-file=<ファイルへのパス>¶
ベンチマーク結果を読み取る(analysis モード)または書き込む(latency/uops/inverse_throughput モード)ファイル。“-” は stdin/stdout を使用します。
- --analysis-clusters-output-file=<ファイルへのパス>¶
指定した場合、分析クラスタを CSV としてこのファイルに書き込みます。“-” は stdout に出力します。デフォルトでは、この分析は実行されません。
- --analysis-inconsistencies-output-file=<ファイルへのパス>¶
空でない場合、分析中に見つかった不整合をこのファイルに書き込みます。- は stdout に出力します。デフォルトでは、この分析は実行されません。
- --analysis-filter=[all|reg-only|mem-only]¶
デフォルトでは、すべてのベンチマーク結果が分析されますが、メモリを伴わない結果のみ、またはその逆を見る方が便利な場合があります。このオプションを使用すると、すべてのベンチマークを保持するか、メモリに関連するもの(メモリを読み書きする可能性のある命令を含むもの)をすべて除外(無視)するか、またはその反対に、そのようなベンチマークのみを保持することができます。
- --analysis-clustering=[dbscan,naive]¶
使用するクラスタリングアルゴリズムを指定します。デフォルトでは DBSCAN が使用されます。ナイーブクラスタリングアルゴリズムは、-analysis-inconsistencies-output-file= 出力に対してさらに作業を行うのに適しており、オペコードごとに1つのクラスタを作成し、クラスタが安定している(すべてのポイントが隣接している)ことを確認します。
- --analysis-numpoints=<dbscan numPoints パラメータ>¶
DBSCAN クラスタリング(analysis モード、DBSCAN のみ)に使用する numPoints パラメータを指定します。
- --analysis-clustering-epsilon=<dbscan epsilon パラメータ>¶
ベンチマークポイントのクラスタリングに使用される epsilon パラメータを指定します(analysis モード)。
- --analysis-inconsistency-epsilon=<epsilon>¶
クラスタが LLVM スケジュールプロファイル値と異なる場合の検出に使用される epsilon パラメータを指定します(analysis モード)。
- --analysis-display-unstable-clusters¶
オペコードに複数のベンチマークがある場合、測定されたパフォーマンス特性が異なる場合、それらのベンチマークは同じクラスタにクラスタリングされない可能性があります。デフォルトでは、そのようなすべてのオペコードは除外されます。このフラグは、代わりにそのような不安定なオペコードのみを表示します。
- --ignore-invalid-sched-class=false¶
設定されている場合、スケジュールクラスを持たない命令を無視します(クラス idx = 0)。
- --mtriple=<トリプル名>¶
ターゲットトリプル。使用可能なターゲットについては、-version を参照してください。
- --mcpu=<CPU 名>¶
設定されている場合、この CPU のカウンタを使用して CPU 特性を測定します。これは、新しいスケジュールモデルを作成する場合に役立ちます(ホスト CPU は LLVM に認識されていません)。(詳細は -mcpu=help を参照してください)
- --analysis-override-benchmark-triple-and-cpu¶
デフォルトでは、llvm-exegesis は測定されたトリプル/ CPU のベンチマークを分析しますが、他の組み合わせ(-mtriple/-mcpu で指定)で分析する場合は、このフラグを渡すことができます。
- --dump-object-to-disk=true¶
設定されている場合、llvm-exegesis は生成されたコードを一時ファイルにダンプしてコード検査を可能にします。デフォルトでは無効になっています。
- --use-dummy-perf-counters¶
設定されている場合、llvm-exegesis は実際のパフォーマンスカウンタを読み取らず、代わりにダミー値を返します。これは、ハードウェアパフォーマンスカウンタが使用できない場合にスニペットがクラッシュしないようにするため、および llvm-exegesis 自体のデバッグに使用できます。
- --execution-mode=[inprocess,subprocess]¶
このオプションは、使用する実行モードを指定します。inprocess 実行モードがデフォルトです。subprocess 実行モードでは、メモリアノテーションなどの追加機能を使用できますが、現在は Linux の X86-64 に制限されています。
- --benchmark-repeat-count=<repeat-count>¶
このオプションは、レイテンシ測定を実行する際の測定の繰り返し回数を指定できます。デフォルトでは、llvm-exegesis は実行時間とノイズ低減のバランスを取るのに十分な回数、レイテンシ測定を繰り返します。
- --validation-counter=[instructions-retired,l1d-cache-load-misses,¶
- l1d-cache-store-misses,l1i-cache-load-misses,data-tlb-load-misses,¶
- data-tld-store-misses,instruction-tlb-load-misses]¶
このオプションは、キャッシュミスなどの追加のマイクロアーキテクチャイベントを測定して、スニペット実行条件を検証する検証カウンターの使用を有効にします。これらのイベントは、perf サブシステムを使用して、対象の値を測定するために使用されるパフォーマンスカウンターと同じグループで測定されます。このフラグは、複数のイベントを測定するために複数回指定できます。検証カウンターの最大数はプラットフォームに依存します。
終了ステータス¶
llvm-exegesis は、成功すると 0 を返します。それ以外の場合は、エラーメッセージが標準エラーに出力され、ツールは 0 以外の値を返します。