Skip to content

[Feature] Lift the HOST-rail in-loop pld.tensor.allreduce restriction via shared-signal synthesis #2310

Description

@georgebisbas

Summary

SynthesizeAllReduceSignals currently rejects pld.tensor.allreduce inside a for/while loop (CheckAllReduceCall, repeating_scope_depth_ == 0). With the host collective builtin kernels now self-clearing (#2279 — every kernel restores its signal cells to zero after each call), the restriction is no longer justified by the barrier protocol: it exists only because the pass mints a fresh synthesized signal allocation per call, which cannot be placed per dynamic iteration. This issue tracks lifting the restriction — a single per-host_orch shared signal plus in-loop support — originally deferred from #2279 as a follow-up.

Motivation / Use Case

Proposed API / Behavior

for step in pl.range(num_steps):
    data = pld.tensor.allreduce(data, signal, op=pld.ReduceOp.Sum)  # explicit signal — allowed

and, once shared-signal synthesis lands, the fully ergonomic form:

for step in pl.range(num_steps):
    data = pld.tensor.allreduce(data, op=pld.ReduceOp.Sum)  # synthesized signal, hoisted to host_orch entry

Pass change in SynthesizeAllReduceSignals:

  • Emit one synthesized signal per host_orch function, allocated before the body exactly as MakeSignalBinding does today (world_size * 4 bytes → [world_size, 1] INT32 window), and pass it to every implicit-signal allreduce.
  • Delete the repeating_scope_depth_ == 0 check (explicit signals pass through unchanged).
  • Keep the mesh [NR, 1] vs ring [2*(NR-1)+1, NR] signal-shape guard (ValidateMeshSignalShape).
  • Update the pass doc and the debugging "rejected inside loop" row (en/zh), and add loop + implicit-signal STs (convert the existing test_host_tensor_allreduce_signal_reuse to a live pl.range loop).

Alternatives Considered

  • Keep the restriction and require users to manage signals manually: rejected — signal-window management is the most error-prone part of the collective API and the HOST rail is the only rail still loop-restricted.
  • Hoist only the explicit-signal case (move the check after the arg-count branch): a reasonable minimal first step, but the synthesized path needs the shared-signal synthesis to be fully ergonomic, so the shared-signal approach is preferred.

Additional Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions