# 機能設計書 176-アイドル時間取得

## 概要

本ドキュメントは、libuv の `uv_metrics_idle_time()` 関数によるイベントループのアイドル時間取得機能について、その設計仕様を記載する。

### 本機能の処理概要

`uv_metrics_idle_time()` は、イベントループがI/Oプロバイダ（epoll/kqueue/IOCP等）で待機していた累積時間をナノ秒単位で取得する関数である。この値はイベントループが「アイドル状態」であった時間の指標として使用される。

**業務上の目的・背景**：イベントループベースのアプリケーションにおいて、ループがI/O待機にどれだけの時間を費やしているかを知ることは、パフォーマンス分析の重要な指標である。アイドル時間が長ければループは軽負荷、短ければ高負荷であることを示す。この情報を用いてスケーリング判断やパフォーマンスチューニングが可能になる。

**機能の利用シーン**：イベントループのビジー率計算（ビジー率 = 1 - アイドル時間/経過時間）、負荷モニタリング、自動スケーリング判断、パフォーマンスプロファイリングなどに利用される。

**主要な処理内容**：
1. ミューテックスによるメトリクスデータの排他読み取り
2. 累積アイドル時間と現在の待機エントリ時刻の取得
3. 現在I/O待機中の場合、経過分を加算して返却

**関連システム・外部連携**：イベントループの内部フィールド（`uv__loop_metrics_t`）から provider_idle_time と provider_entry_time を取得する。計算には `uv_hrtime()` を使用する。

**権限による制御**：特別な権限は不要である。ただし、アイドル時間の計測には `uv_loop_configure()` で `UV_METRICS_IDLE_TIME` を有効にする必要がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 30 | メトリクス | 主機能 | uv_metrics_idle_time()によるイベントループアイドル時間取得のAPI定義 |

## 機能種別

データ取得処理（イベントループ統計情報の読み取り・計算）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loop | uv_loop_t* | Yes | アイドル時間を取得するイベントループ | - |

### 入力データソース

イベントループの内部フィールド（`uv__loop_metrics_t` の `provider_idle_time` と `provider_entry_time`）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | uint64_t | 累積アイドル時間（ナノ秒単位） |

### 出力先

呼び出し元に戻り値として返却。

## 処理フロー

### 処理シーケンス

```
1. メトリクスポインタ取得
   └─ uv__get_loop_metrics(loop) でメトリクス構造体を取得
2. ミューテックスロック取得
   └─ uv_mutex_lock(&loop_metrics->lock)
3. アイドル時間と待機エントリ時刻を読み取り
   └─ idle_time = loop_metrics->provider_idle_time
   └─ entry_time = loop_metrics->provider_entry_time
4. ミューテックスロック解放
   └─ uv_mutex_unlock(&loop_metrics->lock)
5. 現在I/O待機中の場合、経過分を加算
   └─ entry_time > 0 なら idle_time += uv_hrtime() - entry_time
6. idle_time を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[uv__get_loop_metrics でメトリクスポインタ取得]
    B --> C[ミューテックスロック取得]
    C --> D[provider_idle_time と provider_entry_time を読み取り]
    D --> E[ミューテックスロック解放]
    E --> F{entry_time > 0?}
    F -->|Yes| G[idle_time += uv_hrtime - entry_time]
    F -->|No| H[idle_time をそのまま返す]
    G --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-176-01 | 累積アイドル時間 | 戻り値はプロセス開始からの累積アイドル時間（ナノ秒） | 常時 |
| BR-176-02 | 現在待機中の加算 | I/Oプロバイダでの待機中（entry_time > 0）の場合、現在時刻との差分を加算 | I/O待機中 |
| BR-176-03 | スレッドセーフ | ミューテックスにより排他的にメトリクスデータを読み取る | 常時 |

### 計算ロジック

```
idle_time = provider_idle_time
if (entry_time > 0):
    idle_time += uv_hrtime() - entry_time
return idle_time
```

`provider_idle_time` はI/Oプロバイダからの復帰時に `uv__metrics_update_idle_time()` で更新される。`provider_entry_time` はI/Oプロバイダへの進入時に `uv__metrics_set_provider_entry_time()` でセットされる。

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

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

該当なし。

### テーブル別操作詳細

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| (なし) | - | 本関数はエラーを返さない（uint64_tを返す） | - |

### リトライ仕様

不要。

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

ミューテックスによる排他制御あり。`provider_idle_time` と `provider_entry_time` の読み取りはアトミックに行われる。

## パフォーマンス要件

ミューテックスのロック/アンロックと `uv_hrtime()` の呼び出しを伴うが、軽量な操作。マイクロ秒オーダーで完了する。

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

特別なセキュリティ要件はない。

## 備考

- アイドル時間の計測を有効にするには、`uv_loop_configure(loop, UV_METRICS_IDLE_TIME)` を事前に呼び出す必要がある。
- `uv__metrics_update_idle_time()` と `uv__metrics_set_provider_entry_time()` はイベントループの内部処理として自動的に呼び出される。
- entry_time が 0 の場合は現在I/O待機中ではないことを意味する。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | uv-common.h | `src/uv-common.h` | uv__loop_metrics_t 構造体（399-404行目）。provider_idle_time(累積アイドル時間), provider_entry_time(待機開始時刻), lock(ミューテックス) |

**読解のコツ**: `provider_idle_time` はI/Oプロバイダでの累積待機時間、`provider_entry_time` は現在のI/O待機の開始時刻を表す。entry_time が 0 なら現在待機中ではない。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | uv.h | `include/uv.h` | API宣言（1399行目）: `uint64_t uv_metrics_idle_time(uv_loop_t* loop)` |

#### Step 3: 実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | uv-common.c | `src/uv-common.c` | `uv_metrics_idle_time()` 実装（1042-1056行目） |

**主要処理フロー**:
- **1047行目**: `uv__get_loop_metrics(loop)` でメトリクスポインタ取得
- **1048行目**: `uv_mutex_lock()` でロック取得
- **1049-1050行目**: idle_time と entry_time を読み取り
- **1051行目**: `uv_mutex_unlock()` でロック解放
- **1053-1054行目**: entry_time > 0 なら `uv_hrtime() - entry_time` を加算
- **1055行目**: idle_time を返す

#### Step 4: メトリクス更新処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | uv-common.h | `src/uv-common.h` | `uv__metrics_update_idle_time()` と `uv__metrics_set_provider_entry_time()` の宣言（406-407行目） |

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

```
uv_metrics_idle_time(loop)
    |
    +-- uv__get_loop_metrics(loop)
    |   +-- uv__get_internal_fields(loop)->loop_metrics
    |
    +-- uv_mutex_lock(&loop_metrics->lock)
    +-- [read] provider_idle_time, provider_entry_time
    +-- uv_mutex_unlock(&loop_metrics->lock)
    |
    +-- [if entry_time > 0]
        +-- uv_hrtime()
        +-- idle_time += uv_hrtime() - entry_time
```

### データフロー図

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

loop ──────▶ uv_metrics_idle_time() ─────────▶ uint64_t idle_time
                |                                (ナノ秒単位)
                +-- ミューテックスロック
                +-- provider_idle_time 読取
                +-- provider_entry_time 読取
                +-- ミューテックスアンロック
                +-- [待機中なら] uv_hrtime()差分加算
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| uv.h | `include/uv.h` | ヘッダー | API宣言 |
| uv-common.c | `src/uv-common.c` | ソース | uv_metrics_idle_time() 実装 |
| uv-common.h | `src/uv-common.h` | ヘッダー | uv__loop_metrics_t 定義、メトリクス更新関数宣言 |
