Skip to main content

perf-optimize

Launch and operate this repo's perf-optimize workflow, which iteratively APPLIES TensorRT-LLM serving optimizations — baseline benchmark at one concurrency or a Pareto curve of them (tok/s/user vs tok/s/gpu), analytical SOL projection on by default (via the internal-perf-sol-analysis skill) sizing the headroom the campaign chases, profile-ranked roadmap.yaml (nsys + ncu per-kernel analysis via the perf-nsight-compute-analysis skill), a fixed budget of rounds applying items one at a time gated on measured gain (curve mode uses a Pareto gate; the evaluator accepts, rejects, or pushes back each attempt and nsys-profiles every accept), one final-verification QA benchmark, expected-vs-measured report with Pareto improvement results. Use when the user wants to optimize / improve / speed up a trtllm-serve deployment (throughput, TTFT, TPOT, ITL, e2e latency) or says "run perf-optimize". For diagnosis WITHOUT applying changes, use the perf-analyze workflow instead.

Informações da origem

Repositório
NVIDIA/TensorRT-LLM
Última atividade na origem
8 de setembro de 2026 às 13:18
Idioma detectado do SKILL.md
inglês
Estrelas
14.826
Forks
2.823

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
perf-optimize
description
Launch and operate this repo's perf-optimize workflow, which iteratively APPLIES TensorRT-LLM serving optimizations — baseline benchmark at one concurrency or a Pareto curve of them (tok/s/user vs tok/s/gpu), analytical SOL projection on by default (via the internal-perf-sol-analysis skill) sizing the headroom the campaign chases, profile-ranked roadmap.yaml (nsys + ncu per-kernel analysis via the perf-nsight-compute-analysis skill), a fixed budget of rounds applying items one at a time gated on measured gain (curve mode uses a Pareto gate; the evaluator accepts, rejects, or pushes back each attempt and nsys-profiles every accept), one final-verification QA benchmark, expected-vs-measured report with Pareto improvement results. Use when the user wants to optimize / improve / speed up a trtllm-serve deployment (throughput, TTFT, TPOT, ITL, e2e latency) or says "run perf-optimize". For diagnosis WITHOUT applying changes, use the perf-analyze workflow instead.
license
Apache-2.0
metadata
{"author":"NVIDIA Corporation"}
# Operating the perf-optimize workflow `perf-optimize` is this repo's iterative optimization campaign for `trtllm-serve`: benchmarker (baseline) → projector (a one-shot analytical speed-of-light ceiling; on unless task.yaml sets `sol.enabled: false`) → a fixed budget of rounds of [analyzer (re-profile when the runtime evidence is stale; otherwise replan-only) → (optimizer ⇄ evaluator) per roadmap item] → one final-verification QA pass → reporter. Every change is gated on code quality, functionality, and measured gain vs the last accepted measurement — the evaluator's verdict is three-way (APPROVE / REJECT terminally / PUSH_BACK for a bounded retry), and every accept is profiled under nsys (accept-evidence capture). No agent decides when to stop: the loop runs `optimize.max_rounds` rounds unless the roadmap runs out of actionable items or the optional improvement target is met. The deliverable is `<workspace>/optimization_report.md` (+ `.html`). Do not hand-roll a serve/benchmark/tune loop when the user asks to optimize serving performance — drive this workflow instead. Authoritative references (read them before answering detailed questions): - `<agent_flow>/workflows/perf_optimize/README.md` — contract, acceptance gate, workspace layout, git requirements. - `<agent_flow>/workflows/perf_optimize/task.example.yaml` — fully commented task template. Use perf-optimize when the user wants changes applied and verified. The workflow itself now ships from TensorRT-LLM, under `agent-flow/`; the paths below are relative to the INSTALLED `agent_flow` package. Print its location with `python -c "import agent_flow,pathlib;print(pathlib.Path(agent_flow.__file__).parent)"`, or read them out of `<trtllm_repo_path>/agent-flow/agent_flow/`. Use `perf-analyze` (same repo) when they only want a bottleneck diagnosis. ## 1. Preflight — verify before launching Run these checks; fix or ask only where noted. 1. **CLI installed**: `perf-optimize --help` works. If not: `pip install -e <trtllm_repo_path>/agent-flow`. The workflow drives the Claude Code backend, so the `claude` CLI must be installed and signed in; `CLAUDE_CODE_DEFAULT_MODEL` overrides the model if the user wants. 2. **Paths from the user**: `checkpoint_path` (model checkpoint dir) and `trtllm_repo_path` (TensorRT-LLM checkout) must exist — the CLI refuses to start otherwise. 3. **Git safety (STOP if it fails)**: `trtllm_repo_path` must be a TensorRT-LLM git repo, and its worktree should be clean (`git -C <repo> status --porcelain` empty). The workflow mutates the checkout: rejected attempts are reverted with `git reset --hard` + `git clean -fd`, which destroys any uncommitted, unignored changes present when the run starts. If the worktree is dirty, do NOT launch — ask the user to commit/stash (or confirm the changes are disposable). Work happens on a fresh `perf-optimize/<workspace>-<timestamp>` branch off the current HEAD; one commit per accepted item. 4. **Editable install (affects scope, not launch)**: source-level (`approach: code`) items only take effect when `python -c "import tensorrt_llm; print(tensorrt_llm.__file__)"` resolves into `trtllm_repo_path`. If it doesn't, tell the user the run will be config-only (the agents detect this too) — still fine to run. 5. **Environment**: either the current node has GPUs (`nvidia-smi` works), or the task carries a `slurm-environment` block that routes the server + benchmark through a Slurm-launched container (`task.example.yaml:139`). On a login or head node with no local GPUs — the most common case — bring up the node and container with your own site's recipe first. 6. **Internal toolkit skills (affects depth, not launch)**: the default-on SOL projector wants `internal-perf-sol-analysis`. That is an `internal-`prefixed skill, so **open-source builds of the `trtllm-agent-toolkit` plugin strip it** while keeping `perf-analysis`. **The CLI checks this itself** at launch and prints one line when the skill is missing, so this is context for the user rather than something you must gate on. The campaign completes either way: without the SOL skill the projector falls back to `perf-analysis`, grounds the peaks from named sources rather than the skill's calculator, marks them as such, and writes no `sol_work/peaks.json` — so the analyzer skips the per-round measured↔SOL correlation, and every roadmap item's `expected_gain_pct` rests on a coarser ceiling. Say so up front; if the user doesn't want the degraded stage, write `sol: {enabled: false}` to skip its wall-clock outright. Never work around a missing skill by having an agent recall hardware peaks. 7. **Disaggregated deployment?** A `disagg:` block in `task.yaml` makes the workflow drive the checkout's own harness (`examples/disaggregated/slurm/benchmark/submit.py`) instead of launching `trtllm-serve`, so this host must be able to `sbatch` **and** see the cluster paths the harness config names. Everything else about the mode is documented on the `disagg` block in `task.example.yaml`. ## 2. Write task.yaml (if the user didn't provide one) Copy `<agent_flow>/workflows/perf_optimize/task.example.yaml` into the workspace-to-be and fill it in. Required: `checkpoint_path`, `trtllm_repo_path`. Ask the user for anything they haven't stated rather than inventing values: - `benchmark`: the operating point(s) every measurement replays (ISL/OSL/concurrency/num_prompts). Defaults exist, but confirm they match the user's deployment shape. `concurrency` is a single int or a list of ints — a list turns on Pareto-curve mode: every measurement (baseline, each evaluator attempt, each QA round) runs once per point, and the evaluator applies the Pareto gate (mean per-point gain must pass the thresholds AND no point may regress beyond the noise floor); the report gains a Pareto Improvement section (x = tok/s/user, y = tok/s/gpu). Benchmark cost multiplies by the point count — keep the list short (~3-5 points), or pair it with a `num_prompts` **list** (same length, each entry ≥ its point) so low-concurrency points run far fewer prompts than high-concurrency ones; that is what makes a wide curve affordable. - **Size the per-measurement cost before launching** — this is the #1 preflight trap. Estimate one full measurement as `Σ_points (num_prompts_i × OSL / expected_agg_tok_s(c_i))` and keep it well under the allocation walltime minus ~30 min of env build (the campaign replays it for the baseline, every evaluator attempt, and the final verification; a measurement that cannot finish inside one allocation restarts forever and the campaign never completes). Example: 9 points [1..256] × 4096 prompts × OSL 6144 ≈ 30-70 h per measurement — infeasible; scaling num_prompts [8..1024] with the points brings it to ~1 h. - `optimize.target_metric` (default `output_throughput`; latency keys like `median_ttft_ms`/`median_tpot_ms` also work — gains are normalized so positive = better) and optional `optimize.target_improvement_pct` (orchestrator-enforced early stop). - `optimize` budgets — defaults `max_rounds: 5`, `max_items_per_round: 3`, `max_attempts_per_item: 3`, `accept_fraction: 0.5`, `noise_floor_pct: 1.0` — are sensible. The loop **runs the full round budget** (it only ends early when the target is met, or an analyzer turn finds no actionable item), so `max_rounds × max_items_per_round` is what bounds the items a campaign can attempt — 15 with the defaults. `optimize.item_execution` defaults to `parallel`; set it to `serial` to apply approved items directly in order from the latest campaign state. Two things worth telling the user when sizing a run: - **Rounds are not equally expensive.** A round pays for a profile after an accept, after a reverted code attempt may have changed gitignored build output, or when an older checkpoint cannot prove its profile is current. Otherwise it opens replan-only — the analyzer plans from the standing profile and the round's verdicts without touching the GPU. On a config-only plateau `max_rounds` costs almost nothing beyond the per-attempt benchmarks; a productive or code-mutating campaign pays more profiling turns. - The per-item cost driver is the **evaluator benchmark**, one per attempt, which no mode avoids. `noise_floor_pct` and `approaches` are what keep the item list short. - `optimize.approaches` (default `[config, code]`): set `[code]` when the user wants genuine source-level optimizations only (no tuning-YAML knob changes — attempts that touch the tuning file are auto-rejected; requires the editable install from preflight step 4), or `[config]` when the TRT-LLM checkout must not be modified at all. - `profile`: `methods` (subset of `[nsys, ncu]`, default both — what a profiling round captures: nsys timeline + a bounded ncu per-kernel deep dive on the top nsys kernels, interpreted with the `perf-nsight-compute-analysis` skill; drop entries to trim the cost of the rounds that pay it) and `nsys_iter_range` (default `"100-150"`). - `profile.kernel_coverage`: include (an empty mapping enables the defaults `min_share_pct: 0.5`, `coverage_target_pct: 95`) when the user wants the **per-kernel coverage contract** — ncu SOL analysis on every kernel above the share bar (multi-pass capture) and, per kernel, an explicit answer to *can it be eliminated?*, *can it be made faster?*, *can it be fused with its neighbors?* and *can it be overlapped with independent work on another stream?* recorded in a schema-validated `kernel_ledger.yaml` each profiling round (a roadmap item or an evidence-backed dismissal per question; the orchestrator aborts the round on an incomplete ledger — replan-only rounds run no ncu and are waived — and the report gains a Kernel Coverage accountability section resolving every disposition to its outcome). The four are ordered by how much they presuppose. *Elimination* comes first because it assumes only that the kernel runs today, and a `yes` recovers its whole share rather than a fraction — redundant work, work over padded/masked data, per-step recompute of an invariant, or a fallback kernel firing because a gated fast path did not. *Overlap* catches what faster and fusion structurally cannot: both presuppose the kernel runs *alone*, so a kernel at its bound-class ceiling whose neighbors move only mandatory bytes is legitimately closed on both and can still give back most of its share on an aux stream (it needs CUDA graphs enabled — multi-stream no-ops without them, so mention that if the user is running graphs off). The ledger also records the profiled window's `gpu_busy_pct`, because a kernel's share of GPU time is not its share of wall clock and only the latter can move the target metric. This is the "every kernel elimination/optimization/fusion/ overlap possibility considered before done" guarantee; it needs `nsys` + `ncu` in `profile.methods` and adds profiling wall-clock to every round that profiles. - `accuracy`: include only if the user has an eval command they want the final verification to run at campaign end; omit the block otherwise. - `extra_llm_api_options`: starting server tuning YAML, if they have one. It seeds `<workspace>/tuning/extra_llm_api_options.yaml`, which the optimizer then evolves — the workflow always passes the workspace copy to `trtllm-serve`. - `sol`: **the analytical SOL-projection stage is on by default**, so omit this block unless the user wants to turn it off or hand the skill a hint. Enabled, it produces `sol_projection.md` + `sol_work/peaks.json` after the baseline; the analyzer ranks roadmap items against the projected headroom, correlates each round's per-op measurements against the ceiling via the skill's `sol_calc.py analyze` into the findings' *SOL correlation* section, and owes a remaining-gap attribution whenever it exhausts the roadmap with headroom left, the optimizer aims each item's realization at the binding ceiling, and the report gains a Projection vs Measured headroom-captured section closed by a remaining-gap accountability breakdown. Write `sol: {enabled: false}` when the user explicitly does not want it — e.g. to save the extra stage's wall-clock, or when the SOL skill is unavailable. The projector follows the `internal-perf-sol-analysis` skill (from the `trtllm-agent-toolkit` plugin — an `internal-` skill, so open-source builds strip it; install a build that has it for the full methodology). Without it the projector falls back to `perf-analysis` and degrades honestly: a coarse ceiling grounded on named sources rather than the peaks calculator, no peaks file, and no per-round correlation. It never recalls a hardware peak. Every field is optional — `enabled` gates the stage (default `true`) and `gpu` is the part-name hint for the skill's peaks calculator. The stage needs no GPU (with local GPUs it additionally measures the skill's latency constants) and runs once per campaign — the ceiling is a property of hardware + model + operating point, not of the applied optimizations. Where a spec or a mapping stays uncertain, the projector is pointed at the `internal-glean-search` skill / `internal-glean-specialist` subagent as read-only reference, used only if that skill or subagent is installed in the session. The hosted-MCP wiring this skill used to document (`--glean-mcp-url`, `$PERF_OPTIMIZE_GLEAN_MCP_URL`) is gone: the workflow ships from TensorRT-LLM now, and upstream replaced the MCP server with that skill. Passing the flag would be a CLI error. ## 3. Launch (long-running — background it) ```bash perf-optimize --task <path>/task.yaml --workspace workspace/perf-optimize/<model-name> \ > <somewhere>/perf_optimize.log 2>&1 ``` A campaign runs for hours (each round: a full benchmark per attempt + a profiled replay per accept, plus one re-profile when the standing runtime evidence became stale; plus one final-verification benchmark at the end). Launch it in the background (`run_in_background` / `nohup`) with output captured to a log file, then monitor. - **Resume**: re-running the identical command resumes from `<workspace>/.perf_optimize_state.json` — interruption (Ctrl-C, crash, node loss) is safe. - **Fresh start**: `--clean` wipes the workspace's managed state but never touches the TRT-LLM checkout (abandoned `perf-optimize/*` branches are left for inspection). - `--max-rounds N` overrides the round budget on a fresh run only; ignored on resume. - `--reuse-analysis <dir>` starts a fresh run **at the optimize stage** by importing a previous `perf-analyze` workspace or `perf-optimize` campaign workspace: its baseline report (+ result JSONs), SOL projection (+ `sol_work/`), and newest profile findings (+ traces, `kernel_ledger.yaml`) are copied in, the benchmarker/projector are skipped, and round 1's analyzer plans from the imported evidence without launching a server or a profiler. Rounds 2+ profile normally. Reach for this when the user has *just* run `perf-analyze` on the same deployment, or is starting a follow-up campaign on a machine whose baseline has not changed — it saves the two most expensive stages. Check before proposing it: the imported baseline is what every gain is measured against, so the source run must describe the **same** model, checkpoint, hardware, parallel mapping and operating point. When in doubt, don't reuse the baseline (the import is per-artifact — point at a source with only findings, or just run normally). A source `roadmap.yaml` is kept as read-only prior art in `reused_analysis/prior_roadmap.yaml`, never as this campaign's ledger; `reused_analysis/manifest.md` records the provenance and the report repeats it. Fresh runs only — ignored on resume. ## 4. Monitor Poll the workspace (and the launch log) rather than waiting silently: - `progress.yaml` — append-only audit log; new entries mean it's alive. - `roadmap.yaml` — the ranked plan; watch item `status` and measured gains vs `expected_gain_pct`; `current_best` tracks the last accepted measurement. - `baseline/benchmark_results.md` (and `sol_projection.md` right after it unless `sol.enabled: false`), then per-round `rounds/round_<n>/` (`analysis/profile_findings.md`, `item_<j>_<id>/attempt_<k>/` — accepted attempts also grow a `profile/` nsys capture), and at the end `final_verification/verification_report.md`. A round whose standing runtime profile is still current writes a short replan note in place of a profiling report, and no traces — that is the replan-only mode, not a stalled analyzer. - `git -C <trtllm_repo_path> log --oneline` on the `perf-optimize/*` branch — one commit per accepted item. If it dies, read the tail of the launch log, fix the environment issue, and re-run the same command to resume. ## 5. Wrap up When the run finishes (round budget spent, roadmap exhausted, or the improvement target met), report to the user from `optimization_report.md` / `.html`: - the verified cumulative improvement vs baseline on the target metric (from the final verification's independent benchmark), - the optimization trajectory (baseline → each accepted item → final verification; the HTML renders it as a line chart), - expected-vs-measured per applied item, failed attempts with reasons, - the kernel-level before/after comparison — the "after" side comes from the **last accepted attempt's `profile/`** (the accept-evidence nsys capture the evaluator takes on every APPROVE; rejects are reverted, so it always reflects the final accepted state), else the last round's profile, - final config (`tuning/extra_llm_api_options.accepted.yaml`) and the code diff on the `perf-optimize/*` branch, - when the projector ran: the Projection vs Measured section — baseline vs final % of SOL, i.e. how much of the analytically projected headroom the campaign captured, which bound class the remaining gap sits in, and the remaining-gap accountability breakdown (every part of the gap `closed` / `infeasible: <constraint>` / `untried` / `unexplained`, each verdict citing evidence — relay this to the user: it is the answer to "why does the campaign end here?"), - remaining roadmap items as future work. Point the user at the branch + accepted config for productionizing (cherry-pick / PR is theirs to drive — the workflow never pushes). ## Pitfalls A Slurm allocation is time-limited; when its walltime expires the node is taken back, which also kills the agent-flow process. When that happens, allocate a fresh node and launch the perf-optimize workflow again with the same command — it resumes from `<workspace>/.perf_optimize_state.json` at the interrupted stage. The walltime ceiling is usually enforced by the *partition*, not by the QoS list your account carries: a partition can set `DenyQos=...`, so a long QoS that `sacctmgr show assoc` happily lists is still rejected at submit with "Invalid qos specification" and only a short QoS passes. Read the partition's own limits (`scontrol show partition <partition>`) rather than your association, and size the benchmark block to the window you actually get (see the per-measurement cost note above). For unattended multi-window campaigns, don't rely on the driving session staying alive to resubmit: run a small nohup'd **keeper loop** on the launch host that every ~5 min resubmits the sbatch iff the workflow state JSON has `done: false` and the queue has no job of that name (double-check an empty queue reading ~60 s apart before resubmitting; guard with a pidfile and a stop-sentinel file). A session restart otherwise turns a walltime kill into a silent hours-long stall. ## Improvement suggestions This workflow and this skill are under active development. If driving a run surfaces an issue — a bug or crash in agent-flow, a misleading log or report, a preflight check this skill is missing, a stale or wrong instruction — don't just work around it silently. Note it while it's concrete, and when reporting results to the user, include a short list of workflow improvement suggestions: what went wrong, where (file / step), and the fix you'd propose. If a fix is a small edit to this skill or the workflow docs, offer to apply it.
Ver no GitHub