# 機能設計書 85-ベンチマーク

## 概要

本ドキュメントは、mrubyのmruby-benchmark gemが提供するベンチマーク・プロファイリングツールの機能設計を記述する。CRubyのBenchmarkモジュールに相当する機能をmruby環境で提供し、コードの実行時間を計測・比較する。

### 本機能の処理概要

**業務上の目的・背景**：ソフトウェア開発において、コードの性能を計測し比較することは最適化の基本である。本機能はBenchmarkモジュールを提供し、ブロックの実行時間を計測するmeasure、ラベル付き比較出力を行うbm、実時間のみを返すrealtime等のメソッドを備える。

**機能の利用シーン**：アルゴリズムの性能比較、ボトルネック特定、最適化前後の効果測定、メモリ消費量のトラッキング（ObjectSpace連携時）等に使用される。

**主要な処理内容**：
1. `Benchmark.measure` - ブロックの実行時間を計測しTmsオブジェクトを返す
2. `Benchmark.realtime` - ブロックの実時間（Float）を返す
3. `Benchmark.bm` - ラベル付きの比較ベンチマーク出力を行う
4. `Benchmark::Tms` - 計測結果を保持するデータクラス
5. `Benchmark::Report` - ラベル付きレポート出力クラス
6. オプションのメモリトラッキング（ObjectSpace連携）

**関連システム・外部連携**：mruby-time（Time.now）、mruby-objectspace（ObjectSpace.count_objects）、mruby-sprintf（文字列フォーマット）、mruby-io（$stdout出力）

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | CLI | 結果表示画面 | ベンチマーク結果の標準出力 |

## 機能種別

計算処理（性能計測）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| memory (measure) | Boolean | No | メモリトラッキング有効化。デフォルトfalse | - |
| label_width (bm) | Integer | No | ラベル列の幅。デフォルト0 | - |
| label (report) | String | No | レポート行のラベル。デフォルト"" | - |
| block | Block | Yes | 計測対象のコードブロック | - |

### 入力データソース

Ruby関数呼び出しの引数およびブロック

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| Tms (measure) | Benchmark::Tms | 計測結果オブジェクト |
| 実時間 (realtime) | Float | 経過秒数 |
| Report (bm) | Benchmark::Report | レポートオブジェクト |

### 出力先

Ruby関数の戻り値、標準出力（$stdout）

## 処理フロー

### 処理シーケンス

```
1. Benchmark.measure(memory: false)
   ├─ Time.now で開始時刻記録
   ├─ memory=true時: ObjectSpace.count_objects で開始オブジェクト数記録
   ├─ yield でブロック実行
   ├─ Time.now で終了時刻記録
   ├─ real = end_time - start_time
   ├─ memory=true時: ObjectSpace.count_objects で差分計算
   │   └─ メモリ推定 = オブジェクト数差分 * 40
   └─ Tms.new(0.0, 0.0, 0.0, 0.0, real, nil, objects, memory) を返却

2. Benchmark.realtime
   ├─ Time.now で開始時刻記録
   ├─ yield でブロック実行
   └─ Time.now - start_time を返却

3. Benchmark.bm(label_width)
   ├─ Report.new(label_width) 生成
   ├─ ヘッダ行出力
   ├─ yield report でブロック実行（report.reportの呼び出しを想定）
   └─ Report を返却
```

### フローチャート

