profile_decode.sh 2.6 KB

12345678910111213141516171819202122232425262728293031323334
  1. #!/usr/bin/env bash
  2. # Profile N steady-state decode steps on rank 0 (mid-generation, no prefill) and
  3. # group GPU kernel time by category. Usage: profile_decode.sh LABEL [steps] [prompt]
  4. set -euo pipefail
  5. label=${1:?label}; steps=${2:-10}; prompt=${3:-Write a Python function implementing an LRU cache class with get/put, with type hints and docstrings. Code only.}
  6. dir=$HOME/mimo-v2.6-pro/cache/prof-$label; rm -rf "$dir"
  7. curl -s localhost:30000/v1/chat/completions -H 'Content-Type: application/json' -d "{\"model\":\"mimo-v2.6-pro\",\"messages\":[{\"role\":\"user\",\"content\":\"$prompt\"}],\"max_tokens\":600,\"temperature\":0,\"chat_template_kwargs\":{\"enable_thinking\":false}}" >/dev/null &
  8. sleep 2
  9. curl -s -XPOST localhost:30000/start_profile -H 'Content-Type: application/json' \
  10. -d "{\"output_dir\":\"/root/.cache/prof-$label\",\"num_steps\":$steps,\"activities\":[\"GPU\"]}" >/dev/null
  11. wait
  12. for _ in $(seq 60); do ls "$dir"/*TP-0*.gz >/dev/null 2>&1 && break; sleep 1; done; sleep 3
  13. python3 - "$dir" "$steps" <<'PY'
  14. import gzip, json, collections, glob, sys, re
  15. f = sorted(glob.glob(sys.argv[1] + "/*TP-0*.gz"))[-1]; steps = int(sys.argv[2])
  16. ev = [e for e in json.load(gzip.open(f))["traceEvents"] if e.get("ph") == "X" and e.get("cat") in ("kernel", "gpu_memcpy", "gpu_memset")]
  17. span = max(e["ts"] + e["dur"] for e in ev) - min(e["ts"] for e in ev)
  18. busy = sum(e["dur"] for e in ev)
  19. rules = [("allreduce-roce", r"roce|Roce"), ("allreduce/gather-nccl", r"nccl"), ("moe-gemm", r"GroupProblemShape|fused_moe|marlin|Marlin"),
  20. ("moe-misc", r"MoeRouting|expandInputRows|doActivation|ExpertMaps|computeStrides|router|quantize_with_block|topk"),
  21. ("bf16-gemm (o_proj/lm_head/draft)", r"wmma|nvjet|gemv|splitKreduce|cublas|gemm_bf16"),
  22. ("fp8-gemm (qkv/dense)", r"w8a8|fp8"), ("attention", r"_fwd_kernel|attn|attention|decode_grouped|flash"),
  23. ("norm/rope/kv-store", r"rmsnorm|RMSNorm|rotary|kvcache|store_kv"), ]
  24. cat = collections.defaultdict(float); top = collections.defaultdict(lambda: [0, 0])
  25. for e in ev:
  26. n = e["name"]; top[n[:90]][0] += e["dur"]; top[n[:90]][1] += 1
  27. for c, rx in rules:
  28. if re.search(rx, n): cat[c] += e["dur"]; break
  29. else: cat["other"] += e["dur"]
  30. print("steps %d span %.1f ms (%.1f ms/step) gpu busy %.1f ms (%.0f%%)" % (steps, span/1e3, span/1e3/steps, busy/1e3, 100*busy/span))
  31. for c, d in sorted(cat.items(), key=lambda x: -x[1]): print(" %-34s %7.2f ms/step %4.1f%%" % (c, d/1e3/steps, 100*d/busy))
  32. print("top kernels:")
  33. for n, (d, c) in sorted(top.items(), key=lambda x: -x[1][0])[:12]: print(" %7.2f ms/step %5d %s" % (d/1e3/steps, c, n))
  34. PY