# 帳票設計書 12-pprofプロファイルレポート

## 概要

本ドキュメントは、TensorFlowモデルのプロファイリング結果をpprof形式で出力するpprofプロファイルレポートの設計について記述する。Google pprofツールチェーンと互換性のある`profile.proto`形式でプロファイルデータを生成し、デバイス別の圧縮protobufファイルとして出力する。

### 本帳票の処理概要

本帳票は、TensorFlowセッションの実行メタデータ（RunMetadata）とグラフ情報からオペレーション単位のプロファイリングデータを抽出し、pprof形式のプロファイルとしてデバイス別に出力する機能を提供する。

**業務上の目的・背景**：TensorFlowモデルの実行パフォーマンスを詳細に分析するために、Google pprofツールチェーンと互換性のあるプロファイルデータが必要である。pprofはフレームグラフやコールグラフ等の多様な可視化をサポートしており、ボトルネックの特定に有効である。TensorFlow 1.x系（compat.v1）のSession APIと組み合わせて使用する。

**帳票の利用シーン**：モデルの学習・推論パフォーマンスの詳細分析、オペレーション単位の実行時間の可視化、Pythonコールスタックの分析、デバイス間のパフォーマンス比較などの場面で利用される。

**主要な出力内容**：
1. デバイス別のpprofプロファイルデータ（gzip圧縮protobuf）
2. サンプル統計情報：count（実行回数）、all_time（全体時間）、op_time（オペレーション時間）
3. 関数位置情報（ファイルパス、関数名、行番号）
4. Pythonコールスタックのトレースバック情報

**帳票の出力タイミング**：`pprof_profiler.profile(graph, run_metadata, output_dir)` 関数を呼び出した時点で、指定されたoutput_dirにデバイス別のプロファイルファイルが出力される。セッション実行後にRunMetadataを取得してから呼び出す。

**帳票の利用者**：機械学習エンジニア、パフォーマンスチューニング担当者、システム最適化エンジニア

## 帳票種別

プロファイリングデータ / パフォーマンス分析レポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | CLIインターフェース | - | `pprof_profiler.profile()` 関数呼び出し |
| - | pprofビューア | pprofコマンドラインまたはWebUI | `pprof -png output.pb.gz` 等で可視化 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | gzip圧縮Protocol Buffers（profile.proto準拠） |
| 用紙サイズ | N/A（電子データ） |
| 向き | N/A |
| ファイル名 | `{デバイス名}_{YYYYMMDDHHmmss}.pb.gz`（デバイス名の`/`と`:`は`_`に変換） |
| 出力方法 | ファイルシステムへの書き出し（output_dir指定）または標準出力 |
| 文字コード | バイナリ（Protocol Buffers + gzip） |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

pprofプロファイルはprotobuf形式のバイナリデータであり、pprofツールで解析・可視化する。データ構造は以下の要素で構成される。

