# 帳票設計書 8-pmcstat - ハードウェアパフォーマンスカウンタレポート

## 概要

本ドキュメントは、FreeBSDシステムにおけるハードウェアパフォーマンスカウンタレポート(pmcstat)の帳票設計書である。pmcstatコマンドはhwpmc(4)フレームワークを通じてCPUのハードウェアパフォーマンスカウンタ（PMC）にアクセスし、カウンティングモードでの定期的な値出力、サンプリングモードでのプロファイリング情報収集、gprof(1)互換プロファイルの生成を行う。

### 本帳票の処理概要

**業務上の目的・背景**：パフォーマンスエンジニアがCPUレベルのハードウェアイベント（キャッシュミス、分岐予測ミス、命令実行数等）を計測し、アプリケーションやカーネルのパフォーマンスボトルネックを特定するために必要なレポートである。

**帳票の利用シーン**：アプリケーションのCPUプロファイリング、カーネルのホットスポット分析、カウンティングモードでのハードウェアイベント監視、gprof互換プロファイル生成。

**主要な出力内容**：
1. カウンティングモード：PMCの値を定期的にテキスト出力
2. サンプリングモード：サンプルデータのログファイル出力
3. gprof(1)互換プロファイル：各実行ファイルに対応するgmon.outファイル
4. トップモード（-T）：curses画面でのリアルタイムプロファイル表示
5. callchain統計：呼び出し階層のサンプリング

**帳票の出力タイミング**：コマンド実行開始でデータ収集開始。カウンティングモードでは指定間隔で定期出力。サンプリングモードでは終了時にプロファイル生成。

**帳票の利用者**：パフォーマンスエンジニア、カーネル開発者、アプリケーション開発者。

## 帳票種別

集計表（テキスト/curses画面/gprof互換バイナリ形式のパフォーマンスプロファイルレポート）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | ターミナル/コンソール | N/A | `pmcstat [-C] [-D path] [-E] [-F file] [-G file] [-M file] [-N] [-O logfile] [-P event] [-R file] [-S event] [-T] [-W] [-a file] [-c cpu] [-d] [-e] [-f filter] [-g] [-k dir] [-l secs] [-m pattern] [-n rate] [-o file] [-p event] [-q] [-r fsroot] [-s event] [-t pid] [-u event] [-v] [-w secs] [-z depth] [command [args]]` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（カウンティングモード）/バイナリログ（サンプリング）/gmon.out（プロファイル）/curses画面（-T） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | -Oで指定（ログ）、-Gで指定（gprof出力ディレクトリ）、-oで指定（カウント出力） |
| 出力方法 | 標準出力/ファイル出力/curses画面 |
| 文字コード | ASCII（テキスト）/バイナリ（ログ/gprof） |

## 帳票レイアウト

### カウンティングモード出力

```
# Time: HH:MM:SS
PMC EVENT NAME1    PMC EVENT NAME2    ...
value1              value2             ...
```

### トップモード（-T）

```
PMC: eventname, Samples: XXXXX, Top: ...
  %   CUMUL  SAMPLES  FUNCTION    IMAGE
 xx.x  xx.x  xxxxx   funcname    imagename
```

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| -Pイベント | カウンティングモードのPMCイベント | いずれかのPMCイベント指定が必須 |
| -Sイベント | サンプリングモードのPMCイベント | |
| -cオプション | CPUアフィニティ指定 | No |
| -tオプション | 特定PIDへのアタッチ | No |
| -fフィルタ | プログラム名フィルタ | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | サンプル数 | 降順（トップモード） |

### 改ページ条件

