# 機能設計書 120-nimprof

## 概要

本ドキュメントは、Nim標準ライブラリの`nimprof`（Nimプロファイラ）モジュールの機能設計について記載する。このモジュールはNimプログラムの実行プロファイリング機能を提供する。

### 本機能の処理概要

nimprofモジュールは、Nimプログラムの実行時パフォーマンス分析のための組み込みプロファイラを提供する。スタックトレースベースのサンプリングにより、どの関数がどれだけの時間を消費しているかを測定する。

**業務上の目的・背景**：アプリケーションのパフォーマンス最適化において、ボトルネックを特定することは重要である。このプロファイラは、外部ツールなしでNimプログラムのパフォーマンス分析を可能にし、開発者が効率的に最適化対象を特定できるようにする。

**機能の利用シーン**：
- パフォーマンスボトルネックの特定
- 関数呼び出し頻度の分析
- メモリ割り当てパターンの分析（memProfiler）
- 開発中のパフォーマンス監視

**主要な処理内容**：
1. スタックトレースのサンプリング
2. サンプルの集計とハッシュテーブル管理
3. `profile_results.txt`への結果出力
4. `setSamplingFrequency`でサンプリング間隔設定
5. `enableProfiling`/`disableProfiling`でプロファイリング制御

**関連システム・外部連携**：
- Nimランタイム（profilingRequestedHook、profilerHook）
- スタックトレース機能
- 終了時処理（exitprocs）

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | プログラム終了時に`profile_results.txt`を出力 |

## 機能種別

プロファイリング / パフォーマンス分析

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| intervalInUs | int | No | サンプリング間隔（マイクロ秒） | > 0 または 0（命令ベース） |

### 入力データソース

実行中のプログラムのスタックトレース

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| profile_results.txt | ファイル | プロファイリング結果 |
| エントリ | テキスト | スタックトレースと呼び出し回数 |
| 合計呼び出し数 | int | 全サンプル数 |

### 出力先

カレントディレクトリの`profile_results.txt`

## 処理フロー

### 処理シーケンス

```
1. モジュールインポート時
   └─ profilingRequestedHook設定
   └─ profilerHook設定
   └─ 終了時ハンドラ登録

2. プログラム実行中
   └─ 定期的にrequestedHookが呼ばれる
   └─ サンプリング条件を満たすとprofilerHook呼び出し
   └─ スタックトレースをハッシュテーブルに記録

3. サンプリング処理
   └─ スタックトレースのハッシュを計算
   └─ 既存エントリを検索または新規作成
   └─ 呼び出しカウントをインクリメント

4. プログラム終了時
   └─ writeProfile()が呼ばれる
   └─ エントリをソート（呼び出し回数降順）
   └─ profile_results.txtに出力
```

### フローチャート

