# 帳票設計書 4-vmstat - 仮想メモリ統計レポート

## 概要

本ドキュメントは、FreeBSDシステムにおける仮想メモリ統計レポート(vmstat)の帳票設計書である。vmstatコマンドはカーネルの仮想メモリカウンタ、プロセス状態、ディスクI/O、割り込み、CPU使用率などの統計を定期的にテキスト形式またはlibxo形式で出力する。

### 本帳票の処理概要

**業務上の目的・背景**：システム管理者がシステム全体のメモリ使用状況、ページング活動、割り込み頻度、CPU使用率を把握し、メモリリソースの適切な配分やパフォーマンス問題の診断に必要なレポートである。

**帳票の利用シーン**：メモリ不足の診断、スワッピング状況の監視、割り込み分析、CPU使用率の監視、フォーク統計の確認、ゾーンメモリアロケータの状態確認。

**主要な出力内容**：
1. VMSTATモード（デフォルト）：プロセス状態、メモリ使用量、ページング統計、ディスクI/O、フォルト統計、CPU使用率
2. FORKSTATモード（-f）：fork/vfork/rforkの呼び出し回数とページ数
3. INTRSTATモード（-i）：割り込みソースごとの発生回数と頻度
4. MEMSTATモード（-m）：mallocメモリアロケータの統計
5. ZMEMSTATモード（-z）：UMAゾーンアロケータの統計
6. SUMSTATモード（-s）：VMカウンタの累積サマリー
7. OBJSTATモード（-o）：VMオブジェクトの統計

**帳票の出力タイミング**：コマンド実行で即時出力。-wオプションで定期出力。libxo形式（JSON/XML等）にも対応。

**帳票の利用者**：システム管理者、パフォーマンスエンジニア、カーネル開発者。

## 帳票種別

集計表（テキスト/libxo形式の仮想メモリ統計レポート）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | ターミナル/コンソール | N/A | `vmstat [-afHhimoPsz] [-M core [-N system]] [-c count] [-n devs] [-p type,if,pass] [-w wait] [disks] [wait [count]]` コマンド実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（標準出力）またはlibxo形式（JSON/XML等） |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | N/A |
| 出力方法 | 標準出力への直接出力（xo_emit使用） |
| 文字コード | ASCII |

## 帳票レイアウト

### レイアウト概要（VMSTATモード: デフォルト）

```
 procs    memory    page                 disks  faults       cpu
 r  b  w  avm  fre  flt  re  pi  po   fr   sr da0 da1   in   sy   cs us sy id
```

### 明細部（VMSTATモード）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | r | 実行可能プロセス数 | vmtotal.t_rq - 1 | 整数 | 2桁 |
| 2 | b | ディスク待ちプロセス数 | vmtotal.t_dw + t_pw | 整数 | 2桁 |
| 3 | w | スワップアウト済みプロセス数 | vmtotal.t_sw | 整数 | 2桁 |
| 4 | avm | 使用可能仮想メモリ | vmtotal.t_avm * v_page_size | human readable | 4桁 |
| 5 | fre | フリーメモリ | vmtotal.t_free * v_page_size | human readable | 4桁 |
| 6 | flt | ページフォルト/秒 | v_vm_faults差分/秒 | human readable | 4桁 |
| 7 | re | ページ再活性化/秒 | v_reactivated差分/秒 | 整数 | 3桁 |
| 8 | pi | ページイン/秒 | (v_swapin + v_vnodein)差分/秒 | 整数 | 3桁 |
| 9 | po | ページアウト/秒 | (v_swapout + v_vnodeout)差分/秒 | 整数 | 3桁 |
| 10 | fr | ページ解放/秒 | v_tfree差分/秒 | human readable | 4桁 |
| 11 | sr | ページスキャン/秒 | v_pdpages差分/秒 | human readable | 4桁 |
| 12 | disk | デバイス転送/秒 | DSM_TRANSFERS_PER_SECOND | human readable | 5桁 |
| 13 | in | 割り込み/秒 | v_intr差分/秒 | human readable | 4桁 |
| 14 | sy | システムコール/秒 | v_syscall差分/秒 | human readable | 4桁 |
| 15 | cs | コンテキストスイッチ/秒 | v_swtch差分/秒 | human readable | 4桁 |
| 16 | us | CPU user% | cp_time計算 | 整数% | 2桁 |
| 17 | sy | CPU system% | cp_time計算 | 整数% | 2桁 |
| 18 | id | CPU idle% | cp_time計算 | 整数% | 2桁 |

