llvm-mca - LLVM 機械コードアナライザー¶
概要¶
llvm-mca [オプション] [入力]
説明¶
llvm-mca は、LLVM で利用可能な情報 (例: スケジューリングモデル) を使用して、特定の CPU での機械コードのパフォーマンスを静的に測定するパフォーマンス分析ツールです。
パフォーマンスは、スループットとプロセッサのリソース消費量の両方の観点から測定されます。このツールは現在、LLVM にスケジューリングモデルが利用可能なバックエンドを持つプロセッサで動作します。
このツールの主な目標は、ターゲットで実行した場合のコードのパフォーマンスを予測するだけでなく、潜在的なパフォーマンスの問題を診断するのに役立つことです。
アセンブリコードのシーケンスが与えられた場合、llvm-mca は、ハードウェアリソースのプレッシャーと同様に、命令/サイクル数 (IPC) を推定します。分析とレポートのスタイルは、Intel の IACA ツールに触発されています。
たとえば、clang でコードをコンパイルし、アセンブリを出力し、それを直接 llvm-mca にパイプして分析できます
$ clang foo.c -O2 --target=x86_64 -S -o - | llvm-mca -mcpu=btver2
または、Intel 構文の場合
$ clang foo.c -O2 --target=x86_64 -masm=intel -S -o - | llvm-mca -mcpu=btver2
(llvm-mca は、入力の先頭に .intel_syntax ディレクティブが存在することによって Intel 構文を検出します。デフォルトでは、その出力構文は入力の構文と一致します。)
スケジューリングモデルは、命令のレイテンシとスループットを計算するだけでなく、利用可能なプロセッサリソースを理解し、それらをシミュレートする方法を理解するためにも使用されます。
設計上、llvm-mca によって実施される分析の質は、必然的に LLVM のスケジューリングモデルの質の影響を受けます。
プロセッサのパフォーマンスレポートが正確でない場合は、適切なバックエンドに対して バグをファイルしてください。
オプション¶
入力
が "-
" であるか省略されている場合、llvm-mca は標準入力から読み取ります。それ以外の場合は、指定されたファイル名から読み取ります。
-o
オプションが省略されている場合、llvm-mca は、入力が標準入力からのものである場合、その出力を標準出力に送信します。-o
オプションが "-
" を指定する場合、出力も標準出力に送信されます。
- -help¶
コマンドラインオプションの概要を出力します。
- -o <ファイル名>¶
出力ファイル名として
<ファイル名>
を使用します。詳細については、上記の概要を参照してください。
- -mtriple=<ターゲットトリプル>¶
ターゲットトリプル文字列を指定します。
- -march=<アーキテクチャ>¶
コードを分析するアーキテクチャを指定します。デフォルトはホストのデフォルトターゲットです。
- -mcpu=<cpuname>¶
コードを分析するプロセッサを指定します。デフォルトでは、CPU 名はホストから自動検出されます。
- -output-asm-variant=<バリアント ID>¶
ツールによって生成されたレポートの出力アセンブリバリアントを指定します。x86 では、可能な値は [0, 1] です。このフラグの値が 0 (vic. 1) の場合、分析レポートでツールによって出力されたコードに AT&T (vic. Intel) アセンブリ形式が有効になります。
- -print-imm-hex¶
レポートの一部として出力されるアセンブリの数値リテラルには、16進形式を優先します。
- -dispatch=<幅>¶
プロセッサの別のディスパッチ幅を指定します。ディスパッチ幅は、プロセッサのスケジューリングモデルのフィールド 'IssueWidth' にデフォルト設定されます。幅がゼロの場合、デフォルトのディスパッチ幅が使用されます。
- -register-file-size=<サイズ>¶
レジスタファイルのサイズを指定します。指定した場合、このフラグは、レジスタの名前変更に使用できる物理レジスタの数を制限します。このフラグの値がゼロの場合、「物理レジスタの数に制限がない」ことを意味します。
- -iterations=<反復回数>¶
実行する反復回数を指定します。このフラグが 0 に設定されている場合、ツールは反復回数をデフォルト値 (つまり 100) に設定します。
- -noalias=<bool>¶
設定した場合、ツールはロードとストアがエイリアスではないと想定します。これはデフォルトの動作です。
- -lqueue=<ロードキューサイズ>¶
ツールによってエミュレートされるロード/ストアユニットのロードキューのサイズを指定します。デフォルトでは、ツールはロードキューのエントリ数が無制限であると想定します。このフラグの値がゼロの場合、無視され、代わりにデフォルトのロードキューサイズが使用されます。
- -squeue=<ストアキューサイズ>¶
ツールによってエミュレートされるロード/ストアユニットのストアキューのサイズを指定します。デフォルトでは、ツールはストアキューのエントリ数が無制限であると想定します。このフラグの値がゼロの場合、無視され、代わりにデフォルトのストアキューサイズが使用されます。
- -timeline¶
タイムラインビューを有効にします。
- -timeline-max-iterations=<反復回数>¶
タイムラインビューで出力する反復回数を制限します。デフォルトでは、タイムラインビューは最大10回の反復の情報が出力されます。
- -timeline-max-cycles=<サイクル数>¶
タイムラインビューのサイクル数を制限するか、制限しない場合は 0 を使用します。デフォルトでは、サイクル数は 80 に設定されています。
- -resource-pressure¶
リソースプレッシャービューを有効にします。これはデフォルトで有効になっています。
- -register-file-stats¶
レジスタファイルの使用状況統計を有効にします。
- -dispatch-stats¶
追加のディスパッチ統計を有効にします。このビューは、静的/動的ディスパッチストールイベントだけでなく、命令ディスパッチイベントを収集して分析します。このビューはデフォルトで無効になっています。
- -scheduler-stats¶
追加のスケジューラ統計を有効にします。このビューは、命令発行イベントを収集して分析します。このビューはデフォルトで無効になっています。
- -retire-stats¶
追加のリタイア制御ユニットの統計を有効にします。このビューはデフォルトで無効になっています。
- -instruction-info¶
命令情報ビューを有効にします。これはデフォルトで有効になっています。
- -show-encoding¶
命令情報ビュー内の命令エンコードの印刷を有効にします。
- -show-barriers¶
命令情報ビュー内の LoadBarrier および StoreBarrier フラグの印刷を有効にします。
- -all-stats¶
すべてのハードウェア統計を出力します。これにより、ディスパッチロジック、ハードウェアスケジューラ、レジスタファイル、およびリタイア制御ユニットに関連する追加の統計が有効になります。このオプションはデフォルトで無効になっています。
- -all-views¶
すべてのビューを有効にします。
- -instruction-tables¶
プロセッサモデルから利用可能な静的情報に基づいて、リソースプレッシャー情報を出力します。これは、コードのシミュレーションを必要としないため、リソースプレッシャービューとは異なります。代わりに、シーケンス内のすべての命令のリソースプレッシャーの理論的な均一分布を出力します。
- -bottleneck-analysis¶
スループットに影響を与えるボトルネックに関する情報を出力します。この分析はコストがかかる可能性があり、デフォルトでは無効になっています。ボトルネックは概要ビューで強調表示されます。ボトルネック分析は現在、インオーダーバックエンドを持つプロセッサではサポートされていません。
- -json¶
要求されたビューを有効なJSON形式で出力します。命令とプロセッサリソースは、特別なトップレベルのJSONオブジェクトのメンバーとして出力されます。個々のビューは、インデックスによってそれらを参照します。ただし、現在サポートされていないビューもあります。たとえば、ボトルネック分析からのレポートはJSONでは出力されません。すべてのデフォルトビューは現在サポートされています。
- -disable-cb¶
ターゲット固有の実装を使用するのではなく、汎用的なCustomBehaviourおよびInstrPostProcessクラスの使用を強制します。汎用クラスは、カスタムハザードを検出したり、命令にポストプロセス変更を加えたりすることはありません。
- -disable-im¶
ターゲット固有の実装を使用するのではなく、汎用的なInstrumentManagerの使用を強制します。汎用クラスは、追加情報を提供しないInstrumentを作成し、InstrumentManagerは、指定された命令のデフォルトのスケジュールクラスをオーバーライドすることはありません。
- -skip-unsupported-instructions=<reason>¶
パースできない命令や、重要なスケジューリング情報が不足している場合でも、llvm-mcaに処理を継続させます。これらのサポートされていない命令は入力の一部として提供されていないかのように無視されるため、結果の分析に影響があることに注意してください。
<reason>の選択によって、mcaがいつエラーを報告するかが制御されます。<reason>は、none(デフォルト)、lack-sched、parse-failure、anyのいずれかです。
終了ステータス¶
llvm-mcaは、成功すると0を返します。それ以外の場合は、エラーメッセージが標準エラーに出力され、ツールは1を返します。
マーカーを使用して特定のコードブロックを分析する¶
llvm-mcaでは、分析するアセンブリコードの領域をマークするために、特別なコードコメントをオプションで使用できます。サブストリングLLVM-MCA-BEGIN
で始まるコメントは、分析領域の開始を示します。サブストリングLLVM-MCA-END
で始まるコメントは、領域の終了を示します。例:
# LLVM-MCA-BEGIN
...
# LLVM-MCA-END
ユーザー定義の領域が指定されていない場合、llvm-mcaは、入力ファイル内のすべての命令を含むデフォルトの領域を想定します。すべての領域は個別に分析され、最終的なパフォーマンスレポートは、すべての分析領域に対して生成されたすべてのレポートの結合です。
分析領域には名前を付けることができます。例:
# LLVM-MCA-BEGIN A simple example
add %eax, %eax
# LLVM-MCA-END
上記の例のコードは、「A simple example」という名前の領域を1つの命令で定義しています。領域名はLLVM-MCA-END
ディレクティブで繰り返す必要がないことに注意してください。重複する領域がない場合、匿名LLVM-MCA-END
ディレクティブは、常に現在アクティブなユーザー定義領域を終了します。
ネストされた領域の例
# LLVM-MCA-BEGIN foo
add %eax, %edx
# LLVM-MCA-BEGIN bar
sub %eax, %edx
# LLVM-MCA-END bar
# LLVM-MCA-END foo
重複する領域の例
# LLVM-MCA-BEGIN foo
add %eax, %edx
# LLVM-MCA-BEGIN bar
sub %eax, %edx
# LLVM-MCA-END foo
add %eax, %edx
# LLVM-MCA-END bar
複数の匿名領域を重複させることはできません。また、重複する領域は同じ名前を持つことはできません。
CやC++などの高レベルのソースコードから領域をマークすることはサポートされていません。回避策として、インラインアセンブリディレクティブを使用できます。
int foo(int a, int b) {
__asm volatile("# LLVM-MCA-BEGIN foo":::"memory");
a += 42;
__asm volatile("# LLVM-MCA-END":::"memory");
a *= b;
return a;
}
ただし、これによりループのベクトル化などの最適化が妨げられ、生成されるコードに影響を与える可能性があります。これは、__asm
ステートメントが重要な副作用を持つ実際のコードと見なされ、それらの周りのコードを変換する方法が制限されるためです。ユーザーがインラインアセンブリを使用してマーカーを出力する場合は、出力アセンブリがマーカーがない場合に生成されたアセンブリと同等であることを常に検証することをお勧めします。最適化の失敗を検出するには、最適化レポートを生成するClangオプションも役立ちます。
インストゥルメント領域¶
InstrumentRegionは、特別なLLVM-MCAコメントディレクティブによって保護されたアセンブリコードの領域を記述します。
# LLVM-MCA-<INSTRUMENT_TYPE> <data>
... ## asm
ここで、INSTRUMENT_TYPEはターゲットによって定義された型であり、dataを使用することを期待します。
サブストリングLLVM-MCA-<INSTRUMENT_TYPE>で始まるコメントは、llvm-mcaが後のすべての命令の分析で使用するためのデータをスコープに持ち込みます。
同じINSTRUMENT_TYPEのコメントが命令リストの後半で見つかった場合、元のInstrumentRegionは自動的に終了し、新しいInstrumentRegionが開始されます。
異なるINSTRUMENT_TYPEを含むコメントがある場合、両方のデータセットが引き続き使用可能です。AnalysisRegionとは対照的に、InstrumentRegionは領域を終了するためのコメントを必要としません。
LLVM-MCA-で始まるが、ターゲットの有効なINSTRUMENT_TYPEに対応しないコメントは、AnalysisRegionに対応するため、BEGINとENDを除いて、エラーを引き起こします。LLVM-MCA-で始まらないコメントは、llvm-mcaによって無視されます。
命令(MCInst)は、その場所が範囲[R.RangeStart、R.RangeEnd]内にある場合にのみ、InstrumentRegion Rに追加されます。
RISCVターゲットでは、ベクター命令はLMULに応じて異なる動作をします。コードは、次の形式のコメントでインストゥルメントできます。
# LLVM-MCA-RISCV-LMUL <M1|M2|M4|M8|MF2|MF4|MF8>
RISCV InstrumentManagerは、ベクター命令のスケジュールクラスをオーバーライドして、LMULに依存する疑似命令のスケジューリング動作を使用します。vset{i}vl{i}命令の直後にRISCVインストゥルメントコメントを配置するのが理にかなっていますが、プログラム内の任意の場所に配置できます。
vset{i}vl{i}を呼び出さないプログラムの例
# LLVM-MCA-RISCV-LMUL M2
vadd.vv v2, v2, v2
vset{i}vl{i}を呼び出すプログラムの例
vsetvli zero, a0, e8, m1, tu, mu
# LLVM-MCA-RISCV-LMUL M1
vadd.vv v2, v2, v2
vset{i}vl{i}を複数回呼び出すプログラムの例
vsetvli zero, a0, e8, m1, tu, mu
# LLVM-MCA-RISCV-LMUL M1
vadd.vv v2, v2, v2
vsetvli zero, a0, e8, m8, tu, mu
# LLVM-MCA-RISCV-LMUL M8
vadd.vv v2, v2, v2
vsetvlを呼び出すプログラムの例
vsetvl rd, rs1, rs2
# LLVM-MCA-RISCV-LMUL M1
vadd.vv v12, v12, v12
vsetvl rd, rs1, rs2
# LLVM-MCA-RISCV-LMUL M4
vadd.vv v12, v12, v12
LLVM-MCAの仕組み¶
llvm-mcaは、アセンブリコードを入力として受け取ります。アセンブリコードは、既存のLLVMターゲットアセンブリパーサーの助けを借りて、MCInstのシーケンスに解析されます。解析されたMCInstのシーケンスは、Pipeline
モジュールによって分析され、パフォーマンスレポートが生成されます。
Pipelineモジュールは、マシンコードシーケンスの実行を繰り返しのループでシミュレートします(デフォルトは100)。このプロセス中に、パイプラインは多くの実行関連の統計を収集します。このプロセスの最後に、パイプラインは収集された統計からレポートを生成して出力します。
これは、4要素のパックされた浮動小数点ベクトルのドット積に対してツールによって生成されたパフォーマンスレポートの例です。分析は、ターゲットx86、cpu btver2に対して実行されます。次の結果は、test/tools/llvm-mca/X86/BtVer2/dot-product.s
にある例を使用して、次のコマンドで生成できます。
$ llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=300 dot-product.s
Iterations: 300
Instructions: 900
Total Cycles: 610
Total uOps: 900
Dispatch Width: 2
uOps Per Cycle: 1.48
IPC: 1.48
Block RThroughput: 2.0
Instruction Info:
[1]: #uOps
[2]: Latency
[3]: RThroughput
[4]: MayLoad
[5]: MayStore
[6]: HasSideEffects (U)
[1] [2] [3] [4] [5] [6] Instructions:
1 2 1.00 vmulps %xmm0, %xmm1, %xmm2
1 3 1.00 vhaddps %xmm2, %xmm2, %xmm3
1 3 1.00 vhaddps %xmm3, %xmm3, %xmm4
Resources:
[0] - JALU0
[1] - JALU1
[2] - JDiv
[3] - JFPA
[4] - JFPM
[5] - JFPU0
[6] - JFPU1
[7] - JLAGU
[8] - JMul
[9] - JSAGU
[10] - JSTC
[11] - JVALU0
[12] - JVALU1
[13] - JVIMUL
Resource pressure per iteration:
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13]
- - - 2.00 1.00 2.00 1.00 - - - - - - -
Resource pressure by instruction:
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] Instructions:
- - - - 1.00 - 1.00 - - - - - - - vmulps %xmm0, %xmm1, %xmm2
- - - 1.00 - 1.00 - - - - - - - - vhaddps %xmm2, %xmm2, %xmm3
- - - 1.00 - 1.00 - - - - - - - - vhaddps %xmm3, %xmm3, %xmm4
このレポートによると、ドット積カーネルは300回実行され、合計900のシミュレートされた命令がありました。シミュレートされたマイクロオペコード(uOp)の合計数も900です。
レポートは、3つの主要なセクションに構造化されています。最初のセクションでは、いくつかのパフォーマンス数値が収集されます。このセクションの目的は、パフォーマンスのスループットの非常に簡単な概要を提供することです。重要なパフォーマンス指標は、IPC、1サイクルあたりのuOp、およびブロックRスループット(ブロック逆スループット)です。
フィールドDispatchWidthは、すべてのシミュレートされたサイクルでアウトオブオーダーバックエンドにディスパッチされるマイクロオペコードの最大数です。インオーダーバックエンドを備えたプロセッサの場合、DispatchWidthは、すべてのシミュレートされたサイクルでバックエンドに発行されるマイクロオペコードの最大数です。
IPCは、シミュレートされた命令の総数をサイクルの総数で割ることによって計算されます。
フィールドブロックRスループットは、ブロックスループットの逆数です。ブロックスループットは、ループキャリー依存関係がない場合に、シミュレートされたクロックサイクルごとに実行できるブロック(つまり、反復)の最大数として計算される理論上の量です。ブロックスループットは、ディスパッチレートとハードウェアリソースの可用性によって上限が制限されます。
ループキャリーデータ依存関係がない場合、観測されたIPCは、1回の反復の命令数をブロックRスループットで割ることによって計算できる理論上の最大値に近づく傾向があります。
フィールド「1サイクルあたりのuOp」は、シミュレートされたマイクロオペコードの合計数をサイクルの合計数で割ることによって計算されます。ディスパッチ幅とこのフィールドの間のデルタは、パフォーマンスの問題を示す指標です。ループキャリーデータ依存関係がない場合、観測された「1サイクルあたりのuOp」は、1回の反復のuOp数をブロックRスループットで割ることによって計算できる理論上の最大スループットに近づくはずです。
フィールド1サイクルあたりのuOpは、ディスパッチ幅によって上限が設定されます。これは、ディスパッチ幅がディスパッチグループの最大サイズを制限するためです。IPCと「1サイクルあたりのuOp」はどちらも、ハードウェアの並列処理の量によって制限されます。ハードウェアリソースの可用性は、リソースプレッシャーの分布に影響を与え、すべてのサイクルで並行して実行できる命令数を制限します。ディスパッチ幅と理論上の最大uOp/サイクル(1回の反復のuOp数をブロックRスループットで割ることによって計算)の間のデルタは、ハードウェアリソースの不足によって引き起こされるパフォーマンスボトルネックの指標です。一般的に、ブロックRスループットが低いほど、パフォーマンスが向上します。
この例では、1回の反復あたりのuOp/ブロックRスループット
は1.50です。ループキャリー依存関係がないため、反復回数が無限大に近づくと、観測された1サイクルあたりのuOpは1.50に近づくと予想されます。ディスパッチ幅(2.00)と理論上の最大uOpスループット(1.50)の間のデルタは、ハードウェアリソースの不足によって引き起こされるパフォーマンスボトルネックの指標であり、リソースプレッシャービューは問題のあるリソースの使用状況を特定するのに役立ちます。
レポートの2番目のセクションは、命令情報ビューです。シーケンス内のすべての命令のレイテンシーと逆スループットを示します。また、マイクロオペコードの数とオペコードのプロパティ(「MayLoad」、「MayStore」、および「HasSideEffects」など)に関連する追加情報も報告します。
フィールドRスループットは、命令スループットの逆数です。スループットは、オペランド依存関係がない場合に、クロックサイクルごとに実行できる同じタイプの命令の最大数として計算されます。この例では、ベクター浮動小数点乗算の逆スループットは1サイクル/命令です。これは、FP乗算器JFPMがパイプラインJFPU1からのみ利用可能であるためです。
フラグ-show-encodingが指定されている場合、命令エンコーディングは命令情報ビュー内に表示されます。
以下は、ドット積カーネルの-show-encoding出力の例です。
Instruction Info:
[1]: #uOps
[2]: Latency
[3]: RThroughput
[4]: MayLoad
[5]: MayStore
[6]: HasSideEffects (U)
[7]: Encoding Size
[1] [2] [3] [4] [5] [6] [7] Encodings: Instructions:
1 2 1.00 4 c5 f0 59 d0 vmulps %xmm0, %xmm1, %xmm2
1 4 1.00 4 c5 eb 7c da vhaddps %xmm2, %xmm2, %xmm3
1 4 1.00 4 c5 e3 7c e3 vhaddps %xmm3, %xmm3, %xmm4
Encoding Size列は、命令のサイズをバイト単位で示しています。Encodings列は、実際の命令エンコーディング(16進数でのバイトシーケンス)を示しています。
3番目のセクションは、リソースプレッシャービューです。このビューは、ターゲットで利用可能なすべてのプロセッサリソースユニットについて、命令が各イテレーションで消費するリソースサイクルの平均数をレポートします。情報は2つのテーブルで構成されています。最初のテーブルは、各イテレーションで平均的に消費されたリソースサイクル数を示しています。2番目のテーブルは、リソースサイクルをシーケンス内のマシン命令と関連付けます。たとえば、vmulps命令の各イテレーションは、常にリソースユニット[6](JFPU1 - 浮動小数点パイプライン#1)で実行され、イテレーションごとに平均1リソースサイクルを消費します。AMD Jaguarでは、ベクター浮動小数点乗算はパイプラインJFPU1にのみ発行でき、水平浮動小数点加算はパイプラインJFPU0にのみ発行できることに注意してください。
リソースプレッシャービューは、特定のハードウェアリソースの使用率が高いことによって発生するボトルネックを特定するのに役立ちます。リソースプレッシャーが主に少数のリソースに集中している状況は、一般的に避けるべきです。理想的には、プレッシャーは複数のリソース間で均等に分散される必要があります。
タイムラインビュー¶
タイムラインビューは、命令パイプラインを通過する各命令の状態遷移の詳細なレポートを生成します。このビューは、コマンドラインオプション-timeline
で有効になります。命令がパイプラインのさまざまな段階を遷移するにつれて、それらの状態がビューレポートに表示されます。これらの状態は、次の文字で表されます。
D:命令がディスパッチされました。
e:命令が実行中です。
E:命令が実行されました。
R:命令がリタイアしました。
=:命令はすでにディスパッチされており、実行を待機しています。
-:命令が実行されましたが、リタイアを待機しています。
以下は、test/tools/llvm-mca/X86/BtVer2/dot-product.s
にあるドット積の例の一部であり、次のコマンドを使用してllvm-mcaで処理された場合のタイムラインビューです。
$ llvm-mca -mtriple=x86_64-unknown-unknown -mcpu=btver2 -iterations=3 -timeline dot-product.s
Timeline view:
012345
Index 0123456789
[0,0] DeeER. . . vmulps %xmm0, %xmm1, %xmm2
[0,1] D==eeeER . . vhaddps %xmm2, %xmm2, %xmm3
[0,2] .D====eeeER . vhaddps %xmm3, %xmm3, %xmm4
[1,0] .DeeE-----R . vmulps %xmm0, %xmm1, %xmm2
[1,1] . D=eeeE---R . vhaddps %xmm2, %xmm2, %xmm3
[1,2] . D====eeeER . vhaddps %xmm3, %xmm3, %xmm4
[2,0] . DeeE-----R . vmulps %xmm0, %xmm1, %xmm2
[2,1] . D====eeeER . vhaddps %xmm2, %xmm2, %xmm3
[2,2] . D======eeeER vhaddps %xmm3, %xmm3, %xmm4
Average Wait times (based on the timeline view):
[0]: Executions
[1]: Average time spent waiting in a scheduler's queue
[2]: Average time spent waiting in a scheduler's queue while ready
[3]: Average time elapsed from WB until retire stage
[0] [1] [2] [3]
0. 3 1.0 1.0 3.3 vmulps %xmm0, %xmm1, %xmm2
1. 3 3.3 0.7 1.0 vhaddps %xmm2, %xmm2, %xmm3
2. 3 5.7 0.0 0.0 vhaddps %xmm3, %xmm3, %xmm4
3 3.3 0.5 1.4 <total>
タイムラインビューは、実行中の命令状態の変化を示しているため興味深いものです。また、ツールがターゲットで実行された命令をどのように処理し、それらのタイミング情報がどのように計算されるかについてのアイデアも得られます。
タイムラインビューは、2つのテーブルで構成されています。最初のテーブルは、時間(サイクル単位で測定)の経過に伴う命令状態の変化を示しています。2番目のテーブル(平均待ち時間という名前)は、長いデータ依存関係やハードウェアリソースの最適でない使用によって引き起こされるパフォーマンスボトルネックを診断するのに役立つ、役立つタイミング統計をレポートします。
タイムラインビューの命令は、インデックスのペアで識別されます。最初のインデックスはイテレーションを識別し、2番目のインデックスは命令インデックス(コードシーケンス内の位置)です。この例は、3回のイテレーションを使用して生成されたため、-iterations=3
、イテレーションインデックスの範囲は0〜2を含みます。
最初と最後の列を除いて、残りの列はサイクル単位です。サイクルは0から始まる順次番号が付けられています。
上記の出力例から、次のことがわかります。
命令[1,0]はサイクル1でディスパッチされました。
命令[1,0]はサイクル2で実行を開始しました。
命令[1,0]はサイクル4でライトバックステージに到達しました。
命令[1,0]はサイクル10でリタイアしました。
命令[1,0](つまり、イテレーション#1からのvmulps)は、オペランドが利用可能になるのをスケジューラのキューで待つ必要はありません。vmulpsがディスパッチされるまでに、オペランドはすでに利用可能であり、パイプラインJFPU1は別の命令に対応する準備ができています。そのため、命令はJFPU1パイプラインですぐに発行できます。これは、命令がスケジューラのキューで1cyしか費やしていないという事実によって実証されます。
ライトバックステージとリタイアイベントの間には、5サイクルのギャップがあります。これは、命令がプログラム順にリタイアする必要があるため、[1,0]は[0,2]が最初にリタイアされるのを待つ必要があるためです(つまり、サイクル10まで待つ必要があります)。
この例では、すべての命令がRAW(Read After Write)依存関係チェーンにあります。vmulpsによって書き込まれたレジスタ%xmm2は最初のvhaddpsですぐに使用され、最初のvhaddpsによって書き込まれたレジスタ%xmm3は2番目のvhaddpsによって使用されます。長いデータ依存関係は、ILP(Instruction Level Parallelism)に悪影響を与えます。
ドット積の例では、異なるイテレーションの命令によって反依存関係が導入されています。ただし、これらの依存関係はレジスタの名前変更段階で削除できます(レジスタエイリアスの割り当て、したがって物理レジスタの消費を犠牲にして)。
テーブル平均待ち時間は、長いレイテンシ命令の存在や、ILPを制限する可能性のある長いデータ依存関係によって引き起こされるパフォーマンスの問題を診断するのに役立ちます。最後の行、<total>
は、測定されたすべての命令のグローバル平均を示しています。llvm-mcaは、デフォルトで、ディスパッチイベントと発行イベントの間に少なくとも1cyを想定していることに注意してください。
パフォーマンスがデータ依存関係や長いレイテンシ命令によって制限されている場合、ready状態で費やされるサイクル数は、スケジューラのキューで費やされる合計サイクル数と比較すると非常に小さくなると予想されます。2つのカウンターの差は、データ依存関係が命令の実行にどれほど大きな影響を与えたかの良い指標です。パフォーマンスが主にハードウェアリソースの不足によって制限されている場合、2つのカウンターの差は小さくなります。ただし、キューで費やされるサイクル数は、特に他の低レイテンシ命令と比較した場合、大きくなる傾向があります(つまり、1〜3cy以上)。
ボトルネック分析¶
-bottleneck-analysis
コマンドラインオプションを使用すると、パフォーマンスボトルネックの分析が可能になります。
この分析は、潜在的にコストがかかります。パイプラインリソースのプレッシャーとデータ依存関係によって引き起こされるバックエンドのプレッシャーの増加を、動的なディスパッチストールと関連付けようとします。
以下は、btver2でのドット積の例の500回のイテレーションについてllvm-mcaによって生成された-bottleneck-analysis
出力の例です。
Cycles with backend pressure increase [ 48.07% ]
Throughput Bottlenecks:
Resource Pressure [ 47.77% ]
- JFPA [ 47.77% ]
- JFPU0 [ 47.77% ]
Data Dependencies: [ 0.30% ]
- Register Dependencies [ 0.30% ]
- Memory Dependencies [ 0.00% ]
Critical sequence based on the simulation:
Instruction Dependency Information
+----< 2. vhaddps %xmm3, %xmm3, %xmm4
|
| < loop carried >
|
| 0. vmulps %xmm0, %xmm1, %xmm2
+----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 74% ]
+----> 2. vhaddps %xmm3, %xmm3, %xmm4 ## REGISTER dependency: %xmm3
|
| < loop carried >
|
+----> 1. vhaddps %xmm2, %xmm2, %xmm3 ## RESOURCE interference: JFPA [ probability: 74% ]
分析によると、スループットはデータ依存関係ではなく、リソースプレッシャーによって制限されています。分析では、シミュレーション実行の48.07%の間、バックエンドのプレッシャーが増加していることが観察されました。これらのプレッシャーの増加イベントのほとんどすべては、プロセッサリソースJFPA/JFPU0の競合によって引き起こされました。
クリティカルシーケンスは、シミュレーションによると最もコストのかかる命令シーケンスです。クリティカルなレジスタ依存関係と命令間のリソース干渉に関する追加情報を提供するために注釈が付けられています。
クリティカルシーケンスの命令は、パフォーマンスに大きな影響を与えることが予想されます。構造上、この分析の精度はシミュレーションに大きく依存しており、(常にそうであるように)llvmのプロセッサモデルの品質に依存します。
ボトルネック分析は、現在、インオーダーバックエンドを持つプロセッサではサポートされていません。
パフォーマンスの問題をさらに診断するための追加の統計¶
-all-stats
コマンドラインオプションを使用すると、ディスパッチロジック、リオーダーバッファ、リタイアコントロールユニット、およびレジスタファイルの追加の統計とパフォーマンスカウンターが有効になります。
以下は、前のセクションで説明したドット積の例の300回のイテレーションについてllvm-mcaによって生成された-all-stats
出力の例です。
Dynamic Dispatch Stall Cycles:
RAT - Register unavailable: 0
RCU - Retire tokens unavailable: 0
SCHEDQ - Scheduler full: 272 (44.6%)
LQ - Load queue full: 0
SQ - Store queue full: 0
GROUP - Static restrictions on the dispatch group: 0
Dispatch Logic - number of cycles where we saw N micro opcodes dispatched:
[# dispatched], [# cycles]
0, 24 (3.9%)
1, 272 (44.6%)
2, 314 (51.5%)
Schedulers - number of cycles where we saw N micro opcodes issued:
[# issued], [# cycles]
0, 7 (1.1%)
1, 306 (50.2%)
2, 297 (48.7%)
Scheduler's queue usage:
[1] Resource name.
[2] Average number of used buffer entries.
[3] Maximum number of used buffer entries.
[4] Total number of buffer entries.
[1] [2] [3] [4]
JALU01 0 0 20
JFPU01 17 18 18
JLSAGU 0 0 12
Retire Control Unit - number of cycles where we saw N instructions retired:
[# retired], [# cycles]
0, 109 (17.9%)
1, 102 (16.7%)
2, 399 (65.4%)
Total ROB Entries: 64
Max Used ROB Entries: 35 ( 54.7% )
Average Used ROB Entries per cy: 32 ( 50.0% )
Register File statistics:
Total number of mappings created: 900
Max number of mappings used: 35
* Register File #1 -- JFpuPRF:
Number of physical registers: 72
Total number of mappings created: 900
Max number of mappings used: 35
* Register File #2 -- JIntegerPRF:
Number of physical registers: 64
Total number of mappings created: 0
Max number of mappings used: 0
動的ディスパッチストールサイクルテーブルを見ると、SCHEDQのカウンターが272サイクルを報告していることがわかります。このカウンターは、スケジューラのキューがいっぱいであるためにディスパッチロジックがフルグループをディスパッチできないたびにインクリメントされます。
ディスパッチロジックテーブルを見ると、パイプラインがマイクロオペコードを2つしかディスパッチできなかったのは、時間の51.5%でした。ディスパッチグループは、サイクルの44.6%、つまり272サイクルに相当するマイクロオペコード1つに制限されていました。ディスパッチ統計は、コマンドオプション-all-stats
または-dispatch-stats
を使用することで表示されます。
次のテーブル、スケジューラは、サイクル数に対するマイクロオペコードの発行回数を表すヒストグラムを表示します。この場合、シミュレートされた610サイクルのうち、シングルオペコードは306回(50.2%)発行され、オペコードが発行されなかったサイクルは7サイクルでした。
スケジューラのキュー使用量テーブルは、実行時に使用されたバッファエントリ(つまり、スケジューラキューエントリ)の平均数と最大数を示しています。リソースJFPU01は最大値(18個のキューエントリのうち18個)に達しました。AMD Jaguarは3つのスケジューラを実装していることに注意してください。
JALU01 - ALU命令用のスケジューラ。
JFPU01 - 浮動小数点演算用のスケジューラ。
JLSAGU - アドレス生成用のスケジューラ。
ドット積は、3つの浮動小数点命令(ベクター乗算に続いて2つの水平加算)のカーネルです。それが、浮動小数点スケジューラのみが使用されているように見える理由です。
フルスケジューラキューは、データ依存関係チェーンまたはハードウェアリソースの最適でない使用によって引き起こされます。場合によっては、異なるスケジューラリソースを消費する異なる命令を使用してカーネルを書き換えることで、リソースのプレッシャーを軽減できます。キューが小さいスケジューラは、長いデータ依存関係の存在によって引き起こされるボトルネックに対する回復力が低くなります。スケジューラの統計は、コマンドオプション-all-stats
または-scheduler-stats
を使用して表示されます。
次のテーブル、リタイアコントロールユニットは、サイクル数に対するリタイアした命令数を表すヒストグラムを表示します。この場合、シミュレートされた610サイクルのうち、2つの命令が同じサイクルで399回(65.4%)リタイアされ、命令がリタイアされなかったサイクルは109サイクルでした。リタイアの統計は、コマンドオプション-all-stats
または-retire-stats
を使用して表示されます。
最後に提示されるテーブルは、レジスタファイル統計です。パイプラインで使用される各物理レジスタファイル(PRF)がこのテーブルに表示されます。AMD Jaguarの場合、浮動小数点レジスタ用の1つ(JFpuPRF)と整数レジスタ用の1つ(JIntegerPRF)の2つのレジスタファイルがあります。テーブルは、処理された900の命令のうち、900のマッピングが作成されたことを示しています。このドット積の例では浮動小数点レジスタのみを使用しているため、JFPuPRFは900のマッピングを作成する役割を担っていました。ただし、パイプラインは、任意の時点で利用可能な72個のレジスタスロットのうち、最大35個しか使用しなかったことがわかります。この例では、浮動小数点PRFのみが使用され、リソースが制約されることはなかったと結論付けることができます。レジスタファイルの統計は、コマンドオプション-all-stats
または-register-file-stats
を使用して表示されます。
この例では、IPCは主にデータ依存関係によって制限されており、リソースプレッシャーによるものではないと結論付けることができます。
命令フロー¶
このセクションでは、llvm-mcaのデフォルトパイプラインを介した命令フローと、プロセスに関与する機能ユニットについて説明します。
デフォルトパイプラインは、命令を処理するために使用される次の段階のシーケンスを実装します。
ディスパッチ(命令はスケジューラにディスパッチされます)。
発行(命令はプロセッサパイプラインに発行されます)。
ライトバック(命令が実行され、結果が書き戻されます)。
リタイア(命令がリタイアされ、書き込みがアーキテクチャ的にコミットされます)。
インオーダーパイプラインは、次の段階のシーケンスを実装します。
インオーダー発行(命令はプロセッサパイプラインに発行されます)。
リタイア(命令がリタイアされ、書き込みがアーキテクチャ的にコミットされます)。
llvm-mca は、命令がすべてデコードされ、シミュレーション開始前にキューに格納されていることを前提としています。したがって、命令フェッチおよびデコードのステージはモデル化されていません。フロントエンドでのパフォーマンスボトルネックは診断されません。また、llvm-mca は分岐予測をモデル化しません。
命令ディスパッチ¶
ディスパッチステージでは、すでにデコードされた命令のキューからプログラム順に命令が選択され、シミュレートされたハードウェアスケジューラにグループでディスパッチされます。
ディスパッチグループのサイズは、シミュレートされたハードウェアリソースの可用性に依存します。プロセッサのディスパッチ幅は、LLVMのスケジューリングモデルにおける IssueWidth
の値にデフォルト設定されます。
命令は以下の場合にディスパッチできます。
ディスパッチグループのサイズがプロセッサのディスパッチ幅よりも小さい。
リオーダバッファに十分なエントリがある。
レジスタリネーミングを実行するための十分な物理レジスタがある。
スケジューラが満杯でない。
スケジューリングモデルでは、プロセッサで使用可能なレジスタファイルをオプションで指定できます。llvm-mca はその情報を使用して、レジスタファイル記述子を初期化します。ユーザーは、コマンドオプション -register-file-size
を使用して、レジスタリネーミングのためにグローバルに使用可能な物理レジスタの数を制限できます。このオプションの値がゼロの場合、制限なし を意味します。リネーミングに使用できるレジスタの数を知ることで、ツールは物理レジスタの不足によって引き起こされるディスパッチストールを予測できます。
命令によって消費されるリオーダバッファのエントリ数は、ターゲットスケジューリングモデルでその命令に対して指定されたマイクロオペコードの数に依存します。リオーダバッファは、「インフライト」状態の命令の進行状況を追跡し、プログラム順にそれらをリタイアさせる役割を担います。リオーダバッファのエントリ数は、ターゲットスケジューリングモデルの MicroOpBufferSize フィールドで指定された値にデフォルト設定されます。
スケジューラにディスパッチされた命令は、スケジューラバッファのエントリを消費します。llvm-mca はスケジューリングモデルにクエリを実行して、命令によって消費されるバッファリングされたリソースのセットを判断します。バッファリングされたリソースは、スケジューラリソースのように扱われます。
命令発行¶
各プロセッサスケジューラは、命令のバッファを実装します。命令は、入力レジスタオペランドが利用可能になるまでスケジューラのバッファで待機する必要があります。その時点で初めて、命令は実行可能になり、実行のために(潜在的にアウトオブオーダーで)発行される可能性があります。命令のレイテンシは、スケジューリングモデルの助けを借りて llvm-mca によって計算されます。
llvm-mca のスケジューラは、複数のプロセッサスケジューラをシミュレートするように設計されています。スケジューラは、データ依存関係を追跡し、命令によって消費されるプロセッサリソースを動的に選択する役割を担います。プロセッサリソースユニットとリソースグループの管理をリソースマネージャーに委任します。リソースマネージャーは、命令によって消費されるリソースユニットを選択する役割を担います。たとえば、命令がリソースグループの1cyを消費する場合、リソースマネージャーはグループで使用可能なユニットの1つを選択します。デフォルトでは、リソースマネージャーはラウンドロビンセレクターを使用して、リソースの使用がグループのすべてのユニット間で均等に分散されるようにします。
llvm-mca のスケジューラは、内部で命令を3つのセットにグループ化します。
WaitSet:オペランドの準備ができていない命令のセット。
ReadySet:実行準備ができた命令のセット。
IssuedSet:実行中の命令のセット。
オペランドの可用性に応じて、スケジューラにディスパッチされた命令は、WaitSetまたはReadySetのいずれかに配置されます。
各サイクルで、スケジューラは、WaitSetからReadySetに命令を移動できるかどうか、およびReadySetからの命令を基になるパイプラインに発行できるかどうかを確認します。アルゴリズムは、より古い命令をより新しい命令よりも優先します。
ライトバックおよびリタイアステージ¶
発行された命令は、ReadySetからIssuedSetに移動されます。そこで、命令はライトバックステージに到達するまで待機します。その時点で、命令はキューから削除され、リタイア制御ユニットに通知されます。
命令が実行されると、リタイア制御ユニットは命令を「リタイア準備完了」としてフラグを立てます。
命令はプログラム順にリタイアされます。レジスタファイルにはリタイアが通知され、レジスタリネーミングステージ中に命令に割り当てられた物理レジスタを解放できます。
ロード/ストアユニットおよびメモリ整合性モデル¶
メモリオペレーションのアウトオブオーダー実行をシミュレートするために、llvm-mca は、ロードとストアの投機的実行をシミュレートするために、シミュレートされたロード/ストアユニット(LSUnit)を利用します。
各ロード(またはストア)は、ロード(またはストア)キューのエントリを消費します。ユーザーは、フラグ -lqueue
および -squeue
を指定して、それぞれロードキューとストアキューのエントリ数を制限できます。キューはデフォルトでは制限がありません。
LSUnitは、メモリロードとストアに対して緩和された整合性モデルを実装します。ルールは次のとおりです。
若いロードは、2つのロード間に介在するストアまたはバリアがない場合にのみ、古いロードを通過することが許可されます。
若いロードは、ロードがストアとエイリアスしない場合に、古いストアを通過することが許可されます。
若いストアは、古いストアを通過することが許可されません。
若いストアは、古いロードを通過することが許可されません。
デフォルトでは、LSUnitは、ロードがストア操作とエイリアスしない(-noalias=true)と楽観的に想定します。この仮定の下では、若いロードは常に古いストアを通過することが許可されます。基本的に、LSUnitは、ロードとストアが相互にエイリアスしない場合を予測するために、エイリアス分析を実行しようとしません。
ライトコンバイニングメモリの場合、ルール3を緩和して、エイリアスしないストア操作の並べ替えを許可できることに注意してください。とはいえ、現時点では、メモリモデルをさらに緩和する方法はありません(-noalias
が唯一のオプションです)。基本的に、異なるメモリタイプ(たとえば、ライトバック、ライトコンバイニング、ライトスルーなど)を指定し、その結果、メモリモデルを弱めたり、強化したりするオプションはありません。
その他の制限は次のとおりです。
LSUnitは、ストアからロードへの転送がいつ発生するかを認識しません。
LSUnitは、キャッシュ階層とメモリタイプについて何も知りません。
LSUnitは、シリアル化操作とメモリフェンスを識別する方法を知りません。
LSUnitは、ロードまたはストアがL1キャッシュにヒットするかミスするかを予測しようとしません。命令が「MayLoad」および/または「MayStore」かどうかのみを認識します。ロードの場合、スケジューリングモデルは「楽観的な」ロードから使用までのレイテンシを提供します(通常、L1Dにヒットする場合のロードから使用までのレイテンシと一致します)。
llvm-mca は(それ自体では)シリアル化操作やメモリバリアのような命令については知りません。以前は、LSUnitは、命令をメモリバリアとして扱う必要があるかどうかを判断するために、命令の「MayLoad」、「MayStore」、およびモデル化されていない副作用フラグを保守的に使用していました。これは一般的に不正確であり、現在は各命令に IsAStoreBarrier および IsALoadBarrier フラグが設定されるように変更されました。これらのフラグは mca 固有であり、すべての命令に対してデフォルトでfalseになります。命令にこれらのフラグのいずれかを設定する必要がある場合は、ターゲットの InstrPostProcess クラス内で設定する必要があります。例については、llvm/lib/Target/X86/MCA/X86CustomBehaviour.cpp 内の X86InstrPostProcess::postProcessInstruction メソッドを参照してください。
ロード/ストアバリアは、ロード/ストアキューの1つのエントリを消費します。ロード/ストアバリアは、ロード/ストアの順序を強制します。若いロードは、ロードバリアを通過できません。また、若いストアは、ストアバリアを通過できません。若いロードは、メモリ/ロードバリアが実行されるのを待つ必要があります。ロード/ストアバリアは、ロード/ストアキューの最古のエントリになったときに「実行」されます。これは、構造上、古いロード/ストアがすべて実行されていることも意味します。
結論として、ロード/ストア整合性ルールの完全なセットは次のとおりです。
ストアは、以前のストアを通過できません。
ストアは、(
-noalias
に関係なく)以前のロードを通過できません。ストアは、古いストアバリアが完全に実行されるまで待つ必要があります。
ロードは、以前のロードを通過できます。
ロードは、
-noalias
が設定されていない限り、以前のストアを通過できません。ロードは、古いロードバリアが完全に実行されるまで待つ必要があります。
インオーダー発行と実行¶
インオーダープロセッサは、単一の InOrderIssueStage
ステージとしてモデル化されます。ディスパッチ、スケジューラ、ロード/ストアユニットをバイパスします。命令は、オペランドレジスタが利用可能になり、リソース要件が満たされるとすぐに発行されます。複数の命令は、LLVMのスケジューリングモデルの IssueWidth
パラメータの値に従って、1つのサイクルで発行できます。
発行されると、命令はリタイア準備が整うまで IssuedInst
セットに移動されます。llvm-mca は、書き込みがインオーダーでコミットされることを保証します。ただし、命令は、書き込みの少なくとも1つに対して RetireOOO
プロパティがtrueである場合、書き込みをコミットしてアウトオブオーダーでリタイアすることが許可されます。
カスタム動作¶
一部の命令はスケジューリングモデル内で完全に表現されていないため、llvm-mca は常にそれらを完全にシミュレートできるわけではありません。ただし、スケジューリングモデルの変更は常に実行可能なオプションではありません(命令が意図的に誤ってモデル化されているか、命令の動作が非常に複雑であるためなど)。CustomBehaviourクラスは、これらのケースで適切な命令モデリングを強制するために使用できます(多くの場合、データ依存関係をカスタマイズし、llvm-mca が認識する方法がないハザードを検出することによって)。
llvm-mca には、1つの汎用クラスと複数のターゲット固有の CustomBehaviour クラスが付属しています。-disable-cb
フラグが使用されている場合、またはターゲット固有の CustomBehaviour クラスがそのターゲットに存在しない場合は、汎用クラスが使用されます。(汎用クラスは何も行いません。)現在、CustomBehaviour クラスはインオーダーパイプラインの一部にすぎませんが、将来的にはアウトオブオーダーパイプラインに追加する計画があります。
CustomBehaviour の主なメソッドは checkCustomHazard() であり、現在の命令とパイプライン内でまだ実行中のすべての命令のリストを使用して、現在の命令をディスパッチする必要があるかどうかを判断します。出力として、このメソッドは、現在の命令がストールする必要があるサイクル数を表す整数を返します(正確な数がわからない場合は過小評価になる可能性があり、値0はストールがないことを表します)。
まだCustomBehaviourクラスがないターゲットに追加する場合は、既存の実装を参照してセットアップ方法を確認してください。クラスは、バックエンドシンボルにアクセスできるように、ターゲット固有のバックエンド内(たとえば、/llvm/lib/Target/AMDGPU/MCA/)に実装されます。
インストルメントマネージャー¶
特定のアーキテクチャでは、特定の命令のスケジューリング情報に、最も正確なスケジュールクラスを識別するために必要なすべての情報が含まれていない場合があります。たとえば、スケジューリングに影響を与える可能性のあるデータがCSRレジスタに格納されている場合があります。
この一例として、RISC-Vでは、vtypeやvlなどのレジスタの値が、ベクター命令のスケジューリング動作を変更します。MCAはレジスタの値を追跡しないため、インストルメントコメントを使用してこれらの値を指定できます。
InstrumentManagerの主な機能はgetSchedClassID()であり、MCInstと、そのMCInstに対してアクティブなすべてのインストルメントにアクセスできます。この関数は、インストルメントを使用してMCInstのスケジュールクラスをオーバーライドできます。
RISC-Vでは、LMUL情報を含むインストルメントコメントは、getSchedClassID()によって使用され、ベクター命令とアクティブなLMULを、そのベース命令とアクティブなLMULを記述する疑似命令のスケジュールクラスにマッピングします。
カスタムビュー¶
llvm-mcaには、タイムラインビューやサマリービューなど、いくつかのビューが付属しています。これらのビューは汎用的であり、ほとんど(すべてではないにしても)のターゲットで機能します。llvm-mcaに新しいビューを追加したい場合で、MCレイヤークラス(MCSubtargetInfo、MCInstrInfoなど)を通じてすでに公開されているバックエンド機能以外を必要としない場合は、/tools/llvm-mca/View/ディレクトリに追加してください。ただし、新しいビューがターゲット固有であり、未公開のバックエンドシンボルや機能が必要な場合は、/lib/Target/<TargetName>/MCA/ディレクトリで定義できます。
このターゲット固有のビューを有効にするには、このターゲットのCustomBehaviourクラスを使用して、CustomBehaviour::getViews()メソッドをオーバーライドする必要があります。出力のどこにビューを表示するかによって、これらのメソッドには3つのバリエーションがあります。getStartViews()、getPostInstrInfoViews()、およびgetEndViews()です。これらのメソッドはビューのベクターを返すため、対象のターゲットのすべてのターゲット固有のビューを含むベクターを返す必要があります。
これらのターゲット固有(およびバックエンドに依存する)ビューは、CustomBehaviour::getViews()のバリエーションを必要とするため、-disable-cbフラグが使用されている場合、これらのビューは有効になりません。
これらのカスタムビューを有効にしても、非カスタム(汎用)ビューには影響しません。これらのビューを有効/無効にするには、通常どおりコマンドライン引数を使用してください。