```mermaid
flowchart TD
    A[モジュールインポート] --> B[フック設定]
    B --> C[exitproc登録]
    C --> D[プログラム実行]
    D --> E{サンプリング条件?}
    E -->|No| D
    E -->|Yes| F[スタックトレース取得]
    F --> G[ハッシュ計算]
    G --> H{既存エントリ?}
    H -->|Yes| I[カウント+1]
    H -->|No| J[新規エントリ作成]
    I --> D
    J --> D
    D --> K[プログラム終了]
    K --> L[writeProfile]
    L --> M[ソート]
    M --> N[ファイル出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-120-01 | デフォルト間隔 | 5ミリ秒（5_000_000ナノ秒 - 補正値） | 特に指定なし |
| BR-120-02 | 命令ベース | intervalInUs=0で命令カウントベース | 明示的設定時 |
| BR-120-03 | ハッシュテーブル上限 | 64K-1エントリで新しいエントリが古いエントリを置換 | 上限到達時 |
| BR-120-04 | 出力上限 | 上位100エントリのみ出力 | 常時 |

### 計算ロジック

呼び出し割合 = エントリの呼び出し数 / 総呼び出し数 * 100%

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

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | コンパイルエラー | --profiler:on未指定 | コンパイルオプションを追加 |
| - | ファイルオープン失敗 | ディスク/権限問題 | "... failed"と出力 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- プロファイリング自体のオーバーヘッドを最小化
- サンプリングベースで連続実行時間への影響を軽減
- プロファイリングコード自体は{.push profiler: off.}で除外

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

- profile_results.txtに関数名が出力される
- 本番環境では無効化推奨

## 備考

- `--profiler:on --stackTrace:on`コンパイルオプションが必要
- スレッド対応（withThreads時はロック使用）
- memProfiler定義時はメモリプロファイリングモード

---

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

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

### 推奨読解順序

#### Step 1: 型定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | nimprof.nim | `lib/pure/nimprof.nim` | StackTrace型（36-38行目） |
| 1-2 | nimprof.nim | `lib/pure/nimprof.nim` | ProfileEntry/ProfileData型（42-46行目） |

**読解のコツ**: ProfileEntryは呼び出し回数(total)とスタックトレース(st)を持つ。ProfileDataは64K-1エントリの固定サイズ配列。

#### Step 2: グローバル状態を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nimprof.nim | `lib/pure/nimprof.nim` | profileData/emptySlots等（55-59行目） |
| 2-2 | nimprof.nim | `lib/pure/nimprof.nim` | interval設定（62-69行目） |
| 2-3 | nimprof.nim | `lib/pure/nimprof.nim` | ロック（スレッド対応）（71-76行目） |

#### Step 3: サンプリング処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nimprof.nim | `lib/pure/nimprof.nim` | hookAux（78-119行目） |
| 3-2 | nimprof.nim | `lib/pure/nimprof.nim` | requestedHook（145-153行目） |
| 3-3 | nimprof.nim | `lib/pure/nimprof.nim` | hook（155-161行目） |

**主要処理フロー**:
- **78-119行目**: hookAuxがハッシュテーブルにスタックトレースを登録
- **84行目**: スタックトレースの最後の関数でハッシュ計算
- **88-101行目**: 空きスロットがない場合のプロービング戦略
- **102-118行目**: 空きスロットがある場合の挿入

#### Step 4: 出力処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | nimprof.nim | `lib/pure/nimprof.nim` | writeProfile（172-213行目） |
| 4-2 | nimprof.nim | `lib/pure/nimprof.nim` | cmpEntries（166-167行目） |

**主要処理フロー**:
- **173-175行目**: フックを無効化
- **180行目**: profileDataをソート
- **197-209行目**: 上位100エントリを出力

#### Step 5: 制御関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | nimprof.nim | `lib/pure/nimprof.nim` | disableProfiling（218-221行目） |
| 5-2 | nimprof.nim | `lib/pure/nimprof.nim` | enableProfiling（223-226行目） |
| 5-3 | nimprof.nim | `lib/pure/nimprof.nim` | 初期化と終了時処理（228-232行目） |

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

```
Nimランタイム
    │
    ├─ profilingRequestedHook (インターバルチェック)
    │      └─ requestedHook()
    │             └─ 時間/カウント判定
    │
    ├─ profilerHook (サンプリング実行)
    │      └─ hook(st)
    │             └─ hookAux(st, costs)
    │                    ├─ ハッシュ計算
    │                    ├─ プロービング
    │                    └─ エントリ更新/作成
    │
    └─ exitproc
           └─ writeProfile()
                  ├─ sort(profileData, cmpEntries)
                  └─ ファイル出力
```

### データフロー図

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

スタックトレース ─▶ hookAux ───────▶ ProfileData (ハッシュテーブル)
        │
        │ (プログラム実行中、定期的にサンプリング)
        │
ProfileData ────────▶ sort ─────────▶ ソート済みリスト
        │
        └─────────────▶ writeProfile ─▶ profile_results.txt
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| nimprof.nim | `lib/pure/nimprof.nim` | ソース | プロファイラ本体 |
| timers.nim | `lib/system/timers.nim` | ソース | 時間計測 |
| exitprocs.nim | `lib/std/exitprocs.nim` | ソース | 終了時処理 |
| locks.nim | `lib/pure/locks.nim` | ソース | スレッド同期 |
