Newer
Older
TIASshot / docs / 03_PLAN / PLAN_04_性能評価計測計画.md

性能評価計測計画 (Performance Evaluation Measurement Plan)

目的 (Purpose)

3 バージョン(v1.6 / v1.7 / 現行)で性能(主にメモリ挙動,副次的にプレビュー性能)の実験・計測を行い,改善効果を定量・可視化する.結果は研究室共有用に画面録画+スライドで提示することを想定する.

対象バージョン (Target Versions)

計測対象は「メモリ改善の 3 段階」を表す.上流(nakaguchi)が素の状態,本 GitHub フォークが改善を積んだ現行.

commit中身主に効くメモリ経路
v1.64b107e4(nakaguchi タグ v1.6ベースライン保存経路・プレビュー経路とも未修正(リークあり)
v1.75315d2d(nakaguchi タグ v1.7「メモリ使用効率化」)SaveThread_shots から pop して都度 Dispose+変換行列の中間 Mat 解放保存経路を改善(プレビューは未修正)
現行HEAD(GitHub rintoHasegawa/TIASshot main)ConvertImage の Mat 解放(メモリ)+PLAN_03(プレビュー)+FastCloneプレビュー経路を修正+コピー高速化

→ 計測のストーリー: 保存経路は v1.6 → v1.7 で,プレビュー経路は v1.7 → 現行で効いた,という切り分けを示す.

計測手段と役割分担 (Method & Roles)

  • 手段: 実機 MEMMONITOR(メモリ観測ウィンドウ+プレビュー計測)を使ったライブ計測.自動 NUnit ベンチ(TEST_01)ではなく,実カメラで普通にアプリを使ったときの挙動を対象とする.
  • カメラ: IScam(ImagingSource DFK 23UX249.白板撮影で使用したもの).
  • 役割分担:
    • Claude: 3 本の計装済みビルド(後述の使い捨てブランチ)と実行チェックリストを用意し,出力 CSV を集計して結果ドキュメント(TEST_02)にまとめる.
    • 人間: 実カメラでの撮影・放置・画面録画を実施する(外部サービス操作・実機動作確認と同じく手動作業).

IScam 前提の効き方の違い (Note: IScam)

PLAN_03 で最も派手だった「Lucam のクロススレッド GDI クラッシュ(_bmps[] をコールバックスレッドで Dispose)」は Lucam 固有で IScam では再現しない.IScam で効くのは次の 5 点であり,計測はここに焦点を当てる.

  • ShowImage のフルコピー Bitmap リーク(原因1)
  • 表示バッファ取りこぼし Dispose(原因2)
  • PreviewMonitor.UpdateImage 上書き前 Dispose(原因3)
  • 副モニタ描画飢餓
  • FastClone によるコピー高速化

移植方針 (Porting Strategy)

現行の計測スカフォールドを v1.6 / v1.7 に移植して 3 版横並びで計測する.ただし次の制約がある.

  • v1.7 はフラット構成TIASshot/*.cs 直置き),現行は UI/Cameras/ 等に再編済みのため,cherry-pick は不可.各タグへ手作業で移植する.
  • 作業は各タグから切った使い捨てブランチbench/v1.6bench/v1.7)上で行い,main には一切マージしない
  • 移植は結合度で 2 層に分ける(Tier A / Tier B).
  • 移植の原則: 旧版へは観測フック(カウンタ/Stopwatch)のみを足し,計測対象のロジック(撮影・保存・プレビューのコピー方式・Invalidate タイミング)は一切変えない.変えると測りたい timing 自体が動く.旧版自体が「修正前」であるため,リーク再現用の仕掛けは不要(旧版をそのまま計測すればよい).

Tier A: メモリ観測(低結合・3 版すべてに移植・確定)

MemoryMonitorForm(+.Designer.cs)は自前の 500ms タイマーで自プロセスを覗くだけで,計測対象コードに触れない.移植は「2 ファイルを置いて起動時に 1 行で開く」だけで,メモリ挙動を歪めない.

計測指標(確定):

  • 主指標: private_MBProcess.PrivateMemorySize64 — コミット量.Mat はネイティブメモリのため GC.GetTotalMemory では捕捉できず,プロセス視点のコミット量を主指標とする.
  • 副指標(CSV のみ記録): ws_MBWorkingSet64),gdi_objects / user_objects / handle_count(GDI ハンドル枯渇仮説の否定材料).

表示・記録の方針(確定):

  • 画面グラフは 1 つに,左右 2 軸で描く(案A).メモリと FPS は単位・スケールが異なるため軸を分ける(.NET Chart の Series.YAxisType = Secondary).
    • 左 Y 軸(メモリ・GB): 主指標 private_MB1 本のみ描画する(録画・スライドで「右肩上がり vs 水平」を一目で伝えるため).現状 2 系列(Private / WorkingSet)を描いているので,WorkingSet 系列は**描かない(または非表示)**にする.
    • 右 Y 軸(副軸・FPS): 本モニタ実描画 FPS(M3 main_paint_fps)と副モニタ実描画 FPS(M4 sub_paint_fps)の 2 本を折れ線で乗せる.副モニタ飢餓(校正後 ≈2fps → 回復)を録画で線として見せるため(テキスト数値より伝わる).F9 で副モニタ給餌を ON/OFF して同一録画内で対比する.
    • callback_fps 等その他の指標はグラフには乗せず,テキスト(lblPreview)と CSV に留める.
  • CSV は全列そのまま残すws_MB・ハンドル数はコストゼロの裏取り材料).「グラフで見せるのはメモリ 1 本+FPS 2 本,録るのは全部」とする.
  • Y 軸スケールは 3 版で揃える(現状はオートスケール.バラバラだと「v1.6 も水平」に錯覚するため,録画時に左軸メモリ上限・右軸 FPS 上限を手動で揃えるか,後段でスクショを同スケールで並べる).
  • この FPS オーバーレイは MemoryMonitorForm のグラフ描画拡張であり,旧版(bench/v1.6bench/v1.7)へ移植する窓にも同じ拡張を含める.

Tier B: プレビュー性能プロファイラ(高結合・一式移植で確定)

PreviewProfilerTimedPictureBoxShowImage/PreviewMonitor へのフック.旧版はプレビュー経路が別物(new Bitmap(bmp) フルコピー・毎フレーム Invalidate・タイマー無し)のため,フック位置を各版の ShowImage に置き直す必要があり侵襲的.

M1〜M5 は同じスカフォールドに相乗りするため(フックを一度置けば同時取得),指標を個別に間引かず一式を移植して CSV 全列を記録する.副モニタ(セカンダリディスプレイ)は実機で使えるため,TimedPictureBox を要する M4/M5(副モニタ実描画)も計測対象とする.

計測指標(確定):

#指標何がわかるか差が出る版
M1copy_ms(1 フレームの Bitmap コピー時間)FastClone の効果を直接分離(25ms→2.5ms)v1.7 vs 現行
M2callback_fpsShowImage 呼び出しレート)コピー負荷がコールバックスレッドを律速しているかv1.7 vs 現行
M3実効プレビュー FPS(本モニタの実描画レート)ユーザーに見える滑らかさ(10→20fps).旧版は毎フレーム Invalidate,現行はタイマー駆動のため「結果としての FPS」比較v1.7 vs 現行
M4副モニタ描画飢餓(sub_paint_fps校正完了後の副モニタ飢餓(≈2fps)と回復(~10fps)v1.7 vs 現行
M5sub_paint_ms(副モニタ実描画コスト自体)「飢餓 or 描画コスト増」の切り分け参考
M6GDI/USER/handle 数の推移ハンドル枯渇仮説の検証(Tier A の窓が既に保持・移植不要)v1.7 vs 現行

画面録画・スライドの方針(確定): 記録は全指標だが,録画で強調するのは 2 つの物語に絞る.

  • ① FastClone でコピーが桁で速くなる: 主役は M1 copy_ms25ms→2.5ms),律速の証拠に M2 callback_fps
  • ② 副モニタ飢餓の解消: 主役は M4 副モニタ FPS(v1.7=校正後に崩壊/現行=steady),実効 FPS に M3,切り分けに M5.F9 トグルToggleSubMonitorProfiling)で副モニタ給餌の ON/OFF を切り替えながら同一録画内で対比を撮る.

計測シナリオ (Scenarios)

同一手順・同一パラメータ(解像度・チャンネル数・枚数・時間)で 3 版を回す.

S1〜S3 は独立に回すのではなく,現行で実測した 1 本の記録(基準プロトコル)を全版で再現して同時取得する(副モニタ ON).基準記録は docs/06_TEST/data/perf_current.csv

ID観測対象この記録での該当区間主な観測差が出る版
S1保存経路リーク撮影イベント前後private_MB のピーク包絡線v1.6 vs v1.7 vs 現行
S2プレビュー経路リーク撮影間・放置区間private_MBgdi_objects/handle_count の推移v1.7 vs 現行
S3プレビュー性能全区間(定常プレビュー)copy_ms / callback_fps / 実効 FPS / 副モニタ FPS(M1〜M5)v1.7 vs 現行

基準プロトコル(確定・現行 perf_current.csv の秒数に全版を合わせる): 撮影は単発撮影(1 枚撮影)の繰り返しとする.

  • 0〜32 秒: プレビュー放置(副モニタ ON)
  • 32.5〜36.1 秒: 校正 1 回(処理時間 約 3.5 秒.アプリ側処理で固定)
  • 62 / 92 / 123 秒: 単発撮影(約 30 秒間隔で 3 回)
  • 123〜303 秒: プレビュー放置(約 180 秒.S2 のリーク観測区間)
  • 303 秒: 単発撮影 1 回
  • 約 348 秒: 停止・CSV 保存

旧版(v1.6 / v1.7)もこの秒数・順序・撮影間隔に合わせて再現し,同じ時間軸で 3 版を重ねて比較する.

同条件の統制 (Comparability Controls)

  • 同一マシン・x64 Debug ビルド・同一カメラ(IScam)・同一解像度・同一チャンネル数.
  • 固定ウォームアップ・固定時間(S1 のサイクル数 M,S2 の放置時間 T を全版共通で固定).
  • GC を強制しない(本番のリーク機序を保つ).
  • 観測窓自体もわずかにメモリ・GDI を消費するが,3 版とも同じ overhead のため比較では相殺される.
  • CSV はバージョン別に命名して後で重ね描きする.

結果の読み方 (Reading the Results)

グラフは滑らかに上がらずのこぎり波/階段状になる(OpenCvSharp が GC にメモリ圧を通知し,リーク版でも GC+ファイナライザが周期的にネイティブメモリを一掃するため).見るべきは振れ幅ではなくピーク包絡線のトレンド(リーク=右肩上がり/修正済み=天井一定).

注意点・リスク (Cautions & Risks)

  • 実機 OOM 上限: 自動ベンチ(TEST_01)には打ち切り上限ガードがあったが,実機観測窓(MemoryMonitorForm)にはガードが無い(記録するのみ).S1 でリーク版(v1.6)を長く回すと OOM に達し得るため,サイクル数 M・放置時間 T に上限を決めておく(値は計測実施時に確定).
  • 移植の非マージ: bench/v1.6bench/v1.7 は計測専用の使い捨てブランチであり,main にマージ・push・PR しない.
  • 旧版が現行と同じツールチェーン(x64 / .NET Framework 4.8 / OpenCvSharp パッケージ)でビルドできるかは移植着手時に確認する.

未確定事項 (Open Items)

  • 計測プロトコル・指標は確定.
  • 3 版(v1.6 / v1.7 / 現行)の計測・移植・再現計測は完了.結果は TEST_02_性能評価計測結果

成果物 (Deliverables)

  • 本計画: docs/03_PLAN/PLAN_04_性能評価計測計画.md
  • 計測結果: docs/06_TEST/TEST_02_性能評価計測結果.md(TEST_01 と同形式の 3 版比較表).