# 機能設計書 42-llvm-profgen

## 概要

本ドキュメントは、LLVM llvm-profgenツールの機能設計を記述したものである。llvm-profgenはLinux perfツールで収集した実行データからLLVMサンプルプロファイルを生成するツールである。

### 本機能の処理概要

llvm-profgenは、Sample-based Profile-Guided Optimization（SPGO）のためのプロファイル生成ツールである。Linux perfツールで収集されたブランチトレースデータやperfスクリプト出力を解析し、LLVMが最適化に利用できるサンプルプロファイル形式に変換する。

**業務上の目的・背景**：プロダクション環境で動作するバイナリから実行プロファイルを収集し、それを基にした最適化を行うAutoFDO（Automatic Feedback-Directed Optimization）は、実際のワークロードに基づいた効果的な最適化を可能にする。llvm-profgenは、このAutoFDOパイプラインにおいて、perfデータからLLVMプロファイル形式への変換を担う重要なツールである。

**機能の利用シーン**：
- プロダクション環境で収集したperfデータからプロファイルを生成する場合
- サンプリングベースの軽量プロファイリングを最適化に活用する場合
- コンテキスト依存プロファイル（CSSPGO）を生成する場合
- バイナリの逆アセンブリと行番号マッピングを確認する場合

**主要な処理内容**：
1. perfデータ（perf.data）またはperfスクリプト出力の読み込み
2. バイナリのデバッグ情報（DWARF）を利用したシンボル化
3. ブランチトレースからの実行フロー再構築
4. サンプルカウントの集計とプロファイル生成
5. コンテキスト依存プロファイルの生成（オプション）

**関連システム・外部連携**：
- Linux perfツール（データ収集元）
- バイナリ実行ファイルとデバッグ情報
- llvm-profdataとの連携（プロファイルマージ）

**権限による制御**：特になし（ローカルファイル操作のみ）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | コマンドライン | 主画面 | オプション指定とプロファイル生成 |

## 機能種別

データ変換処理 / プロファイル生成処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --binary | string | Yes | プロファイル対象の実行バイナリ | ファイル存在チェック |
| --perfscript / --ps | string | No | perf scriptの出力ファイル | ファイル存在チェック |
| --perfdata / --pd | string | No | perf.dataファイル | ファイル存在チェック |
| --unsymbolized-profile / --up | string | No | 非シンボル化プロファイル | ファイル存在チェック |
| --debug-binary | string | No | デバッグ情報を持つバイナリ | ファイル存在チェック |
| --output / -o | string | Yes | 出力プロファイルファイル | 書き込み可能パス |
| --pid | uint32 | No | 対象プロセスID | 正の整数 |
| --format | enum | No | 出力形式（binary/extbinary/text） | 有効な形式 |

### 入力データソース

- Linux perf script出力（-b オプションでブランチ記録を含む）
- Linux perf.data 生データ
- プロファイル対象の実行バイナリ（ELFフォーマット）
- デバッグ情報ファイル（DWARFフォーマット）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| サンプルプロファイル | binary/text | LLVM形式のサンプルプロファイル |
| 非シンボル化プロファイル | text | シンボル化前の中間プロファイル |
| 逆アセンブリ出力 | text | バイナリの逆アセンブリ（--show-disassembly-only） |

### 出力先

- 指定された出力ファイル
- 標準出力（逆アセンブリ表示時）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数の検証
   └─ 入力ファイルの存在確認、オプションの整合性チェック
2. バイナリの読み込みとシンボル情報の解析
   └─ ProfiledBinaryクラスによるELF/DWARF解析
3. perf入力データの解析
   └─ PerfReaderによるブランチトレース読み込み
4. サンプルカウントの集計
   └─ 各命令アドレスのヒットカウント集計
5. シンボル化処理
   └─ アドレスから関数名・行番号へのマッピング
6. プロファイル生成
   └─ ProfileGeneratorによるサンプルプロファイル生成
7. プロファイル出力
   └─ 指定形式でのファイル出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[コマンドライン解析]
    B --> C{入力種別判定}
    C -->|perfscript| D[perf script読込]
    C -->|perfdata| E[perf.data読込]
    C -->|unsymbolized| F[中間プロファイル読込]
    D --> G[ProfiledBinary作成]
    E --> G
    F --> G
    G --> H[PerfReader作成]
    H --> I[トレース解析]
    I --> J{--show-disassembly-only?}
    J -->|Yes| K[逆アセンブリ出力]
    J -->|No| L[ProfileGenerator作成]
    K --> M[終了]
    L --> N[プロファイル生成]
    N --> O[プロファイル出力]
    O --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-42-01 | 入力排他 | perfscript/perfdata/unsymbolized-profileは1つのみ指定可能 | 常時 |
| BR-42-02 | バイナリ必須 | --binaryオプションは必須 | 常時 |
| BR-42-03 | ブランチデータ | perfデータは-bオプション付きで収集されている必要がある | perf入力時 |

### 計算ロジック

- サンプルカウント: ブランチトレース内の各ターゲットアドレスの出現回数
- コンテキスト: コールスタック情報に基づく関数呼び出しコンテキスト
- ディスクリミネータ: 同一行番号の異なるインスタンスを区別

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

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

該当なし（ファイルベースの処理）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 入力競合 | 複数の入力形式を同時指定 | 1つの入力形式のみ指定 |
| - | ファイル不在 | バイナリまたはperfデータが存在しない | ファイルパスを確認 |
| - | デバッグ情報なし | バイナリにDWARF情報がない | --debug-binaryを指定 |
| - | 形式不正 | perfデータ形式が不正 | -bオプション付きで再収集 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 大規模perfトレース（数GB）の処理をサポート
- ストリーミング処理による効率的なメモリ使用

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

- バイナリファイルの検証
- 入力ファイルのサニタイズ

## 備考

- SPGO（Sample-based Profile-Guided Optimization）の主要ツール
- CSSPGO（Context-Sensitive Sample PGO）をサポート
- Pseudo-probe based profilingに対応

---

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

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

### 推奨読解順序

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

プロファイル生成に関わる主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ProfiledBinary.h | `llvm/tools/llvm-profgen/ProfiledBinary.h` | バイナリ解析データ構造 |
| 1-2 | PerfReader.h | `llvm/tools/llvm-profgen/PerfReader.h` | perfデータ読み込み構造 |
| 1-3 | ProfileGenerator.h | `llvm/tools/llvm-profgen/ProfileGenerator.h` | プロファイル生成構造 |

**読解のコツ**: ProfiledBinaryはバイナリの静的解析結果を、PerfReaderは動的トレースデータを保持する。両者を組み合わせてプロファイルを生成する。

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

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

**主要処理フロー**:
1. **32-68行目**: コマンドラインオプション定義
2. **83-129行目**: validateCommandLine()によるオプション検証
3. **148-164行目**: main()関数のターゲット初期化
4. **161-214行目**: メイン処理フロー

#### Step 3: バイナリ解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ProfiledBinary.cpp | `llvm/tools/llvm-profgen/ProfiledBinary.cpp` | バイナリ解析実装 |

**主要処理フロー**:
- ELFファイルの読み込みと解析
- DWARFデバッグ情報の抽出
- 関数境界の特定
- 逆アセンブリの実行

#### Step 4: perfデータ読み込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PerfReader.cpp | `llvm/tools/llvm-profgen/PerfReader.cpp` | perf読み込み実装 |

**主要処理フロー**:
- perf scriptフォーマットの解析
- ブランチトレースの抽出
- アドレス範囲の計算

#### Step 5: プロファイル生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | ProfileGenerator.cpp | `llvm/tools/llvm-profgen/ProfileGenerator.cpp` | プロファイル生成実装 |

**主要処理フロー**:
- **23-28行目**: 出力オプション定義
- **131-160行目**: ProfileGeneratorBase::create()ファクトリメソッド
- **162-190行目**: プロファイル書き込み処理

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

```
main()
    │
    ├─ InitializeAllTargetInfos/MCs/Disassemblers()
    │
    ├─ validateCommandLine()
    │
    ├─ ProfiledBinary(BinaryPath, DebugBinPath)
    │      ├─ ELFファイル読込
    │      ├─ DWARF解析
    │      └─ 逆アセンブリ
    │
    ├─ PerfReaderBase::create()
    │      └─ parsePerfTraces()
    │
    └─ ProfileGeneratorBase::create()
           ├─ generateProfile()
           └─ write()
```

### データフロー図

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

perf.data / script ───▶ PerfReader        ───┐
                                              ├──▶ ProfileGenerator ───▶ .prof
binary (ELF)       ───▶ ProfiledBinary    ───┘
                        + DWARF解析
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| llvm-profgen.cpp | `llvm/tools/llvm-profgen/` | ソース | メインエントリーポイント |
| ProfiledBinary.cpp | `llvm/tools/llvm-profgen/` | ソース | バイナリ解析 |
| ProfiledBinary.h | `llvm/tools/llvm-profgen/` | ヘッダ | バイナリ解析インターフェース |
| PerfReader.cpp | `llvm/tools/llvm-profgen/` | ソース | perfデータ読み込み |
| PerfReader.h | `llvm/tools/llvm-profgen/` | ヘッダ | perf読み込みインターフェース |
| ProfileGenerator.cpp | `llvm/tools/llvm-profgen/` | ソース | プロファイル生成 |
| ProfileGenerator.h | `llvm/tools/llvm-profgen/` | ヘッダ | プロファイル生成インターフェース |
| CSPreInliner.cpp | `llvm/tools/llvm-profgen/` | ソース | コンテキスト依存プリインライン |
| MissingFrameInferrer.cpp | `llvm/tools/llvm-profgen/` | ソース | 欠落フレーム推論 |
