llm-serving-capacity-planner について
SGLang と vLLM の運用担当者向けに、サービング容量の計画や診断を支援するログ分析ツールです。ログの GPU メモリ使用量を分類し、指定したトークン長での同時リクエスト数を推定します。オプションでランク別の値やモデル設定も確認できます。
主な機能
- 01起動ログからメモリ値を抽出
- 02重み、KV、グラフ、オーバーヘッドを分類
- 03ランク別の nvidia-smi 値を比較
- 04リクエストのトークン長ごとに同時数を推定
- 05JSON レポートに対応
活用シーン
- 01GPU 構成でのリクエスト容量の推定
- 02メモリ関連の OOM 障害の調査
- 03設定変更による KV 容量の比較
- 04GPU 値とログ上のメモリ値の照合
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bbuf/ ai-infra-auto-driven-skills --skill llm-serving-capacity-plannerインストール後、Claude Code で/llm-serving-capacity-plannerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/gpu-specs.jsonlog-patterns.mdscripts/capacity_analyzer.py詳細
LLM サービング容量プランナー
概要
サービングログに、GPU HBM の使用状況を説明するメモリ関連の行が十分に含まれている場合に使用します。アナライザーは SGLang/vLLM の起動ログを読み取り、重みの読み込み、KV プール、CUDA グラフ、フレームワークのオーバーヘッド、トークン容量の行を抽出して、一般的なトークン長における同時リクエスト数を推定します。
DeepSeek-V4.1 の場合、推定に 528 B/288 B を使用する前に、 KV レイアウトとページ割り当ての仕様 を確認してください。これらは保存されるトークンごとのペイロードとスケールの値であり、ページパディング後の割り当て量や、モデル全体の KV バイト数ではありません。ピン留めされたソースとログから、実際のプールレイアウト、圧縮率、共有状況を確認してください。
入力
分析を実行する前に、次の入力を収集または確認してください。
| 項目 | 重要な理由 | 入手方法 | ユーザーが指定しない場合のデフォルト |
|---|---|---|---|
| ログファイルのパス | 主な入力です。すべてのメモリデータはここから取得します | ユーザーにサービング起動ログを尋ねます | —(必須) |
| GPU の種類 | 内訳検証に使用する HBM 合計量を特定します | ユーザーに尋ねるか、ログから推定します | 可能な場合はログから自動検出 |
| nvidia-smi の出力 | クロスチェック用に、ランクごとの実メモリを提供します | nvidia-smi --query-gpu=index,memory.used,memory.free --format=csv,noheader > smi.txt を実行して取得します | —(任意ですが、推奨) |
| モデルの config.json | 理論上の KV キャッシュのバイト数計算と複製係数の分析が可能になります | ユーザーにモデルの config.json のパスを尋ねます | —(任意。指定がない場合はログデータを使用) |
| リクエストのトークン長 | 同時実行数推定の分母を決定します | ユーザーに尋ねます | 4096、6144、8192 |
ワークフロー
ステップ 1:サービングログを収集する
ユーザーから、SGLang または vLLM サービングインスタンスの起動ログを提供してもらいます。アナライザーが必要とする主なログ行は次のとおりです。
Load weight begin. avail mem=XX GBserver_args={'model_path': '...', 'tp_size': 8, ...}(解決済みパラメーター)Load weight end. ... avail mem=X GB, mem usage=X GB.(重みのフットプリント)DSV4 memory calculation: ... bytes_per_full_token=X, available_bytes=X GB, ... full_token=N[label] KV Cache is allocated. dtype: ..., #tokens: N, K size: X GB, V size: Y GB(またはKV size)Mamba Cache is allocated. ... conv_state size: X GB, ssm_state size: Y GBMemory pool end. avail mem=XX GBCapture target|draft decode|verify|prefill CUDA graph end. elapsed=X s, mem usage=X GB, avail mem=X GB.Post-capture KV sizing: KV cache allocated. ... KV size: X GB, avail mem=X GB(オプトイン)max_total_num_tokens=XX, ... chunked_prefill_size=-1|N, ... available_gpu_mem=XX GB
従来の ServerArgs(...)、Memory profiling:、Capture cuda graph end. も、古いログや非公開ブランチのログでは引き続き受け付けられます。これらは現在の main が出力するものではありません。
現在の vLLM V1 のログでは、代わりに次の情報が示されます。
Initial free memory: ...; Requested memory: ...(DEBUG のみ)Model loading took ... GiBAvailable KV cache memory: ... GiBGraph capturing finished ... took ... GiB<device> KV cache size: ... tokens, Maximum concurrency for ... tokens per request: ...xFree memory on device (F/T GiB) ... Current kv cache memory in use is K GiB(INFO)CUDA graph pool memory: A GiB (actual), E GiB (estimated), ...Initial free memory X GiB, reserved Y GiB memory for KV Cache ...(明示的な KV バイト数)Maximum concurrency for ... tokens per request: ...x
ログが実行中のインスタンスから取得される場合は、起動時に stdout/stderr をファイルへリダイレクトして収集してください。
ステップ 2:任意で nvidia-smi のデータを取得する
ランクごとのメモリを比較する場合:
docker exec <container> nvidia-smi --query-gpu=index,memory.used,memory.free --format=csv,noheader > smi.txt
ステップ 3:アナライザーを実行する
python3 skills/llm-serving-capacity-planner/scripts/capacity_analyzer.py \
--log-file /path/to/sglang.log \
--nvidia-smi-file /path/to/smi.txt \
--gpu h200 \
--config-json /path/to/config.json
JSON 出力の場合(自動化向け):
python3 skills/llm-serving-capacity-planner/scripts/capacity_analyzer.py \
--log-file /path/to/sglang.log \
--format json
ステップ 4:結果を確認して解釈する
アナライザーには、次の情報が表示されます。
- メモリ内訳表:各カテゴリ(重み、KV プール、CUDA グラフ、フレームワーク、その他)の GiB、MiB、割合、算出根拠
- ランクごとの比較:すべての TP ランクにおける nvidia-smi のデータ
- KV プールの詳細:プール構成、KV データ型、複製係数、トークンあたりのバイト数の計算
- 同時実行数の推定:トークン長ごとの最大同時リクエスト数
- チューニングに関する注記:容量を増やせる可能性がある設定変更
vLLM の場合、レポートには vLLM Startup Evidence セクションも含まれます。ログに存在しない値は不明のままにし、SGLang 固有のフィールドに置き換えないでください。
使用する場面
- LLM サービングインスタンスの起動後に、GPU メモリの分配状況を把握する場合
- 異なる
--mem-fraction-staticの値と、それが KV プール容量に与える影響を比較する場合 - デプロイ容量を計画する場合:所定の GPU 構成で同時に処理できるリクエスト数を確認します
- OOM の問題を調査する場合:最も多くのメモリを使用しているカテゴリを特定します
- fp8 KV キャッシュや EP で同時実行数を改善できるか評価する場合
主な概念
mem-fraction-static
調査対象の SGLang ソースでは、モデル読み込み前の空きメモリからランタイム用の余裕を確保します。headroom = pre_model_load_memory * (1 - mem_fraction_static) です。KV の予算は、現在の空きメモリからこの余裕と、モデル固有のその他の予約分を差し引いて算出されます。post_weight_free * fraction ではありません。キャプチャ後にプールのサイズが更新されることもあります。最終的にログに記録された容量とランク単位の根拠を使用してください。ソースの仕様を参照してください。
デフォルト値は、ハードウェアと構成に基づいて自動的に決定されます。server_args={...} から解決済みの値を確認してください。値を下げると、KV 容量と引き換えにランタイム用の余裕が増えます。値が記載されていない場合に 0.88 と推測しないでください。
KV ヘッドの複製
標準的な GQA/MHA では、各ランクに max(1, num_key_value_heads // tp_size) 個の KV ヘッドが格納されます。TP がヘッド数を超える場合、すべてのランクにヘッド一式が複製されるのではなく、ヘッドがランクのサブグループ間で複製されます。kv_heads=4, tp=8 の場合、各ランクには 1 個のヘッドが格納されます。kv_heads=1, tp=8 の場合は、8 つすべてのランクにその 1 個のヘッドが格納されます。MLA では、代わりに潜在表現と RoPE キーが複製されます。理論計算では、構成されたすべてのレイヤーがそのランクに存在すると仮定します。パイプライン並列処理では、ランクごとのレイヤー数を使用してください。
SWA(スライディングウィンドウアテンション)圧縮
DeepSeek-V4 などのモデルは、CSA(Compressed Sliding Attention)と HCA(Hierarchical Context Attention)をスライディングウィンドウとともに使用します。これにより、完全なアテンションに基づく理論計算と比べて、トークンあたりの KV キャッシュのバイト数が減少します。ログに報告される bytes_per_full_token には、すでにこの圧縮が反映されています。
レポートのチェックリスト
次の項目を含めてください。
- サービング構成:モデル、GPU、TP/PP/EP、mem-fraction-static、kv-cache-dtype
- メモリ内訳表:カテゴリ/GiB/MiB/割合/算出根拠
- ランクごとの nvidia-smi 比較:TP ランクごとの使用メモリと空きメモリ
- KV プールの詳細:プールサイズ、bytes_per_full_token、KV データ型、複製係数、トークンあたりの理論上の KV 計算(config.json が指定されている場合)
- 同時実行数の推定表:リクエストのトークン長/トークン上限/リクエスト上限/最大同時実行数
- 空きメモリと構成に基づくチューニングに関する注記
2026-08-23 ランタイムに関する注記
SGLang v0.5.18 では、コンパイル済みカーネルのキャッシュが SGLANG_CACHE_DIR に集約されます。アップグレード後の初回起動では、Triton/FlashInfer/DeepGEMM/Inductor が一度再コンパイルされるため、「その他」のメモリが増え、起動に時間がかかることがあります。チェックポイントのステージングを重ねて行う設定(--startup-weight-load-mode overlap)によっても、起動時のメモリ推移が変わります。重みのページ読み込みと CUDA グラフのキャプチャが重なる場合があるため、重みの読み込み時間が短くても、重みのメモリ使用量が小さいとは判断しないでください。
既知の制限事項
| 制限事項 | 詳細 | 回避策 |
|---|---|---|
| フレームワーク固有のチェックポイント | SGLang と vLLM では公開されるメモリチェックポイントが異なるため、一部のフィールドは一対一で比較できません | 不明なフィールドは不明として報告し、共通する明示的な情報のみを比較します |
| SWA 圧縮モデル | CSA/HCA アテンションでは、モデル設定からトークンごとの KV バイト数を個別に計算できません。フレームワーク内部の SWA ウィンドウパラメーターが必要です | ログの bytes_per_full_token をそのまま使用します |
| DeepGEMM JIT メモリ | DeepGEMM JIT コンパイルメモリはログに明示的に記録されないため、アナライザーは「その他」に分類します | 正確に計上するには、nvidia-smi の合計値と比較します |
| PP(パイプライン並列処理) | メモリの内訳はランクごとです。PP 構成では、ステージ間でメモリ量に偏りが生じる場合があります | 各 PP ステージで --target-rank を指定します |
| MoE エキスパートバッファー | エキスパートルーティング用の追加バッファーを割り当てるフレームワークもありますが、個別には報告されません | 割り当てのタイミングに応じて、「モデルの重み」または「その他」に含まれます |
参考資料
references/log-patterns.md:メモリ分析で使用するログ行のパターンとその意味。references/gpu-specs.json:h20、h100、h200、b200の各エイリアスに対応する GPU HBM 仕様。scripts/capacity_analyzer.py:中核となる分析スクリプト。
メモリ容量の情報源
同梱のハードウェアテーブルには、使用可能な GiB ではなく、ベンダー公称の GB 最大値が記録されています。
nvidia-smi の使用量と空き容量、または vLLM のログに記録された合計値を優先してください。B200 には DGX の 180GB SKU が記録されています。
ほかの Blackwell SKU では異なる場合があります。DGX Spark の 128GB はシステムと共有するメモリであり、専用 HBM ではありません。L20 の公式 SKU は 48GB です。名前から l20n の容量を推定しないでください。GB200 には物理パッケージの最大容量である 192GB が記録されています。実際に導入された SKU とカスタム SKU の容量は、実測した合計値を確認する必要があります。新たに追加されたハードウェアの各エントリーには、公式情報源の URL が保存されています。