```
┌─────────────────────────────────────┐
│          profile.proto              │
├─────────────────────────────────────┤
│  sample_type[]                      │
│   - count (count)                   │
│   - all_time (nanoseconds)          │
│   - op_time (nanoseconds)           │
├─────────────────────────────────────┤
│  sample[]                           │
│   - value[] (count, all_time,       │
│     op_time)                        │
│   - location_id[]                   │
│   - label[] (node_name, op_type)    │
├─────────────────────────────────────┤
│  location[]                         │
│   - id, line[]                      │
├─────────────────────────────────────┤
│  function[]                         │
│   - id, name, filename, start_line  │
├─────────────────────────────────────┤
│  string_table[]                     │
│  comment[] (device description)     │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | sample_type | サンプルの種別定義（count, all_time, op_time） | 固定定義 | protobuf |
| 2 | comment | デバイス説明（"Device X of Y: device_name"） | run_metadata.step_stats.dev_stats | protobuf |
| 3 | string_table | 全文字列のインターン化テーブル | StringTableクラス | protobuf |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | sample.value[0] | count - ノードの実行回数 | ProfileDatum集計 | 整数 | 可変 |
| 2 | sample.value[1] | all_time - ノードの全体実行時間（ナノ秒） | node_exec_stats.all_end_rel_micros | 整数 | 可変 |
| 3 | sample.value[2] | op_time - オペレーション実行時間（ナノ秒） | op_end_rel_micros - op_start_rel_micros | 整数 | 可変 |
| 4 | sample.label | node_name, op_typeのラベル | graph.get_operations() | 文字列 | 可変 |
| 5 | sample.location_id | コールスタックの位置情報 | op.traceback | 整数配列 | 可変 |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | function | 関数定義情報（id, name, filename, start_line） | Functionsクラス | protobuf |
| 2 | location | 位置情報（id, line） | Locationsクラス | protobuf |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| graph | TensorFlowのGraphオブジェクト | Yes |
| run_metadata | セッション実行のRunMetadataプロト | Yes |
| output_dir | 出力先ディレクトリ（Noneの場合は標準出力） | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | デバイスインデックス | 昇順 |

### 改ページ条件

該当なし（デバイスごとに個別ファイルとして出力）

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

### 参照テーブル一覧

本帳票はデータベースを参照しない。TensorFlowのGraphオブジェクトとRunMetadataから実行時情報を取得する。

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | N/A | N/A |

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

該当なし

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| op_time | op_end_rel_micros - op_start_rel_micros | なし（整数演算） | NodeExecStatsから取得（行244-246） |
| count | 同一ノード名のサンプル出現回数の累積加算 | なし | sample.value[0] += 1（行242） |
| all_time | all_end_rel_microsの累積加算 | なし | sample.value[1]に加算（行243） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[profile graph, run_metadata, output_dir] --> B[PprofProfiler生成]
    B --> C[get_profiles実行]
    C --> D[_get_profile_data_generator生成]
    D --> E{各デバイスについてループ}
    E --> F[_get_pprof_proto生成]
    F --> G[ProfileDatumのイテレーション]
    G --> H[traceback解析・Location/Sample構築]
    H --> I{全デバイス処理完了?}
    I -->|No| E
    I -->|Yes| J{output_dirが指定?}
    J -->|Yes| K[gzip圧縮してファイル出力]
    J -->|No| L[標準出力に表示]
    K --> M[終了]
    L --> M
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| データ不足 | デバイスのサンプルデータが空 | "Not enough data to create profile for device %s. Did you pass RunMetadata to session.run call?" | session.run呼び出し時にrun_metadataを渡す |
| 出力先なし | output_dirがNone | "No output directory specified, printing to stdout instead." | output_dirを指定するか標準出力を利用 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | グラフのオペレーション数 x デバイス数（数百〜数万ノード） |
| 目標出力時間 | グラフサイズに依存（数秒〜数十秒） |
| 同時出力数上限 | 制限なし（スレッドセーフではない） |

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

- プロファイルデータにはモデルのオペレーション構造、ファイルパス、関数名が含まれるため、出力ディレクトリのアクセス権限を適切に設定する必要がある
- tracebackにはソースコードのファイルパスと行番号が含まれるため、外部公開時には注意が必要
- gzip圧縮されているが暗号化はされていない

## 備考

- TensorFlow 1.x系（compat.v1）のSession APIを前提とした設計。trace_levelをFULL_TRACEに設定し、run_metadataをsession.runに渡す必要がある
- pprofツール（`go tool pprof`）で `pprof -png --nodecount=100 --sample_index=1 output.pb.gz` のように可視化可能
- sample_indexは0=count, 1=all_time, 2=op_timeに対応
- `_SOURCE`と`_SINK`ノードはプロファイルから除外される（行374）
- `apply_op`より前のコールスタックフレームは全オペレーション共通のため除外される（行331-334）

---

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

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

### 推奨読解順序

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

pprofプロファイルの基礎となるデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | ProfileDatum namedtuple（行55-56）：node_exec_stats, op_type, tracebackの3フィールドを持つプロファイルデータの基本単位 |
| 1-2 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | StringTableクラス（行59-97）：pprofプロトコルで必須の文字列テーブル。全文字列をインデックスで管理し、最初のエントリは空文字列 |
| 1-3 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | Functionsクラス（行100-141）：(file_path, function_name, start_line_number)のタプルをキーとして関数情報を管理 |
| 1-4 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | Locationsクラス（行144-198）：関数呼び出し位置情報を管理。(file_path, called_function_name, line_number)をキーとする |
| 1-5 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | Samplesクラス（行201-250）：ノード名をキーとしてサンプルデータ（count, all_time, op_time）を集計 |

**読解のコツ**: pprofのProfile proto仕様（https://github.com/google/pprof/blob/master/proto/profile.proto）を事前に確認すると、各クラスの役割が理解しやすい。StringTable, Functions, Locations, Samplesの4クラスがprotobufのフィールドに1対1対応している。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | profile()関数（行400-440）がメインのエントリーポイント。graph, run_metadata, output_dirを引数に取り、デバイス別にgzip圧縮したpb.gzファイルを出力 |
| 2-2 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | get_profiles()関数（行384-397）はPprofProfilerを生成してprofile()メソッドを呼ぶラッパー |

**主要処理フロー**:
1. **行418**: get_profiles(graph, run_metadata)でプロファイルデータ取得
2. **行420-425**: output_dir指定時、ディレクトリ作成とファイル名テンプレート生成（タイムスタンプ付き）
3. **行428-439**: デバイスごとにprotobufをgzip圧縮してファイル出力

#### Step 3: プロファイル生成の核心部を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | PprofProfiler.profile()メソッド（行269-296）：デバイスごとにpprof protoを生成する主要ロジック |
| 3-2 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | _get_pprof_proto()メソッド（行298-358）：ProfileDatumジェネレータからprotobufのProfile構造を組み立てる |
| 3-3 | pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | _get_profile_data_generator()メソッド（行360-381）：グラフオペレーションからtraceback/op_typeを収集し、デバイスステップ統計からProfileDatumをyieldするジェネレータ |

**主要処理フロー**:
- **行310-338**: tracebackを逆順に走査し、apply_op以降のスタックフレームからLocation情報を構築
- **行341-352**: sample_type（count, all_time, op_time）をprotobufに設定
- **行354-357**: string_table, sample, function, locationをprotobufに格納

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

```
profile(graph, run_metadata, output_dir)  [行400]
    |
    +-- get_profiles(graph, run_metadata)  [行384]
    |       |
    |       +-- PprofProfiler(graph, run_metadata)  [行253]
    |       |       +-- StringTable()  [行59]
    |       |       +-- Functions(string_table)  [行100]
    |       |       +-- Locations(functions)  [行144]
    |       |
    |       +-- PprofProfiler.profile()  [行269]
    |               |
    |               +-- _get_profile_data_generator()  [行360]
    |               |       +-- graph.get_operations()
    |               |       +-- yield ProfileDatum(...)
    |               |
    |               +-- _get_pprof_proto(generator)  [行298]
    |                       +-- Samples(string_table)  [行201]
    |                       +-- samples.add(datum, location_ids)
    |                       +-- locations.index_of(...)
    |                       +-- profile_pb2.Profile()
    |
    +-- gzip.open(profile_file, 'w')  [行437]
            +-- pprof_proto.SerializeToString()
```

### データフロー図

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

Graph                  -----> get_operations()          ----->
  (op.name,                   node_to_traceback構築
   op.type,                   node_to_op_type構築
   op.traceback)

RunMetadata            -----> step_stats.dev_stats      ----->
  (step_stats.                ProfileDatum生成
   dev_stats[].               (node_exec_stats,
   node_stats[])              op_type, traceback)

                              _get_pprof_proto()        ----->  {device}_{timestamp}.pb.gz
                              traceback解析                     (デバイスごとに1ファイル)
                              Location/Sample構築
                              profile_pb2.Profile構築
                              gzip圧縮・シリアライズ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pprof_profiler.py | `tensorflow/python/profiler/pprof_profiler.py` | ソース | pprofプロファイラの主要実装。StringTable, Functions, Locations, Samples, PprofProfilerクラスとprofile/get_profiles関数を提供 |
| profile_pb2 | `proto/profile_pb2` | 生成コード | pprofのprotobuf定義から生成されたPythonコード。Profile, Sample, Location, Function等のメッセージ型 |
