ln-811-performance-profiler について
ln-811-performance-profilerは、ファイル、エンドポイント、パイプラインの遅さを調べる開発者向けのプロファイリングスキルです。実行時の複数指標と関数単位のデータから、構造化された性能マップとボトルネックレポートを作成します。
主な機能
- 01複数指標の実行時測定
- 02関数単位のプロファイリングと計測
- 03テストの検出またはベンチマーク作成
- 04ボトルネック分類と性能マップ
活用シーン
- 01CPU、メモリ、I/O、時間のボトルネック特定
- 02エンドポイントや処理パイプラインの分析
- 03最適化前の性能ベースライン作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ levnikolaevich/ claude-code-skills --skill ln-811-performance-profilerインストール後、Claude Code で/ln-811-performance-profilerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/benchmark_generation.mdbottleneck_classification.mdci_tool_detection.mdcoordinator_summary_contract.mdlatency_estimation.mdmonitor_integration_pattern.mdoutput_normalization.md詳細
パス: ファイルパス(
references/、../ln-*)は、このスキルディレクトリを基準とします。
ln-811-performance-profiler
タイプ: L3 ワーカー カテゴリ: 8XX 最適化
最適化対象を実行し、複数の指標(CPU、メモリ、I/O、時間)を計測し、関数単位の内訳を把握できるようコードを計測し、実データに基づいた標準化済みパフォーマンスマップを生成するランタイムプロファイラーです。
概要
| 項目 | 詳細 |
|---|---|
| 入力 | 問題の説明:対象(ファイル/エンドポイント/パイプライン)+観測された指標 |
| 出力 | パフォーマンスマップ(複数指標、関数単位)、疑わしい箇所のスタック、ボトルネックの分類 |
| パターン | テストの検出 → ベースライン実行 → 静的解析 → 詳細プロファイル → パフォーマンスマップ → レポート |
ワークフロー
フェーズ: テストの検出 → ベースライン実行 → 静的解析 → 詳細プロファイル → パフォーマンスマップ → レポート
フェーズ 0:テストの検出/作成
必ず読み込む: テストフレームワークの検出には references/ci_tool_detection.md を読み込みます。
必ず読み込む: テストが存在しない場合にベンチマークを自動生成するには references/benchmark_generation.md を読み込みます。
最適化対象を実行するコマンドを検出するか、作成します。出力は 2 つです。test_command(プロファイリング/計測用)と e2e_test_command(機能上の安全性を確認するゲート用)です。
ステップ 1:test_command を検出する
| 優先度 | 方法 | アクション |
|---|---|---|
| 1 | ユーザー指定 | ユーザーがテストコマンドまたは API エンドポイントを指定します |
| 2 | 既存の E2E テストを検出 | テストファイルから対象のエントリーポイントを検索します(最初に一致した時点で終了) |
| 3 | テストスクリプトを作成 | references/benchmark_generation.md に従って .hex-skills/optimization/{slug}/profile_test.sh を生成します |
E2E の検出手順(最初に一致した時点で終了):
| 優先度 | 方法 | 手順 |
|---|---|---|
| 1 | ルートベースの検索 | e2e/統合テストファイルからエントリーポイントのルートを検索します |
| 2 | 関数ベースの検索 | エントリーポイントの関数名を検索します |
| 3 | モジュールベースの検索 | エントリーポイントのモジュールのインポートを検索します |
テストの作成(既存のテストが見つからない場合):
| 対象の種類 | 生成するスクリプト |
|---|---|
| API エンドポイント | curl -w "%{time_total}" -o /dev/null -s {endpoint} |
| 関数 | references/benchmark_generation.md に従った、スタックに固有のベンチマーク |
| パイプライン | テスト入力を使ったパイプライン全体の呼び出し |
ステップ 2:e2e_test_command を検出する
test_command が E2E の検出(ステップ 1 の優先度 2)で見つかった場合、e2e_test_command = test_command とします。
それ以外の場合、E2E の検出手順(同じ優先度 3 段階の表)を再度実行し、別の機能安全性テストを探します。
見つからない場合は、e2e_test_command = null とし、次のログを記録します:WARNING: No e2e test covers {entry_point}. Full test suite serves as functional gate.
出力
| フィールド | 説明 |
|---|---|
test_command | プロファイリング/計測用のコマンド |
e2e_test_command | 機能上の安全性を確認するゲート用のコマンド(test_command と同じ場合や、null の場合があります) |
e2e_test_source | 検出方法:user / route / function / module / none |
フェーズ 1:ベースライン実行(複数指標)
システムレベルのプロファイリングを使って test_command を実行します。次の指標を同時に取得します。
| 指標 | 取得方法 | タイミング |
|---|---|---|
| 実時間 | time ラッパーまたはテストハーネス | 常に |
| CPU 時間(user+sys) | /usr/bin/time -v または言語プロファイラー | 常に |
| メモリのピーク(RSS) | /usr/bin/time -v(Max RSS)、tracemalloc または process.memoryUsage() | 常に |
| I/O バイト数 | /usr/bin/time -v または構造化ログ | I/O が疑われる場合 |
| HTTP の往復回数 | 構造化ログまたはアプリケーションメトリクスからカウント | 呼び出しグラフにネットワーク I/O がある場合 |
| GPU 使用率 | nvidia-smi --query-gpu | スタックで CUDA/GPU が検出された場合のみ |
ベースラインの手順
| パラメーター | 値 |
|---|---|
| 実行回数 | 3 |
| 指標 | 中央値 |
| ウォームアップ | 1 回実行し、結果を破棄 |
| 出力 | baseline — 複数指標のスナップショット |
プロファイラーの実行を監視する(Claude Code 2.1.98 以降)
必ず読むこと: references/monitor_integration_pattern.md を読み込みます
ベースラインおよび詳細なプロファイルの実行中:
Monitor(command="{test_command} 2>&1", timeout_ms=300000, description="profiler run N")
クラッシュや無限ループを即座に検出します。フォールバック:Bash と timeout を使用します。
フェーズ 2:静的解析 → 計測ポイント
必ず読むこと: bottleneck_classification.md を読み込みます
コードから呼び出しチェーンをたどり、疑わしい箇所のスタックを構築します。目的: フェーズ 3 で計測する場所を特定します。
ステップ 1:呼び出しチェーンをたどる
エントリーポイントから開始し、深さ優先でたどります(最大深度 5)。各ステップで、関数本体全体を読みます。
サービスをまたぐトレース: コーディネーターから service_topology を利用でき、あるステップでコードにアクセス可能な別のサービスへ HTTP/gRPC 呼び出しを行う場合:
| 状況 | 対応 |
|---|---|
| サブモジュール/モノレポ内にコードがあるサービスへの HTTP 呼び出し | そのサービスのハンドラーをたどります:ルートを特定 → ハンドラーのコードをトレースします(新しいサービスでは深度を 0 にリセット) |
| コードにアクセスできないサービスへの HTTP 呼び出し | External と分類し、レイテンシの推定値を記録します |
| 既知のサービスへの gRPC/メッセージキュー | HTTP と同様に、コードにアクセスできる場合はハンドラーをたどります |
各ステップに service: "{service_name}" を記録し、どのサービスがその処理を担うかを追跡します。performance_map の steps ツリーには複数のサービスを含められます。
深さ優先のルール: 呼び出し先サービスのコードにアクセスできる場合は、必ず内部をプロファイルします。内部をプロファイルせずに、アクセス可能なサービスを「External/低速」と分類してはいけません。「低速」は症状であり、診断ではありません。
各ボトルネックに対する 5 Whys: ボトルネックを報告する前に、「なぜ?」を設定/アーキテクチャレベルに到達するまで繰り返します。
- 「何が遅いのか?」→ アライメントサービス(5.9 秒) 2. 「なぜ?」→ 6 組 × 約 1 秒 3. 「なぜ 1 組あたり約 1 秒かかるのか?」→ O(n²) の mwmf 計算 4. 「なぜ O(n²) なのか?」→ ライブラリのデフォルトであり、本番設定ではない 5. 「なぜデフォルトなのか?」→
matching_methodsが設定されていない → 根本原因 = 設定
ステップ 2:分類と疑わしい箇所のスキャン
各ステップをタイプ(CPU、I/O-DB、I/O-Network、I/O-File、Architecture、External、Cache)で分類し、パフォーマンス上の懸念をスキャンします。
疑わしい箇所のチェックリスト(最低限であり、これに限定されません):
| カテゴリー | 確認する内容 |
|---|---|
| 接続管理 | リクエストごとにクライアントを作成していませんか?プーリングがありませんか?再利用していませんか? |
| データフロー | データを複数回読み込んでいませんか?過剰に取得していませんか?不要な変換をしていませんか? |
| 非同期パターン | 非同期コンテキストで同期 I/O を行っていませんか?データ依存関係のない await を逐次実行していませんか? |
| リソースのライフサイクル | 接続を閉じていませんか?一時ファイルはありませんか?ループ内でメモリが蓄積していませんか? |
| 設定 | タイムアウトがハードコードされていませんか?プールサイズがデフォルトのままではありませんか?バッチサイズの設定がありませんか? |
| 冗長な処理 | 複数のレイヤーで同じ検証をしていませんか?同じデータを 2 回読み込んでいませんか? |
| アーキテクチャ | ループ内に N+1 がありませんか?バッチ API を使っていませんか?キャッシュインフラストラクチャを使っていませんか?並列化できる処理を逐次実行していませんか? |
| (open) | ほかに気づいたことがあれば記録します。チェックリストは調査結果を制限しません |
ステップ 2b:疑わしい箇所の重複排除
必ず読むこと: references/output_normalization.md を読み込みます
呼び出しチェーンのすべてのステップについて疑わしい箇所を抽出した後、§1~§2 に従って正規化し、重複を排除します。
- 疑わしい箇所の説明を正規化します(具体的な値をプレースホルダーに置き換えます)
- 異なるステップにある同一の疑わしい箇所をまとめ、
affected_steps: [list]を持つ 1 つの項目に統合します - 例:「接続プーリングがない」がステップ 1.1、1.2、1.3 で見つかった場合、
affected_steps: ["1.1", "1.2", "1.3"]を持つ 1 つの疑わしい箇所にまとめます
ステップ 3:検証して計測ポイントに対応付ける
FOR each suspicion:
1. VERIFY: follow code to confirm or dismiss
2. VERDICT: CONFIRMED → map to instrumentation point | DISMISSED → log reason
3. For each CONFIRMED suspicion, identify:
- function to wrap with timing
- I/O call to count
- memory allocation to track
プロファイラーの選択(スタックごと)
| スタック | 非侵襲的なプロファイラー | 侵襲的(非侵襲的な方法で不十分な場合) |
|---|---|---|
| Python | py-spy、cProfile | time.perf_counter() デコレーター |
| Node.js | clinic、--prof | console.time() ラッパー |
| Go | pprof(組み込み) | 通常は不要 |
| .NET | dotnet-trace | Stopwatch ラッパー |
| Rust | cargo flamegraph | std::time::Instant |
スタック検出: references/ci_tool_detection.md に従ってください。
フェーズ 3:詳細なプロファイリング
プロファイラーの階層(必要に応じて段階的にエスカレーション)
| レベル | ツールの例 | 表示される内容 | 使用するタイミング |
|---|---|---|---|
| 1 | py-spy、cProfile、pprof、dotnet-trace | 関数レベルのホットスポット | 常に — 最初に実施 |
| 2 | line_profiler、行ごとの計測 | ホットスポット関数内の行ごとの計測時間 | ホットスポット関数は見つかったが、原因が不明 |
| 3 | tracemalloc、memory_profiler | 行ごとのメモリ割り当て | ベースラインのメモリ指標に異常がある |
ステップ 1:非侵襲的なプロファイリング(推奨)
コードを変更せずに関数ごとの内訳を取得するため、レベル 1 のプロファイラーを使って test_command を実行します。
ステップ 2:エスカレーションの判断
レベル 1 のプロファイラーを実行した後、結果をフェーズ 2 の疑いのあるスタックと照らし合わせて評価します。
| プロファイラーの結果 | 対応 |
|---|---|
| ホットスポット関数が特定され、時間の内訳が疑いを裏付けている | 完了 — フェーズ 4 に進みます |
| ホットスポットは特定されたが、内部の原因が不明(1 つの関数内で CPU か I/O かが不明) | レベル 2(行ごとの計測)にエスカレーションします |
| メモリのベースラインに異常がある(ピーク値または差分) | レベル 3(メモリプロファイラー)にエスカレーションします |
| 複数の疑いが解消されず、プロファイラーの粒度では不十分 | ステップ 3(対象を絞った計測)に進みます |
| プロファイラーを利用できない、またはオーバーヘッドが実時間の 20% を超える | ステップ 3(対象を絞った計測)に進みます |
停止条件(プロファイラーのエスカレーション)
| 条件 | 対応 |
|---|---|
| 原因が明確なホットスポットを特定できた | 停止 — パフォーマンスマップに進みます |
| 3 つすべてのプロファイラーレベルを使い切った | 停止 — 入手可能な最善のデータからマップを作成します |
| 計測によってテストが失敗する | 停止 — 計測を元に戻し、非侵襲的なデータのみを使用します |
| プロファイラーのオーバーヘッドが実時間の 20% を超える | 停止 — 対象を絞った計測に進みます |
ステップ 3:対象を絞った計測(積極的に実施)
フェーズ 2 のステップ 3 で特定した計測ポイントに沿って、呼び出しスタックに計測やログ記録を追加します。
1. FOR each CONFIRMED suspicion without measured data:
Add timing wrapper around target function/I/O call
Add counter for I/O round-trips if network/DB suspected
(cross-service: instrument in the correct service's codebase)
2. Re-run test_command (3 runs, median)
3. Collect per-function measurements from logs
4. Record list of instrumented files (may span multiple services)
| 計測の種類 | タイミング | 例 |
|---|---|---|
| 時間計測ラッパー | 未解決の疑いがある場合は常に | 関数呼び出しの前後で time.perf_counter() を使用 |
| I/O 呼び出しカウンター | ネットワークまたは DB がボトルネックと思われる場合 | ループ内の HTTP リクエスト、DB クエリを数える |
| メモリスナップショット | メモリの蓄積が疑われる場合 | 前後で tracemalloc.get_traced_memory() を使用 |
計測はそのまま残してください。 実行担当は、最適化後の関数ごとの比較に計測を再利用し、その後、ストライクの後にクリーンアップします。出力では instrumented_files を報告してください。
フェーズ 4:パフォーマンスマップの作成
標準化された形式です。後続処理で使用するため、.hex-skills/optimization/{slug}/context.md に渡します。
performance_map:
test_command: "uv run pytest tests/automated/e2e/test_example.py -s"
baseline:
wall_time_ms: 7280
cpu_time_ms: 850
memory_peak_mb: 256
memory_delta_mb: 45
io_read_bytes: 1200000
io_write_bytes: 500000
http_round_trips: 13
steps: # service field present only in multi-service topology
- id: "1"
function: "process_job"
location: "app/services/job_processor.py:45"
service: "api" # optional — which service owns this step
wall_time_ms: 7200
time_share_pct: 99
type: "function_call"
children:
- id: "1.1"
function: "translate_binary"
wall_time_ms: 7100
type: "function_call"
children:
- id: "1.1.1"
function: "tikal_extract"
service: "tikal" # cross-service: code traced into submodule
wall_time_ms: 2800
type: "http_call"
http_round_trips: 1
- id: "1.1.2"
function: "mt_translate"
service: "mt-engine"
wall_time_ms: 3500
type: "http_call"
http_round_trips: 13
bottleneck_classification: "I/O-Network"
bottleneck_detail: "13 sequential HTTP calls to MT service (3500ms)"
top_bottlenecks:
- step: "1.1.2", type: "I/O-Network", share: 48%
- step: "1.1.1", type: "I/O-Network", share: 38%
フェーズ 5:レポート
レポートの構成
profile_result:
entry_point_info:
type: <string> # "api_endpoint" | "function" | "pipeline"
location: <string> # file:line
route: <string|null> # API route (if endpoint)
function: <string> # Entry point function name
performance_map: <object> # Full map from Phase 4
bottleneck_classification: <string> # Primary bottleneck type
bottleneck_detail: <string> # Human-readable description
top_bottlenecks:
- step, type, share, description
optimization_hints: # CONFIRMED suspicions only (Phase 2)
- hint with evidence
suspicion_stack: # Full audit trail (confirmed + dismissed)
- category: <string>
location: <string>
description: <string>
verdict: <string> # "confirmed" | "dismissed"
evidence: <string>
verification_note: <string>
e2e_test:
command: <string|null> # E2E safety test command (from Phase 0)
source: <string> # user / route / function / module / none
instrumented_files: [<string>] # Files with active instrumentation (empty if non-invasive only)
wrong_tool_indicators: [] # Empty = proceed, non-empty = exit
適切でないツールを示す指標
| 指標 | 条件 |
|---|---|
external_service_no_alternative | 測定時間の 90% 以上を外部サービスが占め、バッチ処理、キャッシュ、並列処理の手段がない |
within_industry_norm | 測定時間が、処理の種類について想定される範囲内 |
infrastructure_bound | ボトルネックがハードウェアにある(システム指標で測定) |
already_optimized | コードがすでに最適なパターンを使用している(疑いのスキャンで確認済み) |
エラー処理
| エラー | 対処 |
|---|---|
| エントリーポイントを解決できない | ブロック:「{path} にファイル/関数が見つかりません」 |
| 変更していないコードでテストコマンドが失敗する | ブロック:「プロファイリング前にテストが失敗します。まずテストを修正してください」 |
| スタックでプロファイラーを利用できない | 侵襲的な計測に切り替える(フェーズ 3 ステップ 2) |
| 計測によってテストが失敗する | 直ちに元に戻す:git checkout -- . |
| 呼び出しチェーンが深すぎる(5 レベル超) | 深さ 5 で停止し、打ち切りを記録する |
| ステップの種類を分類できない | 「不明」を既定値として、実測時間を使用する |
| I/O が検出されない(CPU のみ) | CPU に分類し、アルゴリズムのプロファイリングに注力する |
参考資料
- bottleneck_classification.md — 分類体系
- latency_estimation.md — レイテンシのヒューリスティック(静的解析のみのモードでのフォールバック)
references/ci_tool_detection.md— スタック/ツールの検出references/benchmark_generation.md— スタックごとのベンチマークテンプレート
ランタイム概要アーティファクト
必読: references/coordinator_summary_contract.md を読み込んでください。
optimization-worker のサマリーエンベロープを出力します。
管理モード:
ln-810は決定論的なrunIdと正確なsummaryArtifactPathを渡します- 指定された
summaryArtifactPathにサマリーを書き込みます
スタンドアロンモード:
runIdとsummaryArtifactPathを省略します.hex-skills/runtime-artifacts/runs/{run_id}/optimization-worker/ln-811--{identifier}.jsonに書き込みます
完了の定義
- 最適化対象のテストコマンドを検出または作成している
- E2E 安全性テストを検出している(または利用できないことを記録している)
- ベースラインを測定している:実時間、CPU、メモリ(3 回実行、中央値)
- 呼び出しグラフを追跡し、関数本体を読み込んでいる
- 疑いのスタックを構築している:各疑いを検証し、計測箇所に対応付けている
- 詳細なプロファイルを完了している(非侵襲的な方法を優先し、必要に応じて侵襲的な方法を使用)
- 計測したファイルを報告している(クリーンアップは実行担当者に委ねる)
- 標準形式でパフォーマンスマップを構築している(実測値を使用)
- 実測データから上位 3 つのボトルネックを特定している
- 実際のメトリクスに基づき、誤ったツールの指標を評価している
- optimization_hints に測定の根拠がある確認済みの疑いのみを含めている
- 測定結果を含むレポートを作成している
- 最適化プロファイルのアーティファクトを共有場所に書き込んでいる
バージョン: 3.0.0 最終更新日: 2026-03-15