### フォーク統計モード（-f）

| No | 項目名 | 説明 | データ取得元 |
|----|-------|------|-------------|
| 1 | forks | fork()呼び出し回数・ページ数・平均 | v_forks, v_forkpages |
| 2 | vforks | vfork()呼び出し回数・ページ数・平均 | v_vforks, v_vforkpages |
| 3 | rforks | rfork()呼び出し回数・ページ数・平均 | v_rforks, v_rforkpages |

### 割り込み統計モード（-i）

| No | 項目名 | 説明 | データ取得元 |
|----|-------|------|-------------|
| 1 | interrupt | 割り込みソース名 | hw.intrnames (sysctl) |
| 2 | total | 割り込み発生回数 | hw.intrcnt (sysctl) |
| 3 | rate | 割り込み頻度/秒 | count * 1000 / period_ms |

### サマリーモード（-s）

35種類以上のVMカウンタの累積値を名前付きで出力する。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| デバイス指定 | コマンドライン引数でディスクデバイスを指定 | No |
| -Pオプション | CPU別統計表示（ライブシステムのみ） | No |
| -aオプション | 割り込み統計でゼロカウントも表示 | No |

### ソート順

特定のソート順なし（VMカウンタの定義順に出力）

### 改ページ条件

端末行数に基づきヘッダーを繰り返し表示（winlines変数、SIGWINCH対応）

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

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| vm.stats.* (sysctl) | VMカウンタ（60以上のカウンタ） | sysctlbyname() |
| vm.vmtotal (sysctl) | VMシステム全体統計 | sysctlbyname() |
| kern.cp_time (sysctl) | CPU時間統計 | sysctlbyname() |
| kern.cp_times (sysctl) | CPU別時間統計 | -Pオプション時 |
| kern.clockrate (sysctl) | クロック周波数 | sysctlbyname() |
| devstat (カーネル) | ディスクI/O統計 | devstat_getdevs() |
| hw.intrnames/intrcnt (sysctl) | 割り込み統計 | sysctlbyname() |
| kern.malloc (sysctl) | mallocアロケータ統計 | memstat_sysctl_malloc() |
| vm.uma (sysctl) | UMAゾーン統計 | memstat_sysctl_uma() |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| rate(x) | (x * rate_adj + halfuptime) / uptime | unsigned long | rateマクロ（762行目） |
| CPU% | 100LL * cp_time[state] / total | long | percent関数（1114行目） |
| 割り込みrate | count * 1000 / period_ms | unsigned long | 四捨五入（+ period_ms/2） |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[コマンド実行] --> B[xo_parse_args: libxo引数解析]
    B --> C[getoptでオプション解析]
    C --> D{todoビットマスク判定}
    D -->|FORKSTAT| E[doforkst: フォーク統計]
    D -->|MEMSTAT| F[domemstat_malloc: malloc統計]
    D -->|ZMEMSTAT| G[domemstat_zone: ゾーン統計]
    D -->|SUMSTAT| H[dosum: サマリー統計]
    D -->|OBJSTAT| I[doobjstat: オブジェクト統計]
    D -->|INTRSTAT| J[dointr: 割り込み統計]
    D -->|VMSTAT| K[dovmstat: VM統計ループ]
    K --> L{メインループ}
    L --> M[fill_vmmeter: VMカウンタ取得]
    M --> N[fill_vmtotal: VM合計取得]
    N --> O[xo_emit: プロセス・メモリ・ページング出力]
    O --> P[devstats: ディスク統計出力]
    P --> Q[xo_emit: フォルト統計出力]
    Q --> R[cpustats/pcpustats: CPU統計出力]
    R --> S{カウント残り?}
    S -->|Yes| T[usleep: 待機]
    T --> L
    S -->|No| U[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| kvm_openfiles失敗 | -Mオプション時のコアファイル問題 | xo_errx(1, "kvm_openfiles: ...") | コアファイル確認 |
| kvm_nlist失敗 | カーネルシンボル未定義 | xo_error("undefined symbols: ...") | カーネルバージョン確認 |
| devstatバージョン不一致 | カーネルとの不一致 | xo_errx(1, "%s", devstat_errbuf) | カーネル同期 |
| -P + crashdump | -Pはライブシステムのみ | xo_errx(1, "Cannot use -P with crash dumps") | -Pを外す |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 固定（VMカウンタ数 + デバイス数） |
| 目標出力時間 | リアルタイム出力 |
| 同時出力数上限 | N/A |

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

- sysctlベースの統計取得は一般ユーザーでも実行可能
- -Mオプションでのカーネルメモリ参照にはkmem権限が必要
- libxo出力により構造化データとしてAPIからの利用も可能

## 備考

- VMSTAT_XO_VERSION "2" でlibxo構造化出力をバージョン管理（68行目）
- -hオプション（human readable）はデフォルトでisatty(1)が真の場合に有効（216行目）
- todoビットマスクで複数の出力モードが排他的に制御される（165-172行目）
- `_WANT_VMMETER`マクロでvmmeter構造体の内部定義にアクセス（44行目）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | vmstat.c | `usr.bin/vmstat/vmstat.c` | 100-152行目: `struct __vmmeter`定義。60以上のVMカウンタフィールド。sum/osumの2つのインスタンスで差分計算 |
| 1-2 | vmstat.c | `usr.bin/vmstat/vmstat.c` | 72-86行目: nlist定義。X_SUM, X_HZ, X_STATHZ等のカーネルシンボル参照 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | vmstat.c | `usr.bin/vmstat/vmstat.c` | 198-392行目: main関数。todoビットマスクで出力モードを切り替え |

**主要処理フロー**:
1. **212行目**: xo_parse_argsでlibxo引数を処理
2. **218行目**: getoptで15種類のオプション解析
3. **284行目**: xo_open_container("vmstat")でlibxoコンテナ開始
4. **374-387行目**: todoマスクに基づく処理関数ディスパッチ

#### Step 3: VMカウンタ取得処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | vmstat.c | `usr.bin/vmstat/vmstat.c` | 480-581行目: fill_vmmeter関数。kvmまたはsysctl経由でVMカウンタを一括取得 |

**読解のコツ**: GET_VM_STATSマクロ（521-524行目）がsysctlの呼び出しパターンを定義。`vm.stats.sys.*`, `vm.stats.vm.*`の2カテゴリから取得。

#### Step 4: メインループ（dovmstat）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | vmstat.c | `usr.bin/vmstat/vmstat.c` | 636-817行目: dovmstat関数。ヘッダー出力→統計取得→差分計算→xo_emit出力のループ |

**注目ポイント**: rateマクロ（762行目）が差分値を1秒あたりの率に変換。最初のイテレーションはブート以来の累積、2回目以降はインターバルあたりの差分。

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

```
main() [198行目]
    |
    +-- xo_parse_args() ... libxo引数解析
    +-- getdrivedata() [405行目] ... デバイス選択
    +-- doforkst() [1046行目] ... フォーク統計
    +-- domemstat_malloc() [1332行目] ... malloc統計
    +-- domemstat_zone() [1399行目] ... ゾーン統計
    +-- dosum() [924行目] ... サマリー統計
    +-- doobjstat() [1560行目] ... オブジェクト統計
    +-- dointr() [1250行目] ... 割り込み統計
    |      +-- read_intrcnts() [1188行目]
    |      +-- print_intrcnts() [1217行目]
    +-- dovmstat() [636行目] ... VM統計メインループ
           +-- printhdr() [819行目] ... ヘッダー出力
           +-- fill_vmmeter() [480行目] ... VMカウンタ取得
           +-- fill_vmtotal() [583行目] ... VM合計取得
           +-- devstats() [1069行目] ... ディスク統計
           +-- cpustats() [1123行目] / pcpustats() [1144行目]
```

### データフロー図

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

vm.stats.* (sysctl) ────▶ fill_vmmeter()             ──▶ 標準出力
vm.vmtotal (sysctl) ────▶ fill_vmtotal()                  (xo_emit)
kern.cp_time (sysctl) ──▶ cpustats()/pcpustats()
devstat (カーネル) ─────▶ devstats()
hw.intrnames/intrcnt ───▶ dointr()
kern.malloc (sysctl) ───▶ domemstat_malloc()
vm.uma (sysctl) ────────▶ domemstat_zone()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| vmstat.c | `usr.bin/vmstat/vmstat.c` | ソース | 全処理が単一ファイルに集約（1629行） |
