Skip to content

fix(runtime): Scope the L3 swimlane name map to each dispatch's own L2 program - #2173

Merged
lyfne123 merged 2 commits into
hw-native-sys:mainfrom
luohuan19:issue-2169-l3-swimlane-name-map
Jul 29, 2026
Merged

fix(runtime): Scope the L3 swimlane name map to each dispatch's own L2 program#2173
lyfne123 merged 2 commits into
hw-native-sys:mainfrom
luohuan19:issue-2169-l3-swimlane-name-map

Conversation

@luohuan19

Copy link
Copy Markdown
Contributor

Summary

_collect_l3_swimlane merged every next_levels/*/kernel_config.py into one flat func_id -> name table and wrote it into every rank*/d{k} dispatch dir. func_id is a per-L2-program namespace — each program numbers its kernels from 0 — so the alphabetically-later program won ids 0..N and every other dispatch was rendered with its names. The converter's -k fallback had the same flaw (work_dir was always chip_dirs[0]).

On a two-program L3 kernel this printed lm_head_dispatch_wait (a cross-card spin-wait) as mtp_projection_norm — a 24 ms barrier reading as a 24 ms RMS-norm kernel, in the console table and in the Perfetto trace alike. Silent, and actively misleading for performance work.

Nothing on disk recorded which program produced which dispatch. _submit_chip is the only place that sees both the dispatch directory and the callable being dispatched, so it now stamps a dispatch_program.json marker there; the offline post-pass reads it back and resolves names from that program's kernel_config.py alone, keeping --func-names and the -k fallback in agreement. The marker goes through the filesystem so the two halves stay independent of where the runtime places the L3 orchestrator, and both swimlane passes rewrite it identically.

  • A dispatch whose program cannot be resolved (multi-program build, no marker) is converted with anonymous labels instead of guessed ones — a plausible wrong name reads as a real measurement. That path also drops a stale sibling name_map.json the converter would otherwise auto-discover.
  • _generate_swimlane omits -k when the config is absent rather than handing the converter a path it rejects (it errors out on a missing -k, losing the swimlane entirely).
  • Consolidates the two duplicated orch._dfx_dispatch_idx = {} reset sites into _reset_dfx_dispatch_state, which publishes the callable -> program names alongside the per-card dispatch counter.

Testing

  • All tests pass — tests/ut 7981 passed / 2 skipped; tests/ut/runtime + tests/lint green after rebase; pre-commit (ruff, pyright, markdownlint, en-zh parity) clean
  • Code review completed
  • Documentation updated — docs/{en,zh-cn}/dev/03-runtime-dfx.md: the marker in the L3 dispatch-dir layout, why names must be resolved per dispatch, and the new implementation-map rows

New coverage in tests/ut/runtime/test_distributed_worker.py and test_swimlane_two_pass.py:

  • the regression itself — two programs both numbering func_id from 0, asserting each dispatch's name_map.json and -k dir name its own program (today the two maps are byte-identical)
  • the single-program fallback for an unmarked dispatch, and that a non-program subdir under next_levels/ does not hide it
  • the unresolvable case: no name map, no foreign -k, stale map dropped
  • _generate_swimlane passing / omitting -k by config presence

Both key cases were verified to be genuine discriminators: they fail against main and pass with the fix. The simpler_setup converter is mocked in tests (optional runtime dep), not vendored.

Related Issues

Fixes #2169

…2 program

Fixes hw-native-sys#2169

`_collect_l3_swimlane` merged every `next_levels/*/kernel_config.py` into one
flat `func_id -> name` table and wrote it into every `rank*/d{k}` dir. But
`func_id` is a per-L2-program namespace — each program numbers its kernels from
0 — so the alphabetically-later program won ids 0..N and every other dispatch
was rendered with its names. On a two-program L3 kernel, `lm_head_dispatch_wait`
(a cross-card spin-wait) printed as `mtp_projection_norm`: a 24 ms barrier read
as a 24 ms RMS-norm kernel, in the console table and in the Perfetto trace
alike. The converter's `-k` fallback had the same flaw (`work_dir` was always
`chip_dirs[0]`).

Nothing on disk recorded which program produced which dispatch. `_submit_chip`
is the only place that sees both the dispatch directory and the callable being
dispatched, so it now stamps a `dispatch_program.json` marker there; the offline
post-pass reads it back and resolves names from that program's `kernel_config.py`
alone, keeping the name map and the `-k` fallback in agreement. The marker goes
through the filesystem so the two halves stay independent of where the runtime
places the L3 orchestrator, and both swimlane passes rewrite it identically.

