# 帳票設計書 3-スクリプトプロファイラーCSV

## 概要

本ドキュメントは、GDScriptやC#スクリプトの実行時間プロファイリングデータをCSV形式でエクスポートする帳票の設計書である。

### 本帳票の処理概要

本帳票は、Godotエディタのスクリプトプロファイラーで収集した関数ごとの実行時間データをCSV形式で出力する機能を提供する。各関数の呼び出し回数、自己時間（self time）、合計時間（total time）などのメトリクスを時系列で記録し、スクリプトのパフォーマンス分析に使用できる形式で出力する。

**業務上の目的・背景**：ゲーム開発において、スクリプトの実行パフォーマンスは全体のフレームレートに直接影響する。特にGDScriptのような動的言語では、最適化されていないコードがボトルネックになることが多い。本帳票により、どの関数がどれだけの時間を消費しているかを定量的に分析し、最適化対象を特定できる。

**帳票の利用シーン**：主に以下のシーンで利用される。1) フレームレート低下の原因調査時、2) 特定スクリプトのパフォーマンスチューニング時、3) コード変更前後のパフォーマンス比較時、4) 継続的なパフォーマンス監視。

**主要な出力内容**：
1. 関数/メソッドのシグネチャ（スクリプトパス::関数名）
2. カテゴリごとの合計時間
3. 各項目の合計実行時間
4. フレームごとの時系列データ

**帳票の出力タイミング**：パフォーマンスモニターCSVの一部として出力される（パフォーマンスモニターCSVのエクスポート時に自動的に追加される）。

**帳票の利用者**：ゲームプログラマー、スクリプトエンジニア、パフォーマンス最適化担当者

## 帳票種別

データエクスポート / プロファイリングデータ一覧

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| 15 | デバッガ | エディタ内蔵（Debugger Panel） | Monitorsタブの「Export CSV」ボタン |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | CSV（パフォーマンスモニターCSVの一部） |
| 用紙サイズ | N/A（データファイル） |
| 向き | N/A |
| ファイル名 | パフォーマンスモニターCSVと同一ファイル |
| 出力方法 | ファイルダイアログでのファイル保存 |
| 文字コード | UTF-8 |

### CSV固有設定

| 項目 | 内容 |
|-----|------|
| 区切り文字 | カンマ（,） |
| 囲み文字 | ダブルクォート（必要時） |
| ヘッダー行 | あり（1行目にシグネチャ名列挙） |

## 帳票レイアウト

### レイアウト概要

プロファイラーデータはパフォーマンスモニターデータの後に空行を挟んで出力される。

```
┌─────────────────────────────────────────────────────────────┐
│              ヘッダー行（シグネチャ列挙）                      │
├─────────────────────────────────────────────────────────────┤
│              データ行（フレームごとの時間値）                   │
│              ...（フレーム数分の行）                          │
└─────────────────────────────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1〜N | シグネチャ名 | 関数/カテゴリの識別名 | possible_signatures | 文字列 |

シグネチャ名の例：
- `res://scripts/player.gd::_physics_process` - 関数のシグネチャ
- `Physics` - カテゴリ名

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1〜N | 時間値 | 対応シグネチャの実行時間（秒） | Metric::Category::total_time / Item::total | 実数 | 可変 |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| デバッガ接続 | リモートデバッガがゲームに接続している必要がある | Yes |
| プロファイラーデータ蓄積 | スクリプトプロファイラーでデータが収集されている必要がある | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | フレーム順（時系列） | last_metricから循環的に |

### 改ページ条件

N/A（CSVファイルのため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを参照せず、インメモリのプロファイラーデータを使用する。

| データソース | 用途 | 取得方法 |
|-----------|------|---------|
| EditorProfiler::frame_metrics | フレームごとのメトリクスデータ | メンバー変数直接アクセス |
| Metric::category_ptrs | カテゴリポインタマップ | HashMapイテレーション |
| Metric::item_ptrs | アイテムポインタマップ | HashMapイテレーション |

### テーブル別参照項目詳細

#### Metric構造体

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| valid | 有効データ判定 | フレームごとにチェック | falseならスキップ |
| category_ptrs | カテゴリ情報 | KeyValueイテレーション | キー=シグネチャ、値=Category* |
| item_ptrs | アイテム情報 | KeyValueイテレーション | キー=シグネチャ、値=Item* |

#### Metric::Category構造体

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| total_time | 時間値 | category_ptrs経由 | カテゴリの合計時間 |