curses画面の端末サイズに基づく（-Tモード時）

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| hwpmc(4) | ハードウェアPMCデバイス | pmc_*() API |
| /dev/pmc | PMCデバイスファイル | カーネルPMCサブシステム |
| ELFバイナリ | シンボル解決 | サンプルアドレスからの逆引き |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| サンプル率 | count / total_samples * 100 | 小数点1桁 | トップモード |
| 累積率 | 上位からの累積サンプル率 | 小数点1桁 | トップモード |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コマンド実行] --> B[オプション解析]
    B --> C[pmc_init: PMCライブラリ初期化]
    C --> D{子プロセス起動?}
    D -->|Yes| E[socketpair + fork]
    D -->|No| F[既存PIDにアタッチ]
    E --> G[PMCの割り当てと開始]
    F --> G
    G --> H[kqueueイベントループ]
    H --> I{イベント種別}
    I -->|タイマー| J[pmc_read: カウント値読み取り・出力]
    I -->|PMCサンプル| K[pmclog処理: ログ書き出し]
    I -->|プロセス終了| L[クリーンアップ]
    J --> H
    K --> H
    L --> M{プロファイル生成?}
    M -->|Yes| N[gprof互換プロファイル生成]
    M -->|No| O[終了]
    N --> O
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| PMC初期化失敗 | hwpmc未ロード | err(EX_OSERR, "ERROR: cannot initialize PMC") | kldload hwpmcを実行 |
| PMC割当失敗 | カウンタ不足またはイベント不正 | err(EX_OSERR, "ERROR: cannot allocate PMC") | イベント名確認、他のPMC解放 |
| プロセスアタッチ失敗 | 権限不足 | err(EX_OSERR, "ERROR: cannot attach PMC") | root権限で実行 |
| ログファイル設定失敗 | パス不正 | err(EX_OSERR, "ERROR: cannot set logfile") | パス確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | サンプリング率に依存（通常数千～数百万サンプル/秒） |
| 目標出力時間 | カウンティングは即時、プロファイル生成はサンプル数に比例 |
| 同時出力数上限 | PMCハードウェアカウンタ数に依存 |

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

- PMCのアクセスにはroot権限またはhwpmc権限が必要
- 他プロセスのプロファイリングにはプロセス所有者権限またはroot権限が必要
- サンプリングログにはプロセスメモリマップ情報が含まれる

## 備考

- PMCイベント名はCPUアーキテクチャに依存（Intel, AMD等で異なる）
- -Gオプションでgprof(1)互換プロファイルを自動生成
- socketpair通信で親子プロセス間の同期を実現（108-106行目のコメント参照）
- libpmcstatライブラリに主要なログ解析・プロファイル生成ロジックが集約
- kqueueベースのイベント駆動ループで複数の入力ソースを効率的に処理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pmcstat.h | `usr.sbin/pmcstat/pmcstat.h` | pmcstat_args構造体、pmcstat_ev構造体。PMCイベントのリスト管理 |
| 1-2 | libpmcstat.h | `lib/libpmcstat/libpmcstat.h` | ログ解析・プロファイル生成用の構造体定義 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pmcstat.c | `usr.sbin/pmcstat/pmcstat.c` | main関数（非常に長大）。60以上のオプション解析→PMC初期化→イベントループ |

**主要処理フロー**:
1. getoptで非常に多数のオプションを解析
2. pmc_init()でPMCサブシステム初期化
3. 子プロセスforkまたは既存PIDアタッチ
4. kqueueイベントループで統計収集

#### Step 3: イベントループを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pmcstat.c | `usr.sbin/pmcstat/pmcstat.c` | kevent()ループ。EVFILT_TIMER, EVFILT_PROCなどの複数イベントソース処理 |

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

```
main()
    |
    +-- pmcstat_get_cpumask() [119行目] ... CPU指定解析
    +-- pmc_init() ... PMCライブラリ初期化
    +-- fork() + exec() ... 子プロセス起動（オプション時）
    +-- pmc_allocate() ... PMCカウンタ割り当て
    +-- pmc_start() ... PMC計測開始
    +-- kqueueイベントループ
    |      +-- pmc_read() ... カウント値読み取り
    |      +-- pmclog_read() ... ログ読み取り
    |      +-- pmcstat_process_log() ... ログ処理
    +-- pmcstat_cleanup() [141行目] ... クリーンアップ
    +-- pmcstat_log_shutdown_logging() ... ログ終了
```

### データフロー図

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

hwpmc(4)カーネル ──────▶ pmc_read() / pmclog_read()   ──▶ 標準出力
  PMCカウンタ                |                              (テキスト)
  PMCサンプル                +-- pmcstat_process_log()   ──▶ ログファイル
                             +-- gprof互換変換           ──▶ gmon.out
ELFバイナリ ──────────▶ シンボル解決                    ──▶ curses画面
  (dlopen/dlsym相当)                                        (-Tモード)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pmcstat.c | `usr.sbin/pmcstat/pmcstat.c` | ソース | メインプログラム、オプション解析、イベントループ |
| pmcstat.h | `usr.sbin/pmcstat/pmcstat.h` | ヘッダ | pmcstat固有の定数・構造体定義 |
| pmcstat_log.c | `usr.sbin/pmcstat/pmcstat_log.c` | ソース | ログ処理 |
| pmcstat_top.c | `usr.sbin/pmcstat/pmcstat_top.c` | ソース | トップモード表示 |
| libpmcstat | `lib/libpmcstat/` | ライブラリ | ログ解析・プロファイル生成ライブラリ |