A dispatch whose program cannot be resolved (multi-program build, no marker) is
converted with anonymous labels instead of guessed ones — a plausible wrong name
reads as a real measurement. That path also drops a stale sibling `name_map.json`
the converter would otherwise auto-discover, and `_generate_swimlane` now omits
`-k` when the config is absent rather than handing the converter a path it
rejects.

Also consolidates the two duplicated `orch._dfx_dispatch_idx = {}` reset sites
into `_reset_dfx_dispatch_state`, which publishes the callable -> program names
alongside the per-card dispatch counter.
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b8ef726-5d68-45c6-b3c4-3958aa6c2cd6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

L3 distributed DFX processing now records each dispatch’s originating program, resolves kernel names using that program’s kernel configuration, anonymizes unresolved dispatches, and conditionally passes kernel configuration to the swimlane converter. Tests and English/Chinese documentation cover the updated behavior.

Changes

L3 swimlane labeling

Layer / File(s) Summary
Record dispatch program metadata
python/pypto/runtime/distributed_runner.py, tests/ut/runtime/test_distributed_worker.py
Dispatch state maps submitted chip callables to programs and writes dispatch_program.json beside each dispatch’s DFX records, including persistent-run resets.
Resolve names per dispatch
python/pypto/runtime/distributed_runner.py, tests/ut/runtime/test_distributed_worker.py
L3 collection reads each marker, generates program-scoped name_map.json files, removes stale maps, and uses anonymous labels when a program cannot be resolved.
Align converter contract and coverage
python/pypto/runtime/runner.py, tests/ut/runtime/test_swimlane_two_pass.py, docs/en/dev/03-runtime-dfx.md, docs/zh-cn/dev/03-runtime-dfx.md
The converter receives -k only when kernel_config.py exists; tests and runtime DFX documentation describe the updated output and resolution rules.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DistributedRunner
  participant DispatchDirectory
  participant SwimlaneCollector
  participant SwimlaneConverter
  DistributedRunner->>DispatchDirectory: write dispatch_program.json
  SwimlaneCollector->>DispatchDirectory: read dispatch_program.json
  SwimlaneCollector->>SwimlaneCollector: create program-scoped name_map.json
  SwimlaneCollector->>SwimlaneConverter: convert records with selected kernel names
Loading

Possibly related PRs

Poem

A bunny found names in each dispatch den,
No merged-up labels confused them again.
JSON marks the path, maps bloom bright,
Missing configs fade to anonymous white.
“Hop!” said the rabbit, “the lanes now sing true!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main fix: scoping L3 swimlane name maps per dispatch L2 program.
Description check ✅ Passed The description accurately describes the bug, the fix, and the related test and documentation updates.
Linked Issues check ✅ Passed The changes address #2169 by resolving names per dispatch program, preserving single-program behavior, and handling the -k fallback.
Out of Scope Changes check ✅ Passed The docs, tests, and runner adjustment are all directly tied to the reported swimlane naming bug.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@python/pypto/runtime/distributed_runner.py`:
- Around line 803-832: Update the resolved-program branch around
_write_dispatch_name_map so that when it returns None, all stale name_map*.json
files in disp_dir are removed before _generate_swimlane runs, preserving
anonymous-label behavior. Keep the existing mapped-name path unchanged when a
valid map is produced, and add a regression test alongside
test_unresolvable_dispatch_drops_a_stale_name_map for a resolved program with an
empty or unloadable kernel table.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cb293613-9730-4d82-a7bc-835af9bc28f2

📥 Commits

Reviewing files that changed from the base of the PR and between 340d6c5 and bf87e55.

📒 Files selected for processing (6)
  • docs/en/dev/03-runtime-dfx.md
  • docs/zh-cn/dev/03-runtime-dfx.md
  • python/pypto/runtime/distributed_runner.py
  • python/pypto/runtime/runner.py
  • tests/ut/runtime/test_distributed_worker.py
  • tests/ut/runtime/test_swimlane_two_pass.py

Comment thread python/pypto/runtime/distributed_runner.py
- Hoist the stale ``name_map*.json`` cleanup out of the unresolvable branch so
  it covers every dispatch: a resolved program whose ``kernel_config.py`` names
  no kernels also writes no map, and an earlier run's map must not be picked up
  in its place. The invariant is now unconditional — a dispatch only ever holds
  a name map the current run wrote — instead of depending on the converter's
  internal precedence between ``--func-names``, ``-k`` and sibling discovery.
- Add a regression test for the resolved-but-empty-table case.
@lyfne123
lyfne123 merged commit 442f511 into hw-native-sys:main Jul 29, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

[Bug] L3 swimlane name_map merges func_id namespaces across L2 programs, mislabeling the second dispatch

2 participants