Skip to content

docs(user): add the Distributed Programming chapter - #2219

Merged
YunjiQin merged 6 commits into
hw-native-sys:mainfrom
georgebisbas:docs/pr2-distributed-chapter
Aug 3, 2026
Merged

docs(user): add the Distributed Programming chapter#2219
YunjiQin merged 6 commits into
hw-native-sys:mainfrom
georgebisbas:docs/pr2-distributed-chapter

Conversation

@georgebisbas

Copy link
Copy Markdown
Contributor

Summary

Split out of #2162 (which is being broken into smaller PRs — see that
PR's description). Adds docs/en/user/distributed/ (+ full docs/zh/
mirror) and wires it into mkdocs.yml nav.

  • index.md — PyPTO's distributed model in one page: symmetric
    memory + signals, comm domains, and how PyPTO's simplified L2
    (single-chip) / L3 (cross-rank) vocabulary relates to the simpler
    runtime's own finer L0–L6 hierarchy.
  • 00-model.md — A minimal end-to-end HelloAllReduce walkthrough:
    host orchestrator, per-chip orchestration function, InCore kernel,
    window buffers, and the launch model (a distributed program launches
    as plain python script.py — PyPTO forks the per-chip workers
    internally).
  • 01-collectives.md — Every collective (allreduce, barrier,
    broadcast, allgather, reduce_scatter, all_to_all), the three
    execution paths (InCore hand-rolled, InCore composite, HOST builtin)
    and when to reach for each, supported ReduceOp/dtype per operation,
    worked examples.
  • 02-primitives.md — Lower-level building blocks: notify/wait
    handshakes, window buffer allocation, tile-level RMA, one-sided
    put/get with chunking/pipelining constraints, composing
    primitives into a hand-rolled collective.
  • 03-execution.mdDistributedWorker lifecycle,
    DistributedConfig, dispatch.
  • 04-debugging.md — Common failure modes with symptoms and fixes.

Note: this chapter cross-references a Performance chapter that is
being split out as a separate PR. Those specific links are omitted
here and will be added back once that PR (and this one) land — see
#2162 for the full picture of how the pieces fit together.

Verification

  • npx markdownlint-cli2 --config tests/lint/.markdownlint.yaml
  • python3 tests/lint/check_docs_en_zh_parity.py
  • python3 tests/lint/check_docs_nav.py
  • pre-commit run --all-files
  • mkdocs build --strict (clean, no broken links)

Split out of PR hw-native-sys#2162. Adds docs/en/user/distributed/ (+ zh mirror):
symmetric-memory-and-signals model, comm domains, the three collective
execution paths (InCore hand-rolled, InCore composite, HOST builtin),
every collective with worked examples, primitives (notify/wait, window
buffers, put/get, tile RMA), DistributedWorker lifecycle, and a
debugging/failure-mode reference. Wires the chapter into mkdocs.yml nav.

Cross-references to the not-yet-landed Performance chapter are
deferred to the PR that lands it.
@coderabbitai

coderabbitai Bot commented Jul 30, 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: fcdcce63-7c28-461c-b5fa-f2613088467a

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

Adds bilingual documentation for PyPTO’s distributed programming model, primitives, collectives, execution runtime, and debugging workflow. The English distributed pages are added to MkDocs navigation.

Changes

Distributed documentation

Layer / File(s) Summary
Model quickstart and navigation
docs/en/user/distributed/00-model.md, docs/zh/user/distributed/00-model.md, docs/en/user/distributed/index.md, docs/zh/user/distributed/index.md, mkdocs.yml
Adds the distributed model overview, 2-rank AllReduce example, terminology, execution structure, cross-links, and navigation entries.
Primitive reference
docs/en/user/distributed/02-primitives.md, docs/zh/user/distributed/02-primitives.md
Documents signals, window buffers, RMA, put/get transfers, custom collectives, and namespace mappings.
Collective reference
docs/en/user/distributed/01-collectives.md, docs/zh/user/distributed/01-collectives.md
Documents six built-in collectives, buffer and signal constraints, modes, and InCore versus HOST execution paths.
Distributed execution
docs/en/user/distributed/03-execution.md, docs/zh/user/distributed/03-execution.md
Documents DistributedWorker, tensor allocation, persistent dispatch, CLI launching, and runtime configuration.
Debugging guidance
docs/en/user/distributed/04-debugging.md, docs/zh/user/distributed/04-debugging.md
Documents common failures, fatal configuration pitfalls, diagnostic flags, runtime markers, and DFX entry points.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Poem

