# 機能設計書 29-perf_hooks

## 概要

本ドキュメントは、Node.jsのperf_hooksモジュールの機能設計について記述する。perf_hooksモジュールは、W3C Performance Timeline仕様に基づいたパフォーマンス計測機能を提供し、ユーザータイミング（マーク・メジャー）、リソースタイミング、イベントループ遅延監視、関数実行時間計測などの機能を実現する。

### 本機能の処理概要

**業務上の目的・背景**：perf_hooksモジュールは、Node.jsアプリケーションのパフォーマンス計測と分析のための標準的なAPIを提供する。ブラウザのPerformance APIとの互換性を持ちながら、Node.js固有のイベントループ監視機能も提供する。

**機能の利用シーン**：
- アプリケーションの処理時間を計測する際
- 特定のコードセクションの実行時間をマーク・メジャーで計測する際
- イベントループの遅延を監視する際
- 関数の実行時間を自動計測する際
- GC（ガベージコレクション）の統計を取得する際
- HTTP/HTTP2リクエストのパフォーマンスを計測する際

**主要な処理内容**：
1. `performance.now()` - 高精度タイムスタンプを取得
2. `performance.mark(name, options)` - パフォーマンスマークを作成
3. `performance.measure(name, startMark, endMark)` - 2点間の時間を計測
4. `performance.getEntries()` / `getEntriesByType(type)` / `getEntriesByName(name)` - エントリの取得
5. `performance.clearMarks()` / `clearMeasures()` / `clearResourceTimings()` - エントリのクリア
6. `PerformanceObserver` - パフォーマンスエントリの監視
7. `monitorEventLoopDelay(options)` - イベントループ遅延の監視
8. `timerify(fn, options)` - 関数実行時間の自動計測
9. `eventLoopUtilization()` - イベントループ使用率の取得
10. `createHistogram()` - ヒストグラムの作成

**関連システム・外部連携**：
- internalBinding('performance') - ネイティブパフォーマンス機能
- internal/perf/performance - Performanceクラス
- internal/perf/observe - PerformanceObserverクラス
- internal/perf/usertiming - mark/measureの実装

**権限による制御**：特になし。すべての機能は任意のユーザーコードから利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 2 | System Analyzer | 補助機能 | パフォーマンスデータの可視化 |
| 4 | Turbolizer | 補助機能 | V8最適化のパフォーマンス分析 |

## 機能種別

パフォーマンス計測 / 監視 / プロファイリング

## 入力仕様

### 入力パラメータ

#### performance.mark

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | マーク名 | validateString |
| options | Object | No | オプション | validateObject |
| options.startTime | number | No | 開始時刻（デフォルト: now()） | validateNumber >= 0 |
| options.detail | any | No | 詳細データ | structuredClone |

#### performance.measure

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | メジャー名 | validateString |
| startOrMeasureOptions | string \| Object | No | 開始マーク名またはオプション | - |
| endMark | string | No | 終了マーク名 | - |

#### PerformanceObserver.observe

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| options | Object | Yes | 監視オプション | validateObject |
| options.entryTypes | string[] | Cond | 監視するエントリタイプ | ArrayIsArray |
| options.type | string | Cond | 単一のエントリタイプ | - |
| options.buffered | boolean | No | バッファされたエントリを含めるか | - |

#### timerify

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fn | Function | Yes | 計測対象の関数 | validateFunction |
| options | Object | No | オプション | validateObject |
| options.histogram | RecordableHistogram | No | 結果を記録するヒストグラム | isHistogram |

#### monitorEventLoopDelay

| パラメータ名 名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| options | Object | No | オプション | validateObject |
| options.resolution | number | No | サンプリング間隔（ミリ秒、デフォルト: 10） | validateNumber |

### 入力データソース

プログラムコードからの直接呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| performance.now()戻り値 | number | ミリ秒単位の高精度タイムスタンプ |
| performance.mark()戻り値 | PerformanceMark | 作成されたマークエントリ |
| performance.measure()戻り値 | PerformanceMeasure | 作成されたメジャーエントリ |
| PerformanceEntry.name | string | エントリ名 |
| PerformanceEntry.entryType | string | エントリタイプ |
| PerformanceEntry.startTime | number | 開始時刻 |
| PerformanceEntry.duration | number | 期間 |

