feat(analysis): swim-lane viewer and aiperf analyze CLI#1116
feat(analysis): swim-lane viewer and aiperf analyze CLI#1116ajcasagrande wants to merge 1 commit into
Conversation
Try out this PRQuick install: pip install --upgrade --force-reinstall git+https://github.com/ai-dynamo/aiperf.git@798274bf58fdc1159cef82ac992cd6fa5de8aa89Recommended with virtual environment (using uv): uv venv --python 3.12 && source .venv/bin/activate
uv pip install --upgrade --force-reinstall git+https://github.com/ai-dynamo/aiperf.git@798274bf58fdc1159cef82ac992cd6fa5de8aa89Last updated for commit: |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Signed-off-by: Anthony Casagrande <acasagrande@nvidia.com>
dcf36b8 to
798274b
Compare
WalkthroughThis PR adds a new "aiperf analyze swim-lane" CLI command that renders per-session swim-lane visualizations from AIPerf run data. It includes a new analysis module for session grouping, layout, and curve computation, a self-contained interactive HTML viewer, CLI wiring, tests, and documentation updates. ChangesSwim-Lane Analysis Feature
Estimated code review effort: 4 (Complex) | ~75 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/aiperf/analysis/swim_lane.py (1)
1154-1158: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRead the viewer template via
safe_read_template_path.
VIEWER_TEMPLATE.read_text()is an inline filesystem template read. The repo standard is to route template reads throughaiperf.common.path_safety.safe_read_template_path.♻️ Suggested change
+ from aiperf.common.path_safety import safe_read_template_path + html = ( - VIEWER_TEMPLATE.read_text() + safe_read_template_path(VIEWER_TEMPLATE) .replace("__AIPERF_TITLE__", run_dir.name) .replace("__AIPERF_PAYLOAD_B64__", payload_b64) )As per coding guidelines: "Read filesystem paths through
aiperf.common.path_safety.safe_read_template_pathinstead of inlinePath().read_text()oropen().read()."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/aiperf/analysis/swim_lane.py` around lines 1154 - 1158, The viewer HTML is reading the template directly with VIEWER_TEMPLATE.read_text(), which bypasses the repo’s path-safety standard. Update the template load in swim_lane.py to use aiperf.common.path_safety.safe_read_template_path for VIEWER_TEMPLATE, then keep the existing __AIPERF_TITLE__ and __AIPERF_PAYLOAD_B64__ replacements unchanged.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/aiperf/analysis/swim_lane_viewer.html`:
- Around line 1971-1985: The PNG export in exportPng is missing the TTFT latency
panel because the stacked canvas list excludes latCv. Update the list assembled
in exportPng to include the latency canvas in the correct position alongside
rulerCv, lanesCv, islCv, tputCv, kvCv, and navCv so the exported image matches
the full swim lane view.
---
Nitpick comments:
In `@src/aiperf/analysis/swim_lane.py`:
- Around line 1154-1158: The viewer HTML is reading the template directly with
VIEWER_TEMPLATE.read_text(), which bypasses the repo’s path-safety standard.
Update the template load in swim_lane.py to use
aiperf.common.path_safety.safe_read_template_path for VIEWER_TEMPLATE, then keep
the existing __AIPERF_TITLE__ and __AIPERF_PAYLOAD_B64__ replacements unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 08665681-6d07-4a1f-9e3e-72b46c719c50
📒 Files selected for processing (8)
docs/cli-options.mdsrc/aiperf/analysis/swim_lane.pysrc/aiperf/analysis/swim_lane_viewer.htmlsrc/aiperf/cli.pysrc/aiperf/cli_commands/analyze.pysrc/aiperf/cli_commands/swim_lane.pytests/unit/analysis/test_swim_lane.pytools/ruff_baseline.json
| function exportPng() { | ||
| const list = [rulerCv, lanesCv, islCv, tputCv, kvCv, navCv]; | ||
| const out = document.createElement("canvas"); | ||
| out.width = Math.max(...list.map((c) => c.width)); | ||
| out.height = list.reduce((a, c) => a + c.height, 0); | ||
| const c = out.getContext("2d"); | ||
| c.fillStyle = "#0a0d13"; | ||
| c.fillRect(0, 0, out.width, out.height); | ||
| let y = 0; | ||
| for (const cv of list) { c.drawImage(cv, 0, y); y += cv.height; } | ||
| const a = document.createElement("a"); | ||
| a.download = `${DATA.run}-swimlane.png`; | ||
| a.href = out.toDataURL("image/png"); | ||
| a.click(); | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
PNG export omits the TTFT latency panel.
list stacks ruler, lanes, ISL, throughput, KV, and nav, but latCv is missing, so the exported PNG drops the latency band chart that is otherwise rendered in the UI. This looks unintentional given the comment "stack every panel canvas into one image."
🐛 Suggested fix
- const list = [rulerCv, lanesCv, islCv, tputCv, kvCv, navCv];
+ const list = [rulerCv, lanesCv, islCv, tputCv, kvCv, latCv, navCv];📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function exportPng() { | |
| const list = [rulerCv, lanesCv, islCv, tputCv, kvCv, navCv]; | |
| const out = document.createElement("canvas"); | |
| out.width = Math.max(...list.map((c) => c.width)); | |
| out.height = list.reduce((a, c) => a + c.height, 0); | |
| const c = out.getContext("2d"); | |
| c.fillStyle = "#0a0d13"; | |
| c.fillRect(0, 0, out.width, out.height); | |
| let y = 0; | |
| for (const cv of list) { c.drawImage(cv, 0, y); y += cv.height; } | |
| const a = document.createElement("a"); | |
| a.download = `${DATA.run}-swimlane.png`; | |
| a.href = out.toDataURL("image/png"); | |
| a.click(); | |
| } | |
| function exportPng() { | |
| const list = [rulerCv, lanesCv, islCv, tputCv, kvCv, latCv, navCv]; | |
| const out = document.createElement("canvas"); | |
| out.width = Math.max(...list.map((c) => c.width)); | |
| out.height = list.reduce((a, c) => a + c.height, 0); | |
| const c = out.getContext("2d"); | |
| c.fillStyle = "`#0a0d13`"; | |
| c.fillRect(0, 0, out.width, out.height); | |
| let y = 0; | |
| for (const cv of list) { c.drawImage(cv, 0, y); y += cv.height; } | |
| const a = document.createElement("a"); | |
| a.download = `${DATA.run}-swimlane.png`; | |
| a.href = out.toDataURL("image/png"); | |
| a.click(); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/aiperf/analysis/swim_lane_viewer.html` around lines 1971 - 1985, The PNG
export in exportPng is missing the TTFT latency panel because the stacked canvas
list excludes latCv. Update the list assembled in exportPng to include the
latency canvas in the correct position alongside rulerCv, lanesCv, islCv,
tputCv, kvCv, and navCv so the exported image matches the full swim lane view.
Summary
Stacked on #1102 (
ajc/metrics-accumulator-engine) — carve-out of the swim-lane viewer and theaiperf analyzeCLI from the agentx branch.Adds post-run visualization of completed AIPerf artifacts:
src/aiperf/analysis/swim_lane.py— session swim-lane renderer overprofile_export.jsonl: one lane per concurrent session slot (greedy slot reuse), subagent sessions (agent_depth > 0) nested as child tiers below their root session's lane, plus concurrency / throughput / tokens-in-flight / TTFT-band curves built on the sameaiperf.analysis.sweeplineprimitives the metrics accumulator uses (from feat(metrics): accumulator engine with records-pipeline wiring #1102).src/aiperf/analysis/swim_lane_viewer.html— single-file interactive canvas trace viewer; the JSON payload is embedded gzip+base64 and inflated client-side via the nativeDecompressionStream(no vendored JS dependencies).src/aiperf/cli_commands/analyze.py— newaiperf analyzedispatcher for post-run artifact analysis subcommands.src/aiperf/cli_commands/swim_lane.py—aiperf analyze swim-lane <run_dir>... [-o OUT] [-c N] [--ramp S] [--html]writesswim_lane.png(and optionallyswim_lane.html).tests/unit/analysis/test_swim_lane.py— root-map resolution (authoritativeroot_correlation_idgrouping + legacyparent_correlation_idwalk), lane layout/nesting, PNG/HTML render, and v1/v2 ramp-config parsing.docs/cli-options.mdregenerated (make generate-cli-docs).tools/ruff_baseline.json: two C901 (complexity) baseline entries for the matplotlib-heavyplot_swim_lane/write_swim_lane_htmlrenderers, mirroring the agentx branch's baseline.Deliberate overlap with the upcoming turn-messages PR
This PR owns
src/aiperf/cli_commands/analyze.pyand theanalyzewiring line insrc/aiperf/cli.py. A sibling agentx carve-out PR (turn-messages viewer) will add itsapp.command(... turn_messages ...)registration to the sameanalyze.pydispatcher — that reference was deliberately stripped here soaiperf analyzeworks standalone with onlyswim-laneregistered. Expect a small, intentional merge overlap in those two files.Adaptations from the agentx branch
analyze.py: dropped theturn-messagessubcommand registration (sibling PR adds it back).cli_commands/swim_lane.py: options made keyword-only (*,afterrun_dirs) to satisfy the ergonomics ratchet at the site instead of growing the baseline; behavior-neutral for cyclopts (all options carry explicitParameternames,RUN-DIRSstays positional).root_correlation_idandcontext_overflow_skipare not emitted by this branch'sMetricRecordMetadata— both are read via.get()with graceful fallbacks (legacy parent-walk grouping; status 0), so exports from this branch render correctly today and pick up richer nesting when the agentx metadata lands.Test + smoke evidence
uv run pytest -n auto tests/unit/analysis/— 166 passed (includes the 33 new swim-lane tests).uv run pytest --collect-only -q tests/unit/— 14304 collected, no collection errors.make check-ruff-baselined— OK (121 total, 121 baselined, 0 new).make check-ergonomics— OK (61 total, 61 baselined, 0 new).aiperf.analysis.swim_lane,aiperf.cli_commands.{analyze,swim_lane},aiperf.cliall import; viewer template resolves next to the module.uv run aiperf analyze --help,uv run aiperf analyze swim-lane --help, then droveuv run aiperf analyze swim-lane /tmp/swimlane-smoke -c 2 --htmlagainst a synthetic run dir (main session + 2 parallel subagents + 1 plain session, v2 ramp config) — wroteswim_lane.png(correct nesting, ramp marker, target line) andswim_lane.html; decoded the embedded gzip payload and verified all 4 sessions,nSlots=2,rampS=2.0, subagent peaks.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Tests