#### Metric::Category::Item構造体

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| total | 時間値 | item_ptrs経由 | 関数の合計時間 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| 時間値（カテゴリ） | String::num_real(E.value->total_time) | なし | 実数をそのまま文字列化 |
| 時間値（アイテム） | String::num_real(E.value->total) | なし | 実数をそのまま文字列化 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[get_data_as_csv呼び出し] --> B{frame_metrics空?}
    B -->|Yes| C[空のVectorを返却]
    B -->|No| D[全フレームからシグネチャ収集]
    D --> E[possible_signaturesにユニーク化]
    E --> F[sig_mapにインデックス割り当て]
    F --> G[ヘッダー行signaturesを生成]
    G --> H[res.push_back signaturesを追加]
    H --> I[last_metricからループ開始]
    I --> J{現在フレーム有効?}
    J -->|No| K[次のフレームへ]
    J -->|Yes| L[values配列をクリア・リサイズ]
    L --> M[category_ptrsからtotal_time取得]
    M --> N[item_ptrsからtotal取得]
    N --> O[res.push_back valuesを追加]
    O --> P{全フレーム処理完了?}
    P -->|No| K
    K --> I
    P -->|Yes| Q[resを返却]
    C --> R[終了]
    Q --> R
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| データなし | frame_metricsが空 | なし | 空のVectorを返却 |
| 無効フレーム | Metric::valid == false | なし | 該当フレームをスキップ |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千フレーム分 |
| 目標出力時間 | 1秒未満 |
| 同時出力数上限 | 1（シングル処理） |

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

- スクリプトパスからプロジェクト構造が推測可能
- 関数名からロジック構成が推測可能な場合がある
- 機密性の高いプロジェクトでは出力ファイルの管理に注意

## 備考

- シグネチャはフレームごとに異なる可能性があるため、全フレームから収集してユニーク化する
- 空のセルは対応するシグネチャがそのフレームに存在しなかったことを示す

---

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

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

### 推奨読解順序

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

まず、プロファイラーのメトリクス構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | editor_profiler.h | `editor/debugger/editor_profiler.h` | Metricクラス構造、valid、category_ptrs、item_ptrsの定義 |
| 1-2 | editor_profiler.h | `editor/debugger/editor_profiler.h` | Metric::Category、Metric::Category::Itemの構造 |

**読解のコツ**: C++のHashMapを使用したポインタマップに注目。キーがStringName（シグネチャ）、値がCategory*/Item*へのポインタ。

#### Step 2: CSV出力実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | editor_profiler.cpp | `editor/debugger/editor_profiler.cpp` | get_data_as_csv()（600-667行目）の実装全体 |

**主要処理フロー**:
1. **603-605行目**: frame_metricsが空の場合は即座に空Vectorを返却
2. **608-620行目**: 全フレームをイテレートしてpossible_signaturesにシグネチャを収集
3. **623-632行目**: sig_mapを作成し、シグネチャからインデックスへのマッピングを構築
4. **634行目**: res.push_back(signatures)でヘッダー行を追加
5. **637-664行目**: last_metricから循環的にフレームデータを出力

#### Step 3: データ収集の流れを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | editor_profiler.cpp | `editor/debugger/editor_profiler.cpp` | add_frame_metric()でフレームデータがどのように追加されるか |

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

```
EditorProfiler::get_data_as_csv()
    │
    ├─ frame_metrics.is_empty() チェック
    │      └─ [空なら空Vector返却]
    │
    ├─ possible_signatures収集ループ
    │      │
    │      ├─ Metric::category_ptrs イテレーション
    │      │      └─ possible_signatures.insert(E.key)
    │      │
    │      └─ Metric::item_ptrs イテレーション
    │             └─ possible_signatures.insert(E.key)
    │
    ├─ sig_map構築ループ
    │      └─ sig_map[E] = sig_index++
    │
    ├─ res.push_back(signatures) [ヘッダー行]
    │
    └─ フレームデータ出力ループ
           │
           ├─ Metric::valid チェック
           │
           ├─ category_ptrs イテレーション
           │      └─ values[sig_map[E.key]] = num_real(total_time)
           │
           ├─ item_ptrs イテレーション
           │      └─ values[sig_map[E.key]] = num_real(total)
           │
           └─ res.push_back(values)
```

### データフロー図

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

リモートプロセス ─────────▶ プロファイリング ──────────────▶ frame_metrics
                              データ収集                    (Vector<Metric>)
                                                                │
                                                                │
frame_metrics ───────────▶ シグネチャ収集 ─────────────────▶ possible_signatures
      │                                                    (HashSet<StringName>)
      │                                                         │
      │                                                         │
      │                   sig_map構築 ◀─────────────────────────┘
      │                        │
      │                        ▼
      │                   ヘッダー行生成 ──────────────────▶ CSVヘッダー行
      │                                                         │
      │                                                         │
      └──────────────────▶ フレームデータ変換 ──────────────▶ CSVデータ行
                               │
                               ▼
                        Vector<Vector<String>> res
                               │
                               ▼
                          [CSV出力]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| editor_profiler.h | `editor/debugger/editor_profiler.h` | ヘッダー | EditorProfilerクラス定義、Metric構造体 |
| editor_profiler.cpp | `editor/debugger/editor_profiler.cpp` | ソース | get_data_as_csv()の実装 |
| script_editor_debugger.cpp | `editor/debugger/script_editor_debugger.cpp` | ソース | get_data_as_csv()の呼び出し元（223行目） |
| string_name.h | `core/string/string_name.h` | ヘッダー | StringNameクラス（シグネチャのキー型） |
