# 機能設計書 49-llvm-exegesis

## 概要

本ドキュメントは、LLVM llvm-exegesisツールの機能設計を記述したものである。llvm-exegesisは命令レベルのベンチマークおよび分析ツールであり、CPU命令の実行特性（レイテンシ、スループット、マイクロオペレーション分解）を実測する。

### 本機能の処理概要

llvm-exegesisは、CPUの命令実行特性を実際のハードウェア上で測定するツールである。LLVMのスケジューリングモデルの精度検証や、コンパイラ最適化の改善に活用される。

**業務上の目的・背景**：コンパイラの命令スケジューリング最適化には、正確な命令特性データが不可欠である。llvm-exegesisは、ターゲットCPU上で命令を実際に実行し、パフォーマンスカウンタを使用して特性を測定する。これにより、LLVMのスケジューリングモデルの妥当性検証や改善が可能となる。

**機能の利用シーン**：
- 特定命令のレイテンシを実測する場合
- 命令のスループット（逆数）を測定する場合
- 命令のマイクロオペレーション分解を分析する場合
- LLVMスケジューリングモデルとの不整合を検出する場合

**主要な処理内容**：
1. ターゲット命令のスニペット生成
2. ベンチマーク実行とパフォーマンスカウンタ読み取り
3. 測定結果のYAML形式出力
4. 測定データのクラスタリング分析

**関連システム・外部連携**：
- libpfm（パフォーマンスカウンタライブラリ）
- LLVMターゲット記述（TableGen）

**権限による制御**：パフォーマンスカウンタへのアクセス権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | コマンドライン | 主画面 | モードとオプション指定 |

## 機能種別

ベンチマーク処理 / 分析処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| -mode | enum | Yes | latency/inverse_throughput/uops/analysis | 有効なモード |
| -opcode-index | int | No | 測定する命令のオペコードインデックス | 有効なインデックス |
| -opcode-name | string | No | 測定する命令名（カンマ区切り可） | 有効な命令名 |
| -snippets-file | string | No | カスタムスニペットファイル | ファイル存在チェック |
| -benchmarks-file | string | No | ベンチマーク結果ファイル（入出力） | - |
| -mcpu | string | No | ターゲットCPU（デフォルト: native） | 有効なCPU名 |
| -mtriple | string | No | ターゲットトリプル | 有効なトリプル |

### 入力データソース

- カスタムスニペットファイル
- 既存ベンチマーク結果（分析モード）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ベンチマーク結果 | YAML | 命令ごとの測定結果 |
| クラスター分析結果 | text | 命令グループの分析 |
| 不整合レポート | text | スケジュールモデルとの差異 |

### 出力先

- 標準出力（デフォルト）
- 指定されたファイル

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数の解析
   └─ モードとオプションの設定
2. ターゲット初期化
   └─ ExegesisTarget、LLVMState作成
3. モード分岐
   ├─ ベンチマークモード:
   │    ├─ オペコード取得またはスニペット読み込み
   │    ├─ スニペット生成
   │    ├─ BenchmarkRunner作成
   │    ├─ 測定実行
   │    └─ 結果出力
   └─ 分析モード:
        ├─ ベンチマーク結果読み込み
        ├─ クラスタリング実行
        └─ 分析レポート出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[コマンドライン解析]
    B --> C[ターゲット初期化]
    C --> D{モード判定}
    D -->|latency/uops/throughput| E[ベンチマークモード]
    D -->|analysis| F[分析モード]
    E --> G[オペコード取得]
    G --> H[スニペット生成]
    H --> I[BenchmarkRunner作成]
    I --> J[測定実行]
    J --> K[結果YAML出力]
    F --> L[ベンチマーク結果読込]
    L --> M[クラスタリング]
    M --> N[分析レポート出力]
    K --> O[終了]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | 排他入力 | opcode-index/opcode-name/snippets-fileのいずれか1つを指定 | ベンチマークモード |
| BR-49-02 | libpfm必須 | 測定にはlibpfmが必要（ビルド時オプション） | Measureフェーズ |
| BR-49-03 | CPU固定 | 分析は単一CPU/トリプルのデータのみ | 分析モード |

### 計算ロジック

- レイテンシ: 依存チェーンを構築して測定
- 逆スループット: 独立した命令列で測定
- Uops: マイクロオペレーション数をカウンタで測定

## データベース操作仕様

### 操作別データベース影響一覧

該当なし（ローカル処理）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | libpfm未初期化 | libpfmなしでビルド | --benchmark-phase指定またはダミーカウンタ使用 |
| - | 入力指定エラー | 複数の入力指定 | いずれか1つのみ指定 |
| - | 命令不明 | 指定した命令名が存在しない | 有効な命令名を使用 |
| - | サポート外 | ターゲットがExegesisをサポートしない | 対応ターゲットを使用 |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- 多数命令の効率的なベンチマーク
- 安定した測定のための反復実行

## セキュリティ考慮事項

- パフォーマンスカウンタへのアクセス権限
- サブプロセスモードでのメモリ保護

## 備考

- Intel/AMD x86、ARM等の主要アーキテクチャをサポート
- ダミーカウンタモードでテスト可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