### 出力先

- 関数戻り値（PerformanceEntry、配列等）
- PerformanceObserverコールバック

## 処理フロー

### 処理シーケンス

```
1. パフォーマンスエントリの作成（mark/measure）
   └─ エントリをバッファに追加
   └─ 監視中のObserverに通知
2. PerformanceObserverの監視
   └─ observe()でエントリタイプを登録
   └─ エントリ作成時にコールバック呼び出し
3. エントリの取得
   └─ getEntries/getEntriesByType/getEntriesByName
4. バッファのクリア
   └─ clearMarks/clearMeasures/clearResourceTimings
```

### フローチャート

```mermaid
flowchart TD
    A[performance.mark] --> B[PerformanceMark作成]
    B --> C[markTimings Mapに登録]
    C --> D[enqueue - Observer通知]
    D --> E[bufferUserTiming - バッファ追加]

    F[performance.measure] --> G[開始/終了時刻計算]
    G --> H[PerformanceMeasure作成]
    H --> I[enqueue]
    I --> J[bufferUserTiming]

    K[PerformanceObserver.observe] --> L{entryTypesまたはtype?}
    L -->|entryTypes| M[複数タイプ監視モード]
    L -->|type| N[単一タイプ監視モード]
    M --> O[kObserversに登録]
    N --> O

    P[エントリ作成] --> Q[kObserversをイテレート]
    Q --> R[kMaybeBuffer]
    R --> S{監視対象タイプ?}
    S -->|はい| T[バッファに追加]
    T --> U[setImmediateでコールバック]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | サポートエントリタイプ | dns, function, gc, http, http2, mark, measure, net, resource | observe時 |
| BR-002 | 監視モード排他 | entryTypesとtypeは同時に指定不可 | observe時 |
| BR-003 | 監視モード変更不可 | 一度設定した監視モードは変更不可 | observe再呼び出し時 |
| BR-004 | GCトラッキング | gc監視時のみネイティブGCトラッキングを有効化 | observe(gc) |
| BR-005 | バッファ警告 | mark/measureが100万件超でメモリリーク警告 | bufferUserTiming |
| BR-006 | リソースタイミングバッファ | デフォルト250件、超過時resourcetimingbufferffullイベント | bufferResourceTiming |
| BR-007 | 予約済みマーク名 | nodeStart, v8Start等の名前は使用不可 | mark作成時 |

### 計算ロジック

#### measure期間計算（calculateStartDuration）
1. startOrMeasureOptionsがオブジェクトの場合: start, end, durationから計算
2. endMarkが指定されている場合: getMark(endMark)で終了時刻取得
3. 開始時刻はデフォルト0、終了時刻はデフォルトnow()
4. duration = end - start

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

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

本モジュールはデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| ERR_ILLEGAL_CONSTRUCTOR | TypeError | Performance/PerformanceMeasure/PerformanceObserverEntryListを直接new | 内部的にのみ使用 |
| ERR_MISSING_ARGS | TypeError | 必須引数が不足 | 必須引数を指定 |
| ERR_INVALID_ARG_TYPE | TypeError | 引数の型が不正 | 正しい型の引数を渡す |
| ERR_INVALID_ARG_VALUE | RangeError | 引数の値が不正 | 有効な値を指定 |
| ERR_PERFORMANCE_INVALID_TIMESTAMP | RangeError | startTimeが負の値 | 0以上の値を指定 |
| ERR_PERFORMANCE_MEASURE_INVALID_OPTIONS | TypeError | measure optionsの指定が不正 | 正しいオプション組み合わせ |
| SyntaxError (DOMException) | DOMException | 存在しないマーク名を参照 | mark()で先に作成 |
| InvalidModificationError (DOMException) | DOMException | 監視モードの変更を試行 | 新しいObserverを作成 |

### リトライ仕様

リトライ処理は行わない。

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

トランザクション処理は行わない。

## パフォーマンス要件

- now()はネイティブで高精度タイムスタンプを取得
- Observerコールバックはマイクロタスクキューでバッチ処理
- mark/measureバッファは100万件超で警告
- resourceTimingバッファは250件でイベント発行

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

特になし。パフォーマンス計測用途のため。

## 備考

- performance.timeOriginはプロセス開始時刻（Unix時刻、ミリ秒）
- performance.nodeTimingはNode.js固有の起動タイミング情報
- PerformanceObserver.supportedEntryTypesでサポートタイプを取得可能
- timerifyはasync関数の場合Promise.finallyで計測
- histogramオプションでRecordableHistogramに結果を記録可能

---

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

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

### 推奨読解順序

#### Step 1: モジュールエントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | perf_hooks.js | `lib/perf_hooks.js` | エクスポート一覧（34-54行目） |

**読解のコツ**: perf_hooks.jsはファサードとして各内部モジュールをまとめてエクスポートしている。Performance、PerformanceObserver、timerify等の主要機能の出所を確認する。

#### Step 2: Performanceクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | performance.js | `lib/internal/perf/performance.js` | Performanceクラス（51-165行目） |

**主要処理フロー**:
- **52-54行目**: コンストラクタはERR_ILLEGAL_CONSTRUCTOR（直接newは禁止）
- **70-77行目**: clearMarks() - markTimingsとバッファをクリア
- **95-98行目**: getEntries() - filterBufferMapByNameAndTypeで全エントリ取得
- **121-127行目**: mark() - internal/perf/usertimingのmark関数を呼び出し
- **129-135行目**: measure() - internal/perf/usertimingのmeasure関数を呼び出し
- **137-140行目**: now() - internal/perf/utilsのnow関数を呼び出し
- **226-231行目**: createPerformance() - 実際のインスタンス生成

#### Step 3: ユーザータイミング（mark/measure）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | usertiming.js | `lib/internal/perf/usertiming.js` | mark/measure実装（167-237行目） |

**主要処理フロー**:
- **69-109行目**: PerformanceMarkクラス - startTimeとdetailを持つ
- **120-157行目**: PerformanceMeasureクラス - 内部使用のみ（ERR_ILLEGAL_CONSTRUCTOR）
- **167-172行目**: mark() - PerformanceMark作成、enqueue、bufferUserTiming
- **174-223行目**: calculateStartDuration() - 開始/終了時刻の計算ロジック
- **225-237行目**: measure() - PerformanceMeasure作成、enqueue、bufferUserTiming

#### Step 4: PerformanceObserverを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | observe.js | `lib/internal/perf/observe.js` | PerformanceObserverクラス（236-377行目） |

**主要処理フロー**:
- **236-245行目**: コンストラクタ - コールバック関数を保存
- **247-314行目**: observe() - entryTypes/typeの排他チェック、監視モード設定
- **316-323行目**: disconnect() - 監視解除、バッファクリア
- **325-329行目**: takeRecords() - バッファを返して空にする
- **335-342行目**: kMaybeBuffer() - エントリタイプチェック、バッファ追加、queuePending
- **344-348行目**: kDispatch() - コールバック実行

#### Step 5: timerifyを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | timerify.js | `lib/internal/perf/timerify.js` | timerify実装（55-107行目） |

**主要処理フロー**:
- **55-69行目**: 引数検証（fn: Function、histogram: RecordableHistogram）
- **71-89行目**: timerified関数 - new.target判定、ReflectConstruct/Apply、Promise.finally対応
- **37-53行目**: processComplete() - 実行時間記録、PerformanceEntry作成、enqueue

#### Step 6: バッファ管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | observe.js | `lib/internal/perf/observe.js` | バッファ管理（94-425行目） |

**主要処理フロー**:
- **94-97行目**: markEntryBuffer、measureEntryBuffer、resourceTimingBuffer定義
- **396-425行目**: bufferUserTiming() - mark/measureをバッファに追加、100万件で警告
- **434-466行目**: bufferResourceTiming() - resourceTimingBufferSizeLimit制御
- **480-495行目**: clearEntriesFromBuffer() - 指定タイプのバッファをクリア

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

```
lib/perf_hooks.js
    │
    ├─ require('internal/perf/performance') [22-24行目]
    │      ├─ Performance クラス [51-165行目]
    │      │      ├─ clearMarks() → clearMarkTimings + clearEntriesFromBuffer
    │      │      ├─ clearMeasures() → clearEntriesFromBuffer
    │      │      ├─ getEntries() → filterBufferMapByNameAndType
    │      │      ├─ mark() → usertiming.mark
    │      │      ├─ measure() → usertiming.measure
    │      │      └─ now() → utils.now
    │      │
    │      └─ createPerformance() [226-231行目]
    │
    ├─ require('internal/perf/observe') [14-16行目]
    │      ├─ PerformanceObserver クラス [236-377行目]
    │      │      ├─ observe() [247-314行目]
    │      │      ├─ disconnect() [316-323行目]
    │      │      └─ takeRecords() [325-329行目]
    │      │
    │      ├─ enqueue() [384-391行目]
    │      ├─ bufferUserTiming() [396-425行目]
    │      └─ bufferResourceTiming() [434-466行目]
    │
    ├─ require('internal/perf/usertiming') [18-20行目]
    │      ├─ PerformanceMark クラス [69-109行目]
    │      ├─ PerformanceMeasure クラス [120-157行目]
    │      ├─ mark() [167-172行目]
    │      │      └─ enqueue + bufferUserTiming
    │      └─ measure() [225-237行目]
    │             └─ calculateStartDuration + enqueue + bufferUserTiming
    │
    ├─ require('internal/perf/timerify') [32行目]
    │      └─ timerify() [55-107行目]
    │             └─ processComplete() [37-53行目]
    │                    └─ enqueue
    │
    └─ require('internal/perf/event_loop_delay') [30行目]
           └─ monitorEventLoopDelay()
```

### データフロー図

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

name, options ───▶ performance.mark ───▶ PerformanceMark
                         │
                         ├── markTimings.set()
                         ├── enqueue() → PerformanceObserver通知
                         └── bufferUserTiming() → markEntryBuffer

name, start, end ───▶ performance.measure ───▶ PerformanceMeasure
                             │
                             ├── getMark() で時刻解決
                             ├── enqueue()
                             └── bufferUserTiming() → measureEntryBuffer

─────▶ performance.getEntries ───▶ PerformanceEntry[]
              │
              └── filterBufferMapByNameAndType()

callback ───▶ PerformanceObserver.observe ───▶ コールバック呼び出し
                     │
                     ├── kObservers.add()
                     └── maybeIncrementObserverCount()

fn ───▶ timerify ───▶ timerified function
              │
              └── processComplete() → PerformanceEntry(function)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| perf_hooks.js | `lib/perf_hooks.js` | ソース | モジュールエントリーポイント |
| performance.js | `lib/internal/perf/performance.js` | ソース | Performanceクラス |
| observe.js | `lib/internal/perf/observe.js` | ソース | PerformanceObserverクラス、バッファ管理 |
| usertiming.js | `lib/internal/perf/usertiming.js` | ソース | mark/measure実装 |
| timerify.js | `lib/internal/perf/timerify.js` | ソース | timerify実装 |
| performance_entry.js | `lib/internal/perf/performance_entry.js` | ソース | PerformanceEntryクラス |
| resource_timing.js | `lib/internal/perf/resource_timing.js` | ソース | PerformanceResourceTimingクラス |
| event_loop_delay.js | `lib/internal/perf/event_loop_delay.js` | ソース | monitorEventLoopDelay |
| event_loop_utilization.js | `lib/internal/perf/event_loop_utilization.js` | ソース | eventLoopUtilization |
| nodetiming.js | `lib/internal/perf/nodetiming.js` | ソース | Node.js起動タイミング |
| utils.js | `lib/internal/perf/utils.js` | ソース | now(), getTimeOriginTimestamp() |
| histogram.js | `lib/internal/histogram.js` | ソース | createHistogram |
