mcpField
L
llm-serving-capacity-planner

llm-serving-capacity-planner

github.com/bbuf云与 DevOps1.1k58 次安装今天更新
代码仓库

关于 llm-serving-capacity-planner

面向 SGLang 和 vLLM 运维人员的日志分析工具,用于规划或诊断服务容量。它拆解日志中的 GPU 内存使用,并按指定 Token 长度估算并发请求数,也可选用逐卡及模型配置数据进行校验。

主要功能

  1. 01从启动日志提取内存数据
  2. 02拆分权重、KV、图及框架开销
  3. 03对比逐卡 nvidia-smi 数据
  4. 04按请求 Token 长度估算并发
  5. 05支持 JSON 报告

适用场景

  1. 01估算 GPU 配置的请求承载量
  2. 02排查内存相关的 OOM 故障
  3. 03比较配置变更前后的 KV 容量
  4. 04用 GPU 数据核验日志内存数据

安装

复制下面的命令,在终端中运行。

$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.json
log-patterns.md
scripts/
capacity_analyzer.py

详细介绍

LLM 服务容量规划器

概述

当服务日志中包含足够的内存信息,可以说明 GPU HBM 的去向时,请使用此工具。分析器会读取 SGLang/vLLM 启动日志,提取权重加载、KV 池、CUDA 图、框架开销和令牌容量相关信息,然后估算常见令牌长度下可同时处理的请求数。

对于 DeepSeek-V4.1,在使用 528 B/288 B 进行估算前,请阅读 KV 布局和页面分配约定。这些数值表示每个存储令牌的载荷和缩放值,并非页面填充后的分配量或模型 KV 总字节数。请根据固定版本的源码和日志,核实实际池布局、压缩率和共享情况。

输入

运行分析前,请收集或核实以下输入:

项目重要性获取方式用户未提供时的默认值
日志文件路径主要输入;所有内存数据均来自此文件请用户提供服务启动日志—(必需)
GPU 类型决定用于分解验证的 HBM 总量询问用户或从日志推断如有可能,则从日志自动检测
nvidia-smi 输出提供每个 rank 的实际内存,用于交叉验证使用 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 GB
  • server_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 GB
  • Memory pool end. avail mem=XX GB
  • Capture 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.;这些不是当前主分支的日志输出格式。

当前 vLLM V1 日志则会显示:

  • Initial free memory: ...; Requested memory: ...(仅 DEBUG 级别)
  • Model loading took ... GiB
  • Available KV cache memory: ... GiB
  • Graph capturing finished ... took ... GiB
  • <device> KV cache size: ... tokens, Maximum concurrency for ... tokens per request: ...x
  • Free 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 数据

用于比较每个 rank 的内存:

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:查看并解读结果

分析器会输出:

  1. 内存细分表:每个类别(权重、KV 池、CUDA 图、框架、其他)的 GiB、MiB、占比和推导方式
  2. 各 rank 对比:所有 TP rank 的 nvidia-smi 数据
  3. KV 池详情:池配置、KV 数据类型、复制因子、每个 token 的字节数计算
  4. 并发估算:不同 token 长度下的最大并发请求数
  5. 调优说明:可能提升容量的配置更改

对于 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。 捕获后可能会再次调整容量池。请以最终记录的容量和各 rank 的本地证据为准;参见源代码约束。

默认值会根据硬件和配置自动解析。请从 server_args={...} 中读取解析后的值。值越低,运行时余量越大,但 KV 容量会降低。如果未提供该值,请勿推断为 0.88。

KV 头复制

对于标准 GQA/MHA,每个 rank 存储 max(1, num_key_value_heads // tp_size) 个 KV 头。当 TP 大于头数时,每个头会在一组 rank 中复制,而不是在每个 rank 上复制整组头。例如,对于 kv_heads=4, tp=8,每个 rank 存储一个头;对于 kv_heads=1, tp=8,八个 rank 都存储这个单独的头。MLA 则会存储一个复制的潜在表示和 RoPE 键。理论计算假设所有配置的层都位于该 rank 上;对于流水线并行,请使用各 rank 的本地层数。

SWA(滑动窗口注意力)压缩

DeepSeek-V4 等模型使用 CSA(压缩滑动注意力)和 HCA (分层上下文注意力)及滑动窗口。这会降低每个 token 的 KV 缓存字节数,相较于理论上的全注意力计算值更少。日志中报告的 bytes_per_full_token 已考虑这种压缩。

报告清单

包含:

  1. 服务配置:模型、GPU、TP/PP/EP、mem-fraction-static、kv-cache-dtype
  2. 内存细分表:类别 / GiB / MiB / 占比 / 推导来源
  3. 各 rank 的 nvidia-smi 对比:每个 TP rank 的已用和可用内存
  4. KV 池详情:池大小、bytes_per_full_token、KV 数据类型、复制因子、理论上的每 token KV 计算(提供 config.json 时)
  5. 并发估算表:请求 token 长度 / token 限制 / 请求限制 / 最大并发数
  6. 基于可用内存和配置的调优说明

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 注意力,无法根据模型配置独立计算每个 token 的 KV 字节数——需要框架内部的 SWA 窗口参数直接使用日志中的 bytes_per_full_token
DeepGEMM JIT 内存由于日志中未明确报告 DeepGEMM JIT 编译内存,分析器会将其归类为“其他”与 nvidia-smi 总量比较,以准确核算
PP(流水线并行)内存分解按 rank 进行;PP 配置中各阶段的内存可能不均衡为每个 PP 阶段指定 --target-rank
MoE 专家缓冲区某些框架会为专家路由分配额外缓冲区,但不会单独报告根据分配时机,计入“模型权重”或“其他”

参考资料

  • references/log-patterns.md:用于内存分析的日志行模式及其语义。
  • references/gpu-specs.json:h20、h100、h200 和 b200 别名对应的 GPU HBM 规格。
  • scripts/capacity_analyzer.py:核心分析脚本。

内存容量来源

随附的硬件表记录的是厂商标称的 GB 最大值,而非可用的 GiB。优先使用 nvidia-smi 显示的已用量和空闲量,或 vLLM 日志中的总量。B200 保留了 DGX 180GB SKU; 其他 Blackwell SKU 可能有所不同。DGX Spark 的 128GB 是统一系统内存, 并非专用 HBM。L20 是官方的 48GB SKU;不要根据名称推断 l20n 的容量。GB200 记录的是物理 192GB 封装的最大值;其已部署的 SKU 和 定制 SKU 需要通过测量确定总量。每个新增硬件条目均附有官方 来源 URL。

评论

支持 Markdown