A rabbit hops through ranks in flight,
Signals blink from left to right.
Buffers gather, kernels cheer,
Docs now guide each path clear.
“AllReduce!” sings the burrow bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a Distributed Programming documentation chapter.
Description check ✅ Passed The description clearly matches the changeset by outlining the new distributed docs, navigation updates, and verification steps.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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

🤖 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 `@docs/en/user/distributed/01-collectives.md`:
- Line 3: Update the introductory collective count in
docs/en/user/distributed/01-collectives.md:3-3 from five to six, and update the
corresponding Chinese count in docs/zh/user/distributed/01-collectives.md:3-3
from 五种 to 六种; no other content needs changing.
- Around line 10-11: Update the AllReduce description in
docs/en/user/distributed/01-collectives.md lines 10-11 to say every rank
receives the reduced result instead of the summed result; make the equivalent
sum-neutral wording change in docs/zh/user/distributed/01-collectives.md line 9,
preserving the existing meaning in both translations.

In `@docs/en/user/distributed/02-primitives.md`:
- Around line 153-167: Correct the barrier explanation around the AtomicAdd
example: clarify that offsets=[my_rank, 0] gives each [src, 0] cell a single
writer, so N ranks do not update one shared cell, and state that this
per-source-slot protocol can use Set instead. Do not retain the incorrect
shared-cell AtomicAdd rationale unless the example is changed to demonstrate a
true shared-slot N-to-1 barrier.

In `@docs/en/user/distributed/04-debugging.md`:
- Around line 51-58: Update the “Distributed DFX Entry Points” documentation to
state the actual output paths: L2 records at
dfx_outputs/l2_swimlane_records.json, scope statistics at
dfx_outputs/scope_stats/scope_stats.jsonl, and dependency data at
dfx_outputs/deps.json. Replace the vague “span-tree” reference and mention any
generated merged files where applicable.

In `@docs/zh/user/distributed/02-primitives.md`:
- Around line 28-36: 完善 docs/zh/user/distributed/02-primitives.md:28-36 的
alloc_window_buffer 文档,补充 shape+dtype 分配重载及 name 命名行为,并在 02-primitives.md:80-117
说明 RMA、Put/Get、分块与流水线规则及动态 shape 限制;完善
docs/zh/user/distributed/01-collectives.md:72-130,补充
Broadcast、AllGather、ReduceScatter、AllToAll 的前置条件和结果语义;完善
docs/zh/user/distributed/04-debugging.md:44-48,写明具体 DFX 产物路径及相关 flag 的行为。

In `@docs/zh/user/distributed/03-execution.md`:
- Around line 19-41: 补齐中文执行文档,使其与英文版本保持完整对应:在现有方法和 DeviceTensor 章节中恢复
StackedDeviceTensor、fork 前共享内存要求、多程序 worker 语义、基准测试环境变量,以及 init 和
release_inherited_host_tensor_refs 等方法细节。保持现有中文术语和示例风格,并确保生产工作流与英文文档涵盖相同内容。
- Around line 37-56: Update the Python examples in the distributed execution
documentation to import torch before any use of torch.float16, torch.randn,
torch.zeros_like, torch.zeros, or torch.float32, including the snippets around
compiled.prepare and the One-Shot example.
🪄 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: ea522659-4081-446c-8a09-a73af22877b4

📥 Commits

Reviewing files that changed from the base of the PR and between 84d11f1 and 250e60b.

📒 Files selected for processing (13)
  • docs/en/user/distributed/00-model.md
  • docs/en/user/distributed/01-collectives.md
  • docs/en/user/distributed/02-primitives.md
  • docs/en/user/distributed/03-execution.md
  • docs/en/user/distributed/04-debugging.md
  • docs/en/user/distributed/index.md
  • docs/zh/user/distributed/00-model.md
  • docs/zh/user/distributed/01-collectives.md
  • docs/zh/user/distributed/02-primitives.md
  • docs/zh/user/distributed/03-execution.md
  • docs/zh/user/distributed/04-debugging.md
  • docs/zh/user/distributed/index.md
  • mkdocs.yml