Exegesis処理に関わる主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | BenchmarkResult.h | `llvm/tools/llvm-exegesis/lib/BenchmarkResult.h` | ベンチマーク結果構造 |
| 1-2 | BenchmarkRunner.h | `llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h` | 実行ランナー |
| 1-3 | LlvmState.h | `llvm/tools/llvm-exegesis/lib/LlvmState.h` | LLVM状態管理 |

**読解のコツ**: Benchmark構造体は測定結果を保持し、BenchmarkRunnerが実際の測定を実行する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | llvm-exegesis.cpp | `llvm/tools/llvm-exegesis/llvm-exegesis.cpp` | メイン関数 |

**主要処理フロー**:
1. **53-66行目**: オペコード指定オプション（OpcodeIndex、OpcodeNames、SnippetsFile）
2. **68-73行目**: BenchmarkFileオプション
3. **75-83行目**: BenchmarkMode列挙型（latency、inverse_throughput、uops、analysis）
4. **85-94行目**: ResultAggregationModeオプション
5. **96-108行目**: RepetitionModeオプション
6. **115-136行目**: BenchmarkPhaseSelectorオプション
7. **246-257行目**: ExecutionModeオプション（inprocess/subprocess）
8. **467-583行目**: benchmarkMain()関数
9. **624-696行目**: analysisMain()関数
10. **701-738行目**: main()関数

#### Step 3: ベンチマーク実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | BenchmarkRunner.cpp | `llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp` | 実行処理 |
| 3-2 | LatencyBenchmarkRunner.cpp | `llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp` | レイテンシ測定 |
| 3-3 | UopsBenchmarkRunner.cpp | `llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp` | Uops測定 |

#### Step 4: 分析処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Analysis.cpp | `llvm/tools/llvm-exegesis/lib/Analysis.cpp` | 分析処理 |
| 4-2 | Clustering.cpp | `llvm/tools/llvm-exegesis/lib/Clustering.cpp` | クラスタリング |

### プログラム呼び出し階層図

```
main()
    │
    ├─ InitLLVM()
    │
    ├─ cl::ParseCommandLineOptions()
    │
    └─ BenchmarkMode判定
           │
           ├─ benchmarkMain()
           │      ├─ pfm::pfmInitialize()
           │      ├─ InitializeAllExegesisTargets()
           │      ├─ LLVMState::Create()
           │      ├─ getOpcodesOrDie()
           │      │      └─ オペコード解決
           │      ├─ readSnippets() [スニペットファイル時]
           │      ├─ generateSnippets() [オペコード時]
           │      │      └─ SnippetGenerator
           │      ├─ BenchmarkRunner作成
           │      │      ├─ LatencyBenchmarkRunner
           │      │      ├─ UopsBenchmarkRunner
           │      │      └─ ParallelSnippetGenerator
           │      ├─ runBenchmarkConfigurations()
           │      │      ├─ Runner.getRunnableConfiguration()
           │      │      ├─ Runner.runConfiguration()
           │      │      └─ Result.writeYamlTo()
           │      └─ pfm::pfmTerminate()
           │
           └─ analysisMain()
                  ├─ InitializeAllExegesisTargets()
                  ├─ Benchmark::readYamls()
                  ├─ BenchmarkClustering::create()
                  ├─ Analysis作成
                  └─ maybeRunAnalysis()
                         ├─ PrintClusters
                         └─ PrintSchedClassInconsistencies
```

### データフロー図

```
[入力]                    [処理]                              [出力]

-opcode-name   ───▶ SnippetGenerator    ───┐
                                           │
-snippets-file ───▶ readSnippets()     ───┼──▶ BenchmarkRunner ───▶ YAML結果
                                           │     (libpfm)
-mcpu          ───▶ LLVMState          ───┘

                     [分析モード]

YAML結果       ───▶ BenchmarkClustering ───▶ Analysis ───▶ クラスターレポート
                                                      ───▶ 不整合レポート
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-exegesis.cpp | `llvm/tools/llvm-exegesis/` | ソース | メインエントリーポイント |
| BenchmarkResult.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | 結果データ構造 |
| BenchmarkRunner.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | ランナーインターフェース |
| BenchmarkRunner.cpp | `llvm/tools/llvm-exegesis/lib/` | ソース | ランナー実装 |
| LatencyBenchmarkRunner.cpp | `llvm/tools/llvm-exegesis/lib/` | ソース | レイテンシ測定 |
| UopsBenchmarkRunner.cpp | `llvm/tools/llvm-exegesis/lib/` | ソース | Uops測定 |
| LlvmState.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | LLVM状態 |
| LlvmState.cpp | `llvm/tools/llvm-exegesis/lib/` | ソース | LLVM状態実装 |
| SnippetGenerator.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | スニペット生成 |
| Analysis.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | 分析処理 |
| Analysis.cpp | `llvm/tools/llvm-exegesis/lib/` | ソース | 分析実装 |
| Clustering.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | クラスタリング |
| Clustering.cpp | `llvm/tools/llvm-exegesis/lib/` | ソース | クラスタリング実装 |
| Target.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | ターゲット抽象化 |
| PerfHelper.h | `llvm/tools/llvm-exegesis/lib/` | ヘッダ | libpfmラッパー |
