大模型应用
当 MAX 推理变慢或 GPU 利用率可疑时…
在 MAX 上对任意内置或通过 --custom-architectures 加载的模型做推理性能 profiling,判断 GPU 是否饱和、时间花在哪些 kernel,以及单个 kernel 为何慢。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 59/100 ×0.15
适用场景
当 MAX 推理变慢或 GPU 利用率可特定
解决思路
- 按成本递增决策:先做 GPU 利用率检查;若 workload 运行时 GPU 空闲或轻载,判定瓶颈在主机侧(CPU、传输、batch 太小),停止并报告;若 GPU 忙,再做 kernel breakdown;仅当单个 kernel 占主导且需要知道原因时,才对该 kernel 做单 kernel 深挖,不要采集超过问题所需的数据。
- 按问题选择工具:GPU 是否忙用 `max.profiler.gpu`(纯 Python,NVIDIA + AMD,秒级,无需额外安装);时间花在哪用 `max ... --profile`,或 NVIDIA 用 `nsys`、AMD 用 `rocprofv3`;单个 kernel 为何慢用 NVIDIA Nsight Compute(`ncu`,仅 NVIDIA,慢,每个 kernel 一次 capture)。
- 按当前步骤只读对应参考:利用率检查读 `references/utilization-api.md` 和内置 `scripts/gpu_snapshot.py`;NVIDIA kernel breakdown 读 `references/nsys.md`;AMD kernel breakdown 读 `references/rocprofv3.md`;NVIDIA 单 kernel 深挖读 `references/ncu.md`。
- 若模型通过 `--custom-architectures` 加载,先读 `references/custom-architectures.md`;profiling 本身与内置架构相同,但加载阶段有额外前置条件和失败模式:与已安装 MAX 版本的 import 兼容性、`PYTHONPATH` 陷阱、架构名冲突、base model 没有 chat template、以及 custom embeddings 模型在 `max serve` 中的限制,这些会在 profiling 前阻止模型加载。
- 解读 dense LLM decode:若被 `gemv_split_k_*` GEMV 主导,`*_mha_*` attention 和 `rms_norm` 在其下,这是正常健康的 dense LLM token generation(decode 是 memory-bound GEMV),无需追查。
- 解读 Sparse-MoE decode:若由 grouped / block-scaled matmul 加 routing kernel 主导,即 per-expert grouped matmul(`*grouped*` / `block_scaled_*` matmul)代替 dense GEMM,并伴随 top-k routing(`topk_*`、`moe_create_indices`)和 expert gather/scatter;多 GPU 时还会出现 EP `dispatch`/`combine` collective。这是 MoE 的健康形态,routing 和 gather 开销是预期的,只有当它逼近 matmul 本身时才值得追查。
- 解读低比特权重(FP8 / FP4 / NVFP4):除 matmul 外会出现 dynamic activation-quantization 和 scale-layout kernel(`*quantize*`、`*block_scales*`)以及 block-scaled matmul 变体,而不是普通 `gemv`/`gemm`。量化/反量化准备耗时对低比特模型正常,只有当它远大于其喂给的 matmul 时才标记。kernel 前缀与 GPU 架构相关(Blackwell 上为 `sm100_*`,Hopper / MI 上不同),应按 kernel family 匹配,不要按精确名字匹配。
- 若 custom architecture 没有命中预期的 fused kernel(例如 attention 显示为通用 `elementwise`/`matmul` 而不是 `*_mha_*` kernel,或 norms/RoPE 未融合),这是 wiring 信号:即使 logits 通过,计算图也可能没有按预期构建,bring-up 期间值得检查。
- 若 decode tok/s 病态低,并且每步重复出现 oversized prefill-shaped kernel mix,这是典型的 O(n²) re-prefill(KV cache 缺失或损坏);这是接近正确性的 bug,不只是慢。
- 若 workload 运行时 `gpu_usage_percent` 低,说明 host-bound、launch/sync 开销或 batch 太小;GPU 不是瓶颈。
- 若出现 throttle reasons,说明 GPU 受时钟限制;在解决 thermal/power 之前,数字不具代表性。
- 持久算法第 1 步:在选定工具前检测环境。运行 `nvidia-smi` 或 `rocm-smi` 确定 vendor;kernel breakdown 和深挖工具因 vendor 而异。确认 profiler 已安装(`which nsys` / `which rocprofv3` / `which ncu`);若缺失,直接告诉用户精确安装命令,而不是中途失败。
- 持久算法第 2 步:任何长生命周期运行前先确认。profiling `max serve` 会预热 compile cache(冷编译可能数分钟)、启动 server 并跑 benchmark;执行前向用户展示模型、flags 和计划命令,等待确认。对 tiny model 的一次性 `max generate --profile` 足够便宜,可跳过确认。
- 持久算法第 3 步:先预热 cache,再 profile。模型首次运行会支付一次性编译和权重加载成本,淹没真实 kernel 时间;先做一次未 profile 的 warm-up run,再做 profiled run,让 capture 反映 steady-state inference 而非 compilation。
- 持久算法第 4 步:保持 capture window 小。concurrency 1 下 10 秒窗口足以看到 kernel mix;长 capture 会产生巨大 trace 文件,打开慢且信息不会更多。
- 持久算法第 5 步:fail fast。启动 server 后几秒内检查进程仍存活且日志没有早期错误(model not found、OOM、bad flag),然后再轮询 `/health`;不要在一个已经死掉的 server 上等完整 timeout。
- 持久算法第 6 步:验证 artifact 后再报告。声称成功前确认输出文件存在且大小非平凡;报告 artifact 路径、如何打开,以及 headline numbers(top kernels 或 peak GPU utilization)。
- 持久算法第 7 步:只清理自己启动的东西。kill 自己启动的 server / benchmark 进程组;在共享机器上避免 broad `pkill -f max`,以免停掉别人的运行。
- Nightly vs stable:profiling 功能先进入 nightly 再进入 stable,因此用 nightly `max-serve` build。用 pixi 安装:`pixi init quickstart -c https://conda.modular.com/max-nightly/ -c conda-forge`;`cd quickstart && pixi add max-serve`;`pixi run max --version` 应显示 `*.dev` build。
- 利用率 API(`GPUDiagContext`、`BackgroundRecorder`)随 **conda** `max` 包发布,所以用 pixi 或 conda 安装,而不是普通 `pip install max` wheel,后者可能不暴露 `max.profiler.gpu`。若命令 404 或 import 失败,确认自己在较新的 nightly build 上。
- MAX 安装:使用通过 pixi 安装 nightly `max-serve` 包的项目;下文所有 `max` CLI 命令都假定可在该项目中运行 `pixi run max ...`。`max-serve` 包含用 MAX serve 模型所需的额外依赖,主 `max` 包不包含这些依赖。
- `nsys` 和 `ncu` 随 CUDA Toolkit 发布。若 `which nsys` 失败但 CUDA 存在,`export PATH=/usr/local/cuda/bin:$PATH`;否则从 NVIDIA 安装 Nsight Systems / Nsight Compute,或 `sudo apt-get install nsight-systems`。
- `rocprofv3` 随 ROCm 发布(`/opt/rocm/bin`);需要时加入 PATH。
- 利用率 API 除 `max` 外不需要额外工具:它通过 `max.profiler.gpu` 直接与 NVML / ROCm SMI 通信。
- Fast path:问“GPU 是否被使用?”时,在短 benchmark 旁运行 `scripts/gpu_snapshot.py`;纯 Python,NVIDIA 和 AMD 都可用。
- Fast path:要快速 kernel breakdown,运行 `pixi run max generate --model <m> --prompt "hello" --num-warmups 1 --profile`。它会打印排序后的 top-N GPU-kernel 表,并写出 `.nsys-rep`(NVIDIA);无 GPU 时回退为 CPU 摘要。
- Fast path:要 profile serving benchmark,使用 serving-endpoint 流程,设置 `MODULAR_ENABLE_PROFILING=detailed`,配合 `nsys launch` / `rocprofv3`。
适用边界 · 注意事项
- 没有 pip/pixi 安装的 MAX 或没有 NVIDIA/AMD GPU 时不适用;这不是通用 PyTorch profiling 流程。
- 未安装与 vendor 匹配的 profiler(NVIDIA 的 nsys/ncu 或 AMD 的 rocprofv3)时,无法做 kernel breakdown 和单 kernel 深挖,只能先做利用率检查。
- 不要在共享机器上用 broad `pkill -f max` 清理环境;只清理自己启动的 server/benchmark 进程组。