Comment thread docs/en/user/distributed/01-collectives.md Outdated
Comment thread docs/en/user/distributed/01-collectives.md Outdated
Comment thread docs/en/user/distributed/02-primitives.md Outdated
Comment thread docs/en/user/distributed/04-debugging.md Outdated
Comment thread docs/zh/user/distributed/02-primitives.md Outdated
Comment thread docs/zh/user/distributed/03-execution.md
Comment thread docs/zh/user/distributed/03-execution.md Outdated

@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: 250e60b104

ℹ️ 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".

Comment thread docs/en/user/distributed/02-primitives.md Outdated
Comment thread docs/en/user/distributed/02-primitives.md Outdated
Comment thread docs/en/user/distributed/01-collectives.md Outdated
- 01-collectives.md (en+zh): "five" -> "six" collectives; AllReduce
  description said "summed result" but the op supports Sum/Max/Min/Prod
  -> "reduced result"; qualified the "HOST builtins handle signal
  allocation automatically" claim as allreduce-only (the other five
  collectives always require a caller-allocated signal, verified
  against tensor_ops.py's overloads).
- 02-primitives.md (en): the "Barrier in Isolation" example claimed N
  ranks write the same signal cell and that's why AtomicAdd is needed;
  with offsets=[my_rank, 0] each cell actually has exactly one writer,
  so Set would work identically. Corrected the explanation. Also
  corrected the System Substrate table: only get_comm_ctx (and
  world_size) work in HOST orchestrator code -- rank/nranks/notify/wait
  have codegen support only in InCore kernel code (verified: no
  orchestration_codegen.cpp handler for any of the four).
- 04-debugging.md (en+zh): replaced vague "output in span-tree" wording
  with the real DFX artifact paths (dfx_outputs/l2_swimlane_records.json,
  dfx_outputs/deps.json), verified against docs/en/dev/03-runtime-dfx.md.
- 02-primitives.md (zh): added the missing alloc_window_buffer
  shape+dtype convenience overload row.
- 03-execution.md (zh): backfilled the sections missing versus the
  English page -- StackedDeviceTensor, multi-program worker semantics,
  release_inherited_host_tensor_refs, benchmark env vars paragraph --
  and added the missing `import torch` in code examples.
@YunjiQin

Copy link
Copy Markdown
Collaborator

Review

Docs-only PR, and the quality bar is high. I spot-checked the API claims against the implementation and the STs rather than reading them as prose, and most of them hold:

  • The quickstart's host-orchestrator shape (alloc_window_buffer outside the loop, window() inside, device=r, inputs[r]) matches tests/st/distributed/test_l3_notify_wait.py:107-112 and test_l3_window_slice_incore.py:97-101 exactly — these aren't invented snippets.
  • allreduce's FP16/FP32 hard check → src/ir/op/distributed/allreduce.cpp:89; reduce_scatter Sum-only → src/ir/op/distributed/collective.cpp:472-474; the "rank-1 [NR] or rank-2 [NR, 1]" signal rule for allgather/all_to_all → collective.cpp:303,405.
  • The exception types are precise: non-shared host tensor at dispatch → TypeError (distributed_runner.py:1999-2003); alloc_stacked_tensorValueError (distributed_runner.py:1733-1738); multi-program rt(*args)TypeError.
  • "Only allreduce may omit the signal" matches the overloads in tensor_ops.py:486-500.
  • nav wiring follows the existing convention (en-only entries + nav_translations; check_docs_nav.py only validates docs/en). Longest file is 213 lines, well inside the 500-line doc limit.

Findings below, roughly in priority order.


A. Link the collectives/primitives examples to the ST reference cases

The snippets in 01-collectives.md are illustrative sketches — local_input, chunk_j, chunk_for_dest, nranks, my_rank are all undefined, and host-only APIs (alloc_window_buffer, window) sit in the same block as InCore-only ones (nranks, rank), so no snippet is valid in either context as written.

Rather than inflating them into runnable programs, I'd say explicitly that they are sketches and link the runnable ST. The repo already has a clean 1:1 mapping onto the three execution paths your own table describes:

Collective InCore hand-rolled InCore composite HOST builtin
allreduce collectives/test_l3_allreduce.py collectives/test_l3_tensor_allreduce_intrinsic.py test_l3_host_tensor_allreduce.py
allreduce (ring) collectives/test_l3_allreduce_ring.py collectives/test_l3_tensor_allreduce_ring_intrinsic.py n/a (mesh only)
barrier collectives/test_l3_tensor_barrier_intrinsic.py test_l3_host_tensor_barrier.py
broadcast collectives/test_l3_broadcast.py collectives/test_l3_tensor_broadcast_intrinsic.py test_l3_host_tensor_broadcast.py
allgather collectives/test_l3_allgather.py collectives/test_l3_tensor_allgather_intrinsic.py test_l3_host_tensor_allgather.py
reduce_scatter collectives/test_l3_reduce_scatter.py collectives/test_l3_tensor_reduce_scatter_intrinsic.py test_l3_host_tensor_reduce_scatter.py
all_to_all collectives/test_l3_all_to_all.py collectives/test_l3_tensor_all_to_all_intrinsic.py test_l3_host_tensor_all_to_all.py

(all under tests/st/distributed/)

Same for 02-primitives.md: notify/wait → test_l3_notify_wait.py, put/get → test_l3_put.py / test_l3_get.py, remote_store → test_l3_remote_store.py.

This also closes the dangling "factory function pattern" reference in the Ring Mode section. collectives/test_l3_tensor_allreduce_ring_intrinsic.py:95-115 is that pattern: an outer function takes nr / size, derives total_rounds = 2 * (nr - 1), and defines the @pl.program inside its body so the [total_rounds, nr] signal shape is a compile-time constant. Right now the doc names the pattern but shows nothing.

B. python script.py has no referent

Both 00-model.md ("Launch Command") and 03-execution.md ("CLI Launch") end at python script.py, but script.py never appears anywhere. The quickstart gives a @pl.program class and stops — the driver (DistributedConfig(device_ids=[...])ir.compile(...)compiled(inputs, outputs)) is missing, so a reader has a program class and no idea what else belongs in the file.

Suggest adding the driver block right after the program definition in 00-model.md (the One-Shot example in 03-execution.md can be lifted verbatim), and turning 03-execution.md's CLI Launch section into a back-link so the two don't duplicate.

C. docs/zh/user/distributed/02-primitives.md diverges from the English

213 → 173 lines, and the cuts go past translation-tightening (project rule: English is ground truth, zh must match content):

  • The Put/Get signature tables are collapsed into two 2-line snippets, dropping dst_offsets / src_offsets / shape / atomic / chunk_rows / chunk_cols / pipeline, the Mutation column, and the asymmetry that dst must be window-bound while src may be a plain Tensor.
  • Namespace table is missing the pld.get_comm_ctx(dt) row; the "no short form" list is missing pld.put / pld.get.
  • The handshake's "Expected output for 2 ranks" paragraph is gone.
  • remote_load's "a 1-element misalignment causes silent corruption" warning is gone.
  • The AtomicAdd-vs-Set discussion in the barrier section is gone entirely (see D).

Related, on the English side: ## Put and Get doesn't name its namespace. put/get exist in both pld.tensor.* (user-facing) and pld.tile.* (pass-emitted, tile_ops.py:168), and the section sits directly under "Tile-Level RMA (pld.tile.*)", so it reads as pld.tile.put. The zh version actually gets this right. Suggest ## Put and Get (\pld.tensor.*`)`.

Worth noting check_docs_en_zh_parity.py compares path sets only, not content — CI will not catch this.

D. 00-model.md's AtomicAdd rationale is wrong and contradicts 02-primitives.md

The line-by-line table says:

AtomicAdd is correct here because N ranks write the same slot (it's a global barrier).

But the code uses offsets=[my_rank, 0] — each rank writes its own dedicated row in every peer's window, so each cell has exactly one writer. 02-primitives.md ("The Barrier in Isolation") states this correctly and even notes Set would work identically. Two pages, opposite explanations of the same snippet.

Both en and zh 00-model.md carry the wrong version, and zh/02-primitives.md dropped the corrective paragraph — so a Chinese reader only ever sees the wrong one.

E. prepare() signature is incomplete, plus a scoping question on the perf-relevant kwargs

The methods table lists compiled.prepare(config=None, callbacks=None), yet extra_compiled= is used 15 lines later on the same page. Actual signature (distributed_compiled_program.py:368-377):

prepare(config=None, *, extra_compiled=(), persistent=False,
        reset_persistent_windows=None, callbacks=None, sub_worker_overrides=None)

At minimum add extra_compiled and persistent.

Author's call — three of these matter a lot for multi-card performance. Whether they belong in this chapter or in the upcoming performance chapter is your judgement, but this chapter should at least point at them:

  1. What config actually does. The RunConfig passed to prepare() is used only for arena pre-warm and is not retained; the warm-up only saves the cold build of the first dispatch, and only when that first dispatch's size matches the pre-warm size. See docs/en/dev/05-runtime-ring-sizing.md § arena pre-warm. 03-execution.md currently doesn't mention config at all, which invites reading it as persistent worker configuration.
  2. persistent=True — retains CommDomain windows for the worker's lifetime instead of allocating/releasing them per dispatch (docs/en/dev/06-persistent-l3.md).
  3. reset_persistent_windows — pairs with persistent, decides whether retained windows are zeroed between requests; a direct correctness-vs-overhead trade-off.

Covering (2) also fixes the unqualified claim in 00-model.md § Window Buffer Lifetime — "there is no persistent IPC between orchestrator invocations" — which only holds on the default, non-persistent path.

F. Pick one way to obtain a DistributedWorker

03-execution.md says "Obtained via compiled.prepare()", then two examples use with DistributedWorker(compiled) as rt:. Both are legal (the constructor is public and exported from pypto.runtime), but the class docstring is explicit: "Obtain via DistributedCompiledProgram.prepare" (distributed_runner.py:1206). Suggest using compiled.prepare(...) throughout and, at most, mentioning direct construction once in the methods table as the equivalent lower-level entry point.

G. The device_ids vs device= pitfall is factually wrong

04-debugging.md says:

device_ids disagreeing with device=: DistributedConfig.device_ids must match the device IDs used in the orchestrator's per-rank dispatch. A mismatch — e.g. device_ids=[0, 1] but dispatching with device=r where r iterates over range(4) — causes undefined behaviour.

These are two different ID spaces:

  • device_ids are physical card IDs — in the STs they come straight from the --device option (tests/st/conftest.py:442-449), so [4, 5] is perfectly normal.
  • device=r is a logical rank index. MaterializeCommDomainScopes requires the enclosing pl.range to be [0, N) (materialize_comm_domain_scopes_pass.cpp:244), and at runtime world = len(device_ids) with worker ids validated against [0, world) (distributed_runner.py:1803-1811). The mapping is rank r → device_ids[r].

As written, the doc would flag device_ids=[4, 5] + device=r over range(2) as a bug, when that is the correct and common form. The real invariant is that the dispatch loop's trip count must equal len(device_ids) — which is automatic when you write pl.range(pld.world_size()) — and has nothing to do with the physical IDs. Needs rewriting in both en and zh, with an example of an actual mismatch (e.g. 4 cards in device_ids but the dispatch loop only covering range(2)).


No runtime risk — docs only. The verification steps in the PR description line up with the repo's lint scripts; just note that C is invisible to CI and needs a human pass.

- 01-collectives.md, 02-primitives.md (en+zh): label the illustrative
  code sketches as such (they omit nranks/my_rank derivation and buffer
  setup) and add a Runnable Examples table linking each snippet to its
  tests/st/distributed/ counterpart. Filled in the dangling "factory
  function pattern" reference in Ring Mode with the actual pattern
  (outer function derives total_rounds, defines @pl.program in its own
  body) and a pointer to the ring intrinsic test.
- 00-model.md, 03-execution.md (en+zh): added a driver snippet
  (DistributedConfig -> ir.compile -> dispatch) after the Quickstart
  class so "python script.py" has a referent, and turned 03-execution's
  duplicate CLI Launch section into a back-link.
- 02-primitives.md (zh): closed content gaps vs. the English page --
  Put/Get signature tables, the missing pld.get_comm_ctx namespace row,
  pld.put/pld.get in the no-short-form list, the handshake's expected-
  output paragraph, remote_load's misalignment warning, and the
  AtomicAdd-vs-Set corrective paragraph in the barrier section. Named
  the namespace on the Put and Get heading (en+zh).
- 00-model.md (en+zh): fixed the Line-by-Line Walkthrough's AtomicAdd
  rationale, which claimed N ranks write the same signal slot -- with
  offsets=[my_rank, 0] each cell has exactly one writer, matching what
  02-primitives.md already said about the same code.
- 03-execution.md (en+zh): completed prepare()'s signature (extra_compiled,
  persistent, reset_persistent_windows, sub_worker_overrides) and added a
  section explaining what config/persistent actually do, qualified
  00-model.md's "no persistent IPC" claim accordingly, and switched the
  DistributedWorker(compiled) examples to compiled.prepare() to match the
  documented entry point.
