Skip to content

[RFC] feat(distributed): ergonomic pld.* collective wrappers (auto-managed signals) - #2275

Open
georgebisbas wants to merge 1 commit into
hw-native-sys:mainfrom
georgebisbas:feat/ergonomic-collective-api
Open

[RFC] feat(distributed): ergonomic pld.* collective wrappers (auto-managed signals)#2275
georgebisbas wants to merge 1 commit into
hw-native-sys:mainfrom
georgebisbas:feat/ergonomic-collective-api

Conversation

@georgebisbas

@georgebisbas georgebisbas commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

[RFC] feat(distributed): ergonomic pld.* collective wrappers — auto-managed signals

Status: RFC — sim-verified; NPU verification pending.
Tracks: #1189 (Scheme A, orchestration-level collectives).
Branch: feat/ergonomic-collective-api — 6 commits, rebased on origin/main with #2175 (self-clearing credit-barrier protocol, e10ce252).


Summary

This PR adds ergonomic short forms over the existing HOST pld.tensor.* collectives that auto-allocate a fresh, correctly-shaped INT32 signal window per call, removing the per-call alloc_window_buffer + window signal boilerplate. The wrapper then delegates to the exact same pld.tensor.* HOST builtin — same lowering, same semantics, same goldens.

data = pld.all_reduce(data, op=pld.ReduceOp.Sum)           # mesh: signal host-synthesized
data = pld.all_reduce(data, mode="ring", nranks=2)         # ring: [2*(NR-1)+1, NR] signal auto
data = pld.all_gather(local, target)
data = pld.reduce_scatter(target, op=pld.ReduceOp.Sum)
data = pld.broadcast(target, root=0)
data = pld.all_to_all(input, target)
data = pld.all_to_all_v(input, target, send_counts, recv_counts)
sig  = pld.barrier(sig)                                     # explicit covered signal (constraint below)

Why this matters

The host-collective infrastructure landed across #1798 / #1829 / #1997 / #2094, but every call still required hand-rolled signal plumbing:

# Before (per call site): shape, dtype, freshness all the caller's job
sig = pld.window(
    pld.alloc_window_buffer([pld.world_size(), 1], dtype=pl.INT32),
    [pld.world_size(), 1], dtype=pl.INT32,
)
target = pld.tensor.allgather(local, target, sig)   # must be a FRESH signal per call
# Now
target = pld.all_gather(local, target)

This PR is the user-facing layer of #1189's Scheme A: it turns raw, powerful builtins into something distributed kernels can actually call — the foundation the ergonomic roadmap builds on.


What this PR offers — in detail

1. The 7 wrappers (python/pypto/language/distributed/op/collective_api.py)

Wrapper Signal handling
pld.all_reduce(target, *, op, mode="mesh"|"ring", nranks) mesh: none (compiler synthesizes [world_size, 1]); ring: auto [2*(NR-1)+1, NR] (requires static nranks)
pld.all_gather(local, target) auto [world_size(), 1]
pld.reduce_scatter(target, *, op) auto [world_size()] (rank-1, per builtin requirement)
pld.broadcast(target, *, root) auto [world_size()] (rank-1)
pld.all_to_all(input, target) auto [world_size(), 1]
pld.all_to_all_v(input, target, send_counts, recv_counts) auto [world_size(), 1]
pld.barrier(signal) explicit, comm-domain-covered signal (see Constraints)

All signal shapes match the corresponding HOST builtin's requirement exactly, encoded in code so users cannot get them wrong.

2. Auto-managed, fresh signals — correctness by construction

  • Each call allocates a fresh __auto_<op>_<n> INT32 window; no stale/reused-buffer bugs, no collisions.
  • fix(ir): make composite collective barrier signals reusable #2175 context (merged, rebased onto): the self-clearing credit-barrier protocol makes signals reusable across calls. The wrappers keep fresh-per-call as the simplest safe default — documented, still correct under the new protocol.

3. Early validation — errors where you typed them, not deep in the compiler

  • Static (pyright): pld.all_reduce is Literal["mesh","ring"] + @overloadmode="tree" and mode="ring" without nranks are type errors.
  • Runtime (context-rich ValueError): invalid mode; nranks required for ring / rejected for mesh; ring is ReduceOp.Sum + FP32 only; reduce_scatter is ReduceOp.Sum only.

4. Exports & discoverability

Wired through op/unified_ops.pyop/__init__.pydistributed/__init__.py, so pld.all_reduce(...) resolves inside @pl.program host bodies (parser expansion to pld.tensor.* verified).

5. Documentation (EN + ZH, parity-checked)

docs/{en,zh}/dev/distributed_ops.md: API table, a worked "publish → collective → consume" example, mesh-vs-ring guidance, and an honest constraints list.


Constraints / limitations (documented, not hidden)

  • pld.barrier requires an explicit, comm-domain-covered signal — a barrier has no data buffer from which MaterializeCommDomainScopes can inherit coverage. Zero-arg pld.barrier() lands with the coverage fallback (feat(distributed): add HOST-orchestrated builtin.tensor.all_to_all_v #2243).
  • Loops on the HOST rail: the wrappers target HOST builtins; HOST allreduce is not self-clearing, so SynthesizeAllReduceSignals still rejects an allreduce inside for/while loops. fix(ir): make composite collective barrier signals reusable #2175's loop-safety applies to the InCore composite rail only (not targeted here).
  • pld.all_to_all_v HOST rail is gated on feat(distributed): add HOST-orchestrated builtin.tensor.all_to_all_v #2243 — wrapper delegation is unit-tested; the HOST path is rejected until it merges.
  • Signal-bearing as_python() round-trip (IR print→reparse) is currently broken: the Python printer emits the auto signal inline (window(alloc_window_buffer(...))) and drops name=, which parse_program rejects. Captured as a strict-xfail UT + KNOWN_ISSUES; the fix is a python_printer hoisting change (own PR). Does not affect compile/run.

Testing (all green on the rebased base)

  • UT tests/ut/language/test_collective_api.py: 15 passed + 1 xfail — signal shape/name generation, fresh-per-call uniqueness, kwarg passthrough, parser resolution, all validation guards, and the documented printer-gap xfail.
  • ST tests/st/distributed/test_l3_ergonomic_api.py: 5 passed on a2a3sim — mesh AR, ring AR, broadcast, all_gather, barrier (cross-rank goldens).
  • Sibling regression test_l3_host_tensor_allreduce.py: 11 passed / 1 skipped.
  • pre-commit all hooks clean (incl. pyright, EN/ZH parity). clang-tidy: N/A (Python-only change).

Design decisions

  1. Pure Python — zero C++/IR/codegen surface; composes with existing host builtins.
  2. No auto-mode — user still picks mesh vs ring explicitly; a future mode="auto" will automate selection.
  3. HOST-orchestration only — the wrappers hide the signal; the data-window + publish/dispatch choreography stays explicit (documented).
  4. Fresh-per-call signals — safe baseline; fix(ir): make composite collective barrier signals reusable #2175 makes signal pooling possible to add later.

Follow-ups (tracked, non-blocking)

  • Typing / validation / docs — this PR already includes static typing, early validation, and docs; the signal round-trip printer fix is tracked separately.
  • Window-less host collectivepld.all_reduce(plain_tensor) to hide the data side too.
  • Future workmode="auto" default, async collectives, group= parameter, FP16/FP8 dtypes.

How to review / verify

  1. Read collective_api.py + tests/ut/language/test_collective_api.py (signals, validation, parser resolution).
  2. Read tests/st/distributed/test_l3_ergonomic_api.py (end-to-end goldens).
  3. Run the sim gate (UT + ST on a2a3sim).
  4. Developer gate (not yet run): NPU ST P=2 / P=4, then merge.

@coderabbitai

coderabbitai Bot commented Aug 4, 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: 6ce5a3aa-0368-43f0-91ff-32be4072a5aa

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

This PR adds HOST ergonomic collective wrappers with automatic signal allocation, public exports, documentation, unit tests, and distributed end-to-end tests for all-reduce, broadcast, all-gather, and barrier.

Changes

Collective API

Layer / File(s) Summary
Collective wrapper implementation
python/pypto/language/distributed/op/collective_api.py
Adds wrappers for collective operations. The wrappers allocate fresh INT32 signals where required and delegate to HOST tensor collectives.
Public namespace exports
python/pypto/language/distributed/__init__.py, python/pypto/language/distributed/op/__init__.py, python/pypto/language/distributed/op/unified_ops.py
Re-exports the new collective operations through distributed namespaces.
Wrapper and parser validation
tests/ut/language/test_collective_api.py
Tests signal shapes, allocation uniqueness, modes, validation errors, delegation, and parser behavior.
End-to-end distributed execution
tests/st/distributed/test_l3_ergonomic_api.py
Tests mesh and ring all-reduce, broadcast, all-gather, and barrier programs across available devices.
Collective API documentation
docs/en/dev/distributed_ops.md, docs/zh/dev/distributed_ops.md
Documents wrapper constraints, signal rules, examples, and mesh versus ring all-reduce behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant HostOrchestration
  participant CollectiveAPI as collective_api.all_reduce
  participant SignalWindow
  participant TensorCollective as HOST tensor allreduce
  HostOrchestration->>CollectiveAPI: invoke all_reduce(target, mode)
  CollectiveAPI->>SignalWindow: allocate fresh INT32 signal
  CollectiveAPI->>TensorCollective: delegate target and parameters
  TensorCollective-->>HostOrchestration: return distributed target
Loading

Possibly related issues

Possibly related PRs

Poem

A rabbit hops through signals bright,
Fresh buffers bloom for each invite.
Mesh and ring now share the load,
HOST collectives guide the road.
Gather, scatter, barrier too—
Binky cheers the API crew!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: ergonomic distributed collective wrappers with automatic signal management.
Description check ✅ Passed The description directly explains the wrappers, validation, exports, documentation, testing, limitations, and follow-up work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

@georgebisbas
georgebisbas marked this pull request as ready for review August 4, 2026 07:27

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9c2c42947

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Returns:
The ``target`` :class:`pld.DistributedTensor` (window-as-result).
"""
signal = _fresh_signal("all_to_all_v", [world_size(), 1])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Require static NR for all_to_all_v signals

For any call to the new pld.all_to_all_v(...) wrapper, this line builds the hidden signal as [pld.world_size(), 1], but the underlying pld.tensor.all_to_all_v type deducer requires the signal's first dimension to be a compile-time ConstInt so it can derive MAX_RECV = target.shape[0] // NR. That means the advertised short form raises during IR construction before it can reach the documented host rejection path; either require a static nranks here (like ring all-reduce) or avoid exposing this wrapper until a dynamic/world-size signal is supported.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in aec3b80: pld.all_to_all_v now requires a positive static nranks (mirroring ring allreduce) and builds the signal as [nranks, 1]; a dynamic world_size() or non-positive value raises a context-rich ValueError at the wrapper call. Added delegation + guard unit tests. Thanks — this was a real construction-time failure.

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/en/dev/distributed_ops.md (1)

182-186: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

EN and ZH docs list different ops for the credit-barrier protocol. The English doc names all_to_all_v as one of the collectives synchronized by the self-clearing credit barrier; the Chinese doc's equivalent sentence omits it. Align both lists to name the same set of ops.

  • docs/en/dev/distributed_ops.md#L182-L186: authoritative list; keep all_to_all_v here and confirm it is intentional.
  • docs/zh/dev/distributed_ops.md#L164-L165: add all_to_all_v to match the English list.

As per coding guidelines, "English documentation in docs/en/dev/ is authoritative and corresponding Chinese documentation in docs/zh/dev/ must remain aligned."

🤖 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 `@docs/en/dev/distributed_ops.md` around lines 182 - 186, Keep all_to_all_v in
the authoritative collective list in docs/en/dev/distributed_ops.md at lines
182-186, confirming it remains intentional; update the corresponding list in
docs/zh/dev/distributed_ops.md at lines 164-165 to add all_to_all_v so both
documentation sets name the same credit-barrier operations.

Source: Coding guidelines

🧹 Nitpick comments (2)
tests/ut/language/test_collective_api.py (1)

125-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct all_to_all_v coverage.

This test module does not call pld.all_to_all_v. Add a delegation test that checks the argument order input, target, signal, send_counts, recv_counts, plus the generated INT32 [world_size(), 1] signal.

Add this routine contract test in this module. As per coding guidelines, use unit tests in tests/ut/ for routine testing.

🤖 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 `@tests/ut/language/test_collective_api.py` around lines 125 - 142, Add a unit
test in this module that calls pld.all_to_all_v and verifies delegation to the
expected IR operation, argument order input, target, signal, send_counts,
recv_counts, and the generated signal’s INT32 [world_size(), 1] shape. Follow
the existing collective API test patterns and keep the coverage focused on this
routine contract.

Source: Coding guidelines

tests/st/distributed/test_l3_ergonomic_api.py (1)

240-244: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate all all-gather rows.

consume_step loads only row 0. The expected value at Line 376 checks only rank 0's chunk on each rank. An implementation that broadcasts rank 0 or leaves later rows invalid passes this test. Copy the complete [NR, SIZE] target into each rank output and compare all rank-indexed input chunks.

Proposed coverage change
     def consume_step(
         self,
         target: pld.DistributedTensor[[NR, SIZE], pl.FP32],
-        out: pl.Out[pl.Tensor[[1, SIZE], pl.FP32]],
-    ) -> pl.Tensor[[1, SIZE], pl.FP32]:
-        return pl.store(pl.load(target, [0, 0], [1, SIZE]), [0, 0], out)
+        out: pl.Out[pl.Tensor[[NR, SIZE], pl.FP32]],
+    ) -> pl.Tensor[[NR, SIZE], pl.FP32]:
+        return pl.store(pl.load(target, [0, 0], [NR, SIZE]), [0, 0], out)
@@
     def consume_orch(
         self,
         target: pld.DistributedTensor[[NR, SIZE], pl.FP32],
-        out: pl.Out[pl.Tensor[[1, SIZE], pl.FP32]],
-    ) -> pl.Tensor[[1, SIZE], pl.FP32]:
+        out: pl.Out[pl.Tensor[[NR, SIZE], pl.FP32]],
+    ) -> pl.Tensor[[NR, SIZE], pl.FP32]:
@@
-        outputs: pl.Out[pl.Tensor[[NR, 1, SIZE], pl.FP32]],
-    ) -> pl.Tensor[[NR, 1, SIZE], pl.FP32]:
+        outputs: pl.Out[pl.Tensor[[NR, NR, SIZE], pl.FP32]],
+    ) -> pl.Tensor[[NR, NR, SIZE], pl.FP32]:
@@
-        outputs = torch.zeros_like(inputs)
+        outputs = torch.zeros((NR, NR, SIZE), dtype=inputs.dtype, device=inputs.device)
@@
-        expected = torch.stack([inputs[0]] * NR)
+        expected = torch.stack([inputs[:, 0, :]] * NR)
🤖 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 `@tests/st/distributed/test_l3_ergonomic_api.py` around lines 240 - 244, Update
consume_step to load and store the complete [NR, SIZE] gathered target into out
rather than only row 0. Extend the assertions around the existing expected-value
check to validate every rank-indexed input chunk, ensuring later all-gather rows
are compared on each rank.
🤖 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/language/distributed/op/collective_api.py`:
- Around line 12-15: Update the module documentation describing signal
allocation to explicitly state that all_reduce with mode="mesh" uses a
compiler-synthesized signal and barrier requires a caller-provided signal, while
preserving the existing fresh-signal behavior for other wrappers.
- Around line 67-69: Update the printer/serialization path for
_fresh_signal-generated buffers so alloc_window_buffer() is emitted as a named
assignment before the window() call, preserving a parser-visible binding that
parse_program() can consume. Ensure signal-bearing wrappers round-trip through
as_python() and make the strict collective API xfail pass.
- Around line 123-141: Update the nranks validation in the mode == "ring" branch
to require a static integer greater than zero, rejecting zero and negative
values before calculating the signal shape. Preserve the existing bool/type
validation and error handling, and add regression coverage for both non-positive
inputs.

---

Outside diff comments:
In `@docs/en/dev/distributed_ops.md`:
- Around line 182-186: Keep all_to_all_v in the authoritative collective list in
docs/en/dev/distributed_ops.md at lines 182-186, confirming it remains
intentional; update the corresponding list in docs/zh/dev/distributed_ops.md at
lines 164-165 to add all_to_all_v so both documentation sets name the same
credit-barrier operations.

---

Nitpick comments:
In `@tests/st/distributed/test_l3_ergonomic_api.py`:
- Around line 240-244: Update consume_step to load and store the complete [NR,
SIZE] gathered target into out rather than only row 0. Extend the assertions
around the existing expected-value check to validate every rank-indexed input
chunk, ensuring later all-gather rows are compared on each rank.

In `@tests/ut/language/test_collective_api.py`:
- Around line 125-142: Add a unit test in this module that calls
pld.all_to_all_v and verifies delegation to the expected IR operation, argument
order input, target, signal, send_counts, recv_counts, and the generated
signal’s INT32 [world_size(), 1] shape. Follow the existing collective API test
patterns and keep the coverage focused on this routine contract.
🪄 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: a1458aa0-907e-4e89-95a1-21cb9bd8eb1a

📥 Commits

Reviewing files that changed from the base of the PR and between a47d300 and a9c2c42.

📒 Files selected for processing (8)
  • docs/en/dev/distributed_ops.md
  • docs/zh/dev/distributed_ops.md
  • python/pypto/language/distributed/__init__.py
  • python/pypto/language/distributed/op/__init__.py
  • python/pypto/language/distributed/op/collective_api.py
  • python/pypto/language/distributed/op/unified_ops.py
  • tests/st/distributed/test_l3_ergonomic_api.py
  • tests/ut/language/test_collective_api.py

Comment thread python/pypto/language/distributed/op/collective_api.py Outdated
Comment on lines +67 to +69
name = f"__auto_{op_name}_{next(_SIGNAL_COUNTER)}"
buf = _tensor.alloc_window_buffer(shape, dtype=DataType.INT32, name=name)
return _tensor.window(buf, shape, dtype=DataType.INT32)

@coderabbitai coderabbitai Bot Aug 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make generated signal allocations round-trip.

_fresh_signal() embeds alloc_window_buffer() directly in window(). The printer emits that allocation inline, but parse_program() requires a named simple assignment. The strict xfail in tests/ut/language/test_collective_api.py, Lines 282-297, proves that signal-bearing wrappers cannot round-trip through as_python().

Hoist generated allocations into named statements in the printer or preserve an equivalent parser-visible binding. Make the strict xfail pass before exporting this API.

🤖 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 `@python/pypto/language/distributed/op/collective_api.py` around lines 67 - 69,
Update the printer/serialization path for _fresh_signal-generated buffers so
alloc_window_buffer() is emitted as a named assignment before the window() call,
preserving a parser-visible binding that parse_program() can consume. Ensure
signal-bearing wrappers round-trip through as_python() and make the strict
collective API xfail pass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed this is a real gap. It is the python_printer not hoisting generated alloc_window_buffer into a named assignment (and dropping name=), which parse_program requires. Tracked as a strict-xfail UT (proves the gap) + KNOWN_ISSUES, and scoped as a separate printer fix rather than expanding this Python-only PR into a C++ printer change — it does not affect compile/run. I will open a follow-up for the printer hoist.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@georgebisbas, acknowledged. The finding remains valid, but the printer fix is reasonably out of scope for this PR.

The strict expected-failure test and KNOWN_ISSUES document the current limitation. Please link the follow-up issue here when available. If you want, I can create the GitHub issue and assign it to you.

🐇 ✅


✏️ Learnings added
Learnt from: georgebisbas
Repo: hw-native-sys/pypto PR: 2275
File: python/pypto/language/distributed/op/collective_api.py:74-76
Timestamp: 2026-08-04T08:08:02.027Z
Learning: In `python/pypto/language/distributed/op/collective_api.py`, generated signal buffers from `_fresh_signal()` compile and run correctly, but `as_python()` does not round-trip them through `parse_program()`. The C++ `python_printer` emits `alloc_window_buffer()` inline and drops its `name=` argument, while `parse_program()` requires the allocation in a named simple assignment. The repository tracks this limitation with a strict expected-failure unit test and `KNOWN_ISSUES`; the printer hoist fix is intentionally scoped to a separate follow-up.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Comment thread python/pypto/language/distributed/op/collective_api.py
@georgebisbas

Copy link
Copy Markdown
Contributor Author

Addressed the AI review feedback in aec3b805.

Codex (P2): all_to_all_v now requires a positive static nranks (signal [nranks, 1]); a dynamic world_size() signal was rejected at IR construction — fixed + delegation/guard unit tests.

CodeRabbit:

  • (Major, docs parity) added all_to_all_v to the ZH credit-barrier collective list (matches EN).
  • (Minor) ring all_reduce nranks <= 0 — now rejected via a shared _is_static_positive_int TypeGuard + regression test.
  • (Trivial) module docstring — states the mesh (compiler-synthesized) and barrier (caller-provided) signal exceptions.
  • (Trivial) missing all_to_all_v UT — added delegation + non-positive-nranks tests.
  • (Trivial) all_gather ST validated only row 0 — now copies/validates the full [NR, SIZE] gathered target.

CodeRabbit (Major, printer round-trip): real gap — python_printer doesn't hoist generated alloc_window_buffer into a named assignment (and drops name=), which parse_program requires. Tracked as a strict-xfail UT + KNOWN_ISSUES and scoped as a separate printer fix (not in this Python-only PR; does not affect compile/run). Follow-up to be opened.

Verified: UT 18 passed + 1 xfail, ST 5 passed on a2a3sim, pre-commit clean (incl. pyright).

Convenience wrappers over the host collective builtins that auto-manage
signal windows, replacing the manual alloc_window_buffer + window +
signal boilerplate with a single call.

- all_reduce(target, op=Sum, mode="mesh"|"ring", nranks): mesh uses a
  compiler-synthesized signal (no window); ring validates positive static
  nranks and rejects non-Sum ops / non-FP32 inputs, allocating a fresh
  INT32 signal window.
- all_gather / reduce_scatter / broadcast / all_to_all / all_to_all_v:
  allocate a fresh INT32 signal window sized from world_size()/nranks;
  all_to_all_v requires a positive static nranks (signal [nranks, 1]).
- barrier(signal): caller-provided, comm-domain-covered signal.
- Each wrapper emits an __auto_<op>_<n> named window; self-clearing
  credit-barrier signals (merged hw-native-sys#2175) make repeated calls loop-safe.
- Literal/overload typing on all_reduce; context-rich ValueError guards
  (mesh nranks, ring nranks<=0, non-static all_to_all_v nranks).

Tests: tests/ut/language/test_collective_api.py; ST
tests/st/distributed/test_l3_ergonomic_api.py (a2a3sim). Docs: EN/ZH
docs/en|zh/dev/distributed_ops.md "Ergonomic collective API".
@georgebisbas
georgebisbas force-pushed the feat/ergonomic-collective-api branch from 7ec7dfc to c2463d2 Compare August 5, 2026 07:01
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.

1 participant