```mermaid
flowchart TD
    A[Benchmark.measure] --> B[開始時刻記録]
    B --> C{memory?}
    C -->|Yes| D[ObjectSpace.count_objects]
    C -->|No| E[ブロック実行]
    D --> E
    E --> F[終了時刻記録]
    F --> G[実時間計算]
    G --> H{memory?}
    H -->|Yes| I[オブジェクト数差分計算]
    H -->|No| J[Tms生成・返却]
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-85-1 | CPU時間ゼロ | mrubyではプロセスCPU時間を取得できないため、utime/stime/cutime/cstimeは常に0.0 | 常時 |
| BR-85-2 | メモリ推定 | オブジェクトあたりのメモリ消費を40バイトと推定 | memory=true時 |
| BR-85-3 | Tms合計 | totalはutime+stime+cutime+cstimeの合計 | 常時 |

### 計算ロジック

- 実時間: `end_time - start_time` (Time.nowの差分)
- メモリ推定: `objects_allocated * 40` (1オブジェクトあたり40バイトの概算)
- Tms#total: `utime + stime + cutime + cstime`

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

該当なし

## エラー処理

### エラーケース一覧

特になし

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 計測のオーバーヘッドはTime.now呼び出し2回分
- memory=true時はObjectSpace.count_objects呼び出し2回分が追加

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

特になし

## 備考

- 本gemは純粋なRuby実装（mrblib/benchmark.rb）であり、Cソースを持たない
- mruby-time、mruby-objectspace、mruby-sprintf、mruby-ioに依存
- CRubyのBenchmarkと異なり、CPU時間（user/system）は計測できない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | Benchmark::Tmsクラス（2-37行目）で計測結果の構造を理解 |
| 1-2 | benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | Benchmark::Reportクラス（40-69行目）でレポート構造を理解 |

**読解のコツ**: Tmsはutime, stime, cutime, cstime, realの5つの時間属性に加え、objects, memoryのメモリトラッキング属性を持つ。mrubyではCPU時間が取得できないため、utime等は常に0.0。

#### Step 2: 計測メソッドを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | `Benchmark.measure`（72-105行目）で計測ロジックを確認 |
| 2-2 | benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | `Benchmark.realtime`（108-113行目）で簡易計測を確認 |

**主要処理フロー**:
- **73行目**: `start_time = Time.now`
- **78-81行目**: memory=true時のObjectSpace.count_objects呼び出し
- **84行目**: `yield` でユーザブロック実行
- **86-87行目**: `end_time = Time.now; real = end_time - start_time`
- **92-99行目**: memory=true時のオブジェクト数差分・メモリ推定計算
- **104行目**: `Tms.new(0.0, 0.0, 0.0, 0.0, real, ...)` で結果生成

#### Step 3: レポート出力を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | `Benchmark.bm`（116-131行目）でフォーマット出力を確認 |
| 3-2 | benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | `Report#report`（46-64行目）で個別レポート出力を確認 |

**主要処理フロー（bm）**:
- **117行目**: Report.new(label_width) 生成
- **120-125行目**: ヘッダ行出力（"user system total real"）
- **127行目**: `yield report` でユーザブロック実行

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

```
Benchmark.measure
    ├─ Time.now [開始]
    ├─ ObjectSpace.count_objects [memory=true時]
    ├─ yield [ブロック実行]
    ├─ Time.now [終了]
    └─ Tms.new [結果生成]

Benchmark.realtime
    ├─ Time.now [開始]
    ├─ yield [ブロック実行]
    └─ Time.now [終了] → Float

Benchmark.bm
    ├─ Report.new
    ├─ $stdout.puts [ヘッダ]
    └─ yield report
         └─ Report#report
              ├─ Benchmark.measure
              ├─ Tms.new [ラベル付き]
              ├─ $stdout.print [出力]
              └─ @results << tms
```

### データフロー図

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

ブロック ───▶ Time.now差分計算 ───▶ Tms (計測結果)
                  │                       │
                  ├─ ObjectSpace連携       ├─ utime/stime (常に0.0)
                  │   └─ count_objects     ├─ real (実時間)
                  │       └─ 差分計算      ├─ objects (オブジェクト数差分)
                  │                       └─ memory (推定メモリ)
                  │
                  └─ $stdout ───▶ フォーマット出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| benchmark.rb | `mrbgems/mruby-benchmark/mrblib/benchmark.rb` | ソース | Benchmarkモジュール全体の実装 |
| mrbgem.rake | `mrbgems/mruby-benchmark/mrbgem.rake` | 設定 | gem仕様定義、依存関係 |
| benchmark.rb | `mrbgems/mruby-benchmark/test/benchmark.rb` | テスト | テストケース |