- 04-debugging.md (en+zh): rewrote the device_ids/device= pitfall --
  device_ids are physical card IDs (need not be contiguous or start at
  0); device=r is a logical rank index validated against [0, world); the
  actual invariant is that the dispatch loop's trip count must equal
  len(device_ids).
@georgebisbas

Copy link
Copy Markdown
Contributor Author

@YunjiQin thanks for the thorough review — fixed all seven in adfdeadc:

  • A (undefined vars / mixed host+InCore snippets): labeled the sketches as illustrative and added a "Runnable Examples" table in both 01-collectives.md and 02-primitives.md (en+zh) mapping every snippet to its real test under tests/st/distributed/. Also filled in the dangling "factory function pattern" reference in Ring Mode with the actual pattern from test_l3_tensor_allreduce_ring_intrinsic.py.
  • B (python script.py referent): added a driver snippet (DistributedConfigir.compile → dispatch) right after the Quickstart class in 00-model.md, and turned 03-execution.md's duplicate CLI Launch section into a back-link.
  • C (zh 02-primitives.md parity): added the Put/Get signature tables, the missing pld.get_comm_ctx namespace row, pld.put/pld.get in the no-short-form list, the handshake's expected-output paragraph, remote_load's misalignment warning, and the AtomicAdd-vs-Set corrective paragraph in the barrier section. Also named the namespace on the "Put and Get" heading in both languages.
  • D (wrong AtomicAdd rationale): fixed 00-model.md's walkthrough — with offsets=[my_rank, 0] each cell has exactly one writer, matching what 02-primitives.md already said about the same code.
  • E (prepare() incomplete): filled in the full signature (extra_compiled, persistent, reset_persistent_windows, sub_worker_overrides) and added a section explaining what config/persistent actually do, with a qualifier on 00-model.md's "no persistent IPC" claim.
  • F (two ways to get a DistributedWorker): switched both examples to compiled.prepare(), matching the documented entry point; DistributedWorker(compiled) is now mentioned once as the equivalent constructor.
  • G (device_ids vs device=): rewrote the pitfall — device_ids are physical card IDs (need not be contiguous/start at 0), device=r is a logical rank index validated against [0, world); the real invariant is that the dispatch loop's trip count equals len(device_ids).

Ran markdownlint-cli2, check_docs_en_zh_parity.py, check_docs_nav.py, mkdocs build --strict, and pre-commit run --all-files locally — all clean.

Every example previously used the class-based @pl.program/@pl.function
authoring API, which requires a two-step ir.compile()+compiled(...) call
just to run. Rewrite to the free-function @pl.jit family instead
(@pl.jit.incore/@pl.jit/@pl.jit.host), matching the decorator this
manual's readers will actually copy-paste and run, and matching the
convention already used in examples/runtime/multi_program_kv_cache.py.
)

# 3. Read the received tag back out.
received = pl.load(signal, [0, 0], [1, 1])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

use pl.read/write for single element operation

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 5408b3e (en + zh) — the handshake now uses pl.read(signal, [0, 0]) / pl.write(out, [0, 0], received) for the single-element access, matching tests/st/distributed/test_l3_notify_wait.py (scalar read/write avoids the 32-byte tile-alignment constraint on the 4-byte INT32 signal cell). Verified with markdownlint-cli2, pre-commit (en/zh parity + nav + english-only), and the docs build.

Single-element access to the 4-byte INT32 signal cell avoids the 32-byte
tile-alignment constraint that a pl.load/pl.store of a [1, 1] tile would
hit, matching tests/st/distributed/test_l3_notify_wait.py.
Copilot AI review requested due to automatic review settings August 3, 2026 09:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Adds a new “Distributed Programming” chapter to the user docs (EN + ZH) and wires it into the MkDocs navigation, covering the distributed model, collectives, primitives, execution/worker lifecycle, and debugging guidance.

Changes:

  • Added docs/en/user/distributed/ with five new pages (index + 00–04).
  • Added a mirrored docs/zh/user/distributed/ chapter with the same structure/content.
  • Updated mkdocs.yml nav and i18n label mapping to surface the new chapter.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
mkdocs.yml Adds “Distributed” to nav and provides zh translation label for the nav item.
docs/en/user/distributed/index.md Introduces the distributed model, L2/L3 vocabulary, and reading path.
docs/en/user/distributed/00-model.md End-to-end quickstart + conceptual model (HOST orchestration, windows, signals).
docs/en/user/distributed/01-collectives.md Documents built-in collectives, modes/constraints, and runnable examples.
docs/en/user/distributed/02-primitives.md Documents low-level primitives (notify/wait, RMA, put/get) and constraints.
docs/en/user/distributed/03-execution.md Documents DistributedWorker, persistence modes, and env vars.
docs/en/user/distributed/04-debugging.md Documents failure patterns, pitfalls, and diagnostic flags.
docs/zh/user/distributed/index.md Chinese mirror of the distributed model overview + reading path.
docs/zh/user/distributed/00-model.md Chinese mirror of the quickstart + conceptual model.
docs/zh/user/distributed/01-collectives.md Chinese mirror of collectives documentation + examples list.
docs/zh/user/distributed/02-primitives.md Chinese mirror of primitives documentation + constraints.
docs/zh/user/distributed/03-execution.md Chinese mirror of DistributedWorker execution/lifecycle + env vars.
docs/zh/user/distributed/04-debugging.md Chinese mirror of debugging/pitfalls + diagnostic flags.

Comment on lines +8 to +12
| Symptom | Likely Cause | Fix |
| ------- | ------------ | --- |
| **All ranks hang** | Notify/wait ordering — a rank is waiting on a peer that hasn't notified yet | Ensure every rank calls `notify` before any rank calls `wait`. The notify loop should precede the wait loop. |
| **Silent data corruption** | `remote_load` offsets or shape don't match what the peer stored | Verify offsets align with the peer's store offsets. A 1-element shift introduces a full row of garbage. |
| **Signal cell never reaches expected value** | Wrong `NotifyOp`: used `Set` instead of `AtomicAdd` for a multi-participant barrier | Use `AtomicAdd` when N ranks contribute to the same slot; use `Set` for 1:1 exchanges. |
Comment on lines +8 to +12
| 症状 | 可能原因 | 修复 |
| ---- | -------- | ---- |
| **所有 rank 挂起** | notify/wait 顺序错误 | 确保 notify 循环在 wait 循环之前。 |
| **静默数据损坏** | `remote_load` offsets 或 shape 不匹配 | 验证 offsets 与对端的 store offsets 对齐。 |
| **Signal cell 永不达到期望值** | 错误 `NotifyOp` | 多参与者屏障用 `AtomicAdd`;1:1 交换用 `Set`。 |
Standardize the chapter on the @pl.jit DSL form: the ring-mode text now
presents the compile-time-NR factory pattern with @pl.jit (the specializer
folds the closure constants), and a DSL-form note frames @pl.program as the
class-based equivalent used by older tests under tests/st/distributed/.
Copilot AI review requested due to automatic review settings August 3, 2026 10:41
@georgebisbas

Copy link
Copy Markdown
Contributor Author

Quick note on the latest push (e17770a) — this chapter is now fully consistent on the @pl.jit DSL form:

  • 01-collectives.md (en+zh) — the Ring Mode factory-function pattern is now taught with @pl.jit (the specializer folds the closure constants into the generated program) instead of @pl.program, with a note that the referenced ST test still uses the equivalent @pl.program class form.
  • 00-model.md (en+zh) — added a short "DSL form" note framing @pl.jit as the canonical form and @pl.program/@pl.function as the class-based equivalent used by the older tests under tests/st/distributed/, cross-referencing the Language Guide § @pl.jit family.

Verified with markdownlint-cli2, check_docs_en_zh_parity.py, and check_docs_nav.py. The distributed ST suite itself still uses @pl.program; a follow-up plan (pypto-3.0-notes plan 77) tracks migrating it to @pl.jit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

Suppressed comments (3)

docs/en/user/distributed/index.md:19

  • Markdown table rows starting with || create an empty first column (the first cell is blank), which will render as a misaligned 4-column table in standard Markdown. Use a single leading | instead (and keep the header separator aligned). This || ... pattern appears across the new distributed docs (EN/ZH), so it should be fixed consistently to avoid broken table rendering.
| Layer | Scope | API namespace |
| ----- | ----- | ------------- |
| L2 | Single-device (one NPU chip) | `pl.*` |
| L3 | Cross-rank (multiple NPUs or processes) | `pld.*` |

docs/en/user/distributed/04-debugging.md:15

  • The suggested fix is internally contradictory: it recommends allocating a fresh signal per iteration, but then states allreduce inside for/while is rejected. Clarify the actual allowed pattern (e.g., whether only signal-synthesized host allreduce is rejected in loops, or whether all forms are rejected), and update the fix text accordingly. Please mirror the clarification in the zh version as well to keep parity.
| **Allreduce rejected inside loop** | Signal protocol can't inject a fresh buffer per iteration | Allocate a fresh signal buffer for each allreduce call outside loops; allreduce inside `for`/`while` is currently rejected. |

docs/en/user/distributed/01-collectives.md:31

  • This statement hard-codes a specific barrier signaling scheme (AtomicAdd/Ge on [NR, 1]), but elsewhere in the chapter/primitives you describe cases where Set is sufficient (e.g., dedicated slots/rows per writer). Consider rephrasing to describe the required property (a global sync on a signal tensor of shape [NR, 1]) and mention the op choice depends on whether the protocol uses shared slots vs per-writer slots. Please keep the zh mirror aligned.
- One global barrier per call (AtomicAdd/Ge on `[NR, 1]` signal)

georgebisbas added a commit to georgebisbas/pypto that referenced this pull request Aug 3, 2026
…nual

Split out of PR hw-native-sys#2162 — the final piece, wiring the two new chapters
(hw-native-sys#2219, hw-native-sys#2220) into the existing manual:

- index.md (+ zh): new Contents/capability-table rows for the two
  chapters, a 4th reading path ("I want to run across multiple
  devices"), dropped the now-superseded dev-doc pointer for
  distributed collectives.
- 00-getting_started.md (+ zh): short pointer paragraphs into the new
  chapters from the existing benchmark/distributed sections.
- 02-operation_reference.md (+ zh): new "Distributed / Collective
  Operations" capability matrix cross-linking into the distributed
  chapter.

Depends on hw-native-sys#2219 (Distributed) and hw-native-sys#2220 (Performance) merging first —
this branch references pages that only exist once both land, so
`mkdocs build --strict` will fail here until then. Verified together
with both dependencies via a local integration merge (all green:
markdownlint, EN/ZH parity, nav, pre-commit, mkdocs build --strict);
opening this now so the full picture of the split is visible.
@YunjiQin
YunjiQin merged commit 4389165 into hw-native-sys:main Aug 3, 2026
15 checks passed
georgebisbas added a commit to georgebisbas/pypto that referenced this pull request Aug 3, 2026
…nual

Split out of PR hw-native-sys#2162 — the final piece, wiring the two new chapters
(hw-native-sys#2219, hw-native-sys#2220) into the existing manual:

- index.md (+ zh): new Contents/capability-table rows for the two
  chapters, a 4th reading path ("I want to run across multiple
  devices"), dropped the now-superseded dev-doc pointer for
  distributed collectives.
- 00-getting_started.md (+ zh): short pointer paragraphs into the new
  chapters from the existing benchmark/distributed sections.
- 02-operation_reference.md (+ zh): new "Distributed / Collective
  Operations" capability matrix cross-linking into the distributed
  chapter.

Depends on hw-native-sys#2219 (Distributed) and hw-native-sys#2220 (Performance) merging first —
this branch references pages that only exist once both land, so
`mkdocs build --strict` will fail here until then. Verified together
with both dependencies via a local integration merge (all green:
markdownlint, EN/ZH parity, nav, pre-commit, mkdocs build --strict);
opening this now so the full picture of the split is visible.
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.

3 participants