Skip to content

Add: L3 communication-computation example - #869

Open
Shenggan wants to merge 3 commits into
hw-native-sys:mainfrom
Shenggan:feat/add_l3_fusion_example
Open

Add: L3 communication-computation example#869
Shenggan wants to merge 3 commits into
hw-native-sys:mainfrom
Shenggan:feat/add_l3_fusion_example

Conversation

@Shenggan

@Shenggan Shenggan commented Jul 30, 2026

Copy link
Copy Markdown

This PR adds an L3 AllGather-GEMM fusion example that overlaps inter-device communication with GEMM computation at the tile level.

  • Add a multi-device L3 AllGather-GEMM example.
  • Support configurable communication and GEMM cores.
  • Support hardware and simulator platforms.

This PR depends on hw-native-sys/PTOAS#1086 and PTOAS 0.56, which has already been released.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds an N-rank L3 all-gather plus GEMM example. It implements tiled communication and GEMM kernels, rank orchestration, CLI validation, correctness checks, benchmarking, and documentation updates.

Changes

N-rank L3 all-gather + GEMM

Layer / File(s) Summary
Distributed communication and GEMM kernels
examples/advanced/l3_allgather_gemm.py
The example validates tile dimensions, publishes local shards, synchronizes remote chunks, and computes gathered GEMM tiles with configurable core partitions.
Execution orchestration and runtime controls
examples/advanced/l3_allgather_gemm.py
Host and chip orchestration allocate per-rank buffers and launch SPMD kernels. The CLI supports platform selection, compilation, correctness checks, benchmarking, and argument validation.
Example documentation and support listing
docs/examples/advanced.md, docs/examples/index.md
The documentation describes the new example, its N-rank execution, options, benchmarking, CI behavior, and platform support. The tracked-example count increases to 12.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant HostOrchestration
  participant ChipOrchestration
  participant CommKernel
  participant GemmKernel
  CLI->>HostOrchestration: parse execution options
  HostOrchestration->>ChipOrchestration: allocate per-rank buffers and launch rank
  ChipOrchestration->>CommKernel: publish local shards and signals
  ChipOrchestration->>GemmKernel: wait for gathered chunks and compute tiles
  GemmKernel-->>CLI: return output for correctness and benchmark reporting
Loading

Possibly related PRs

Poem

A rabbit hops through tiles of light,
Shards gather rank by rank just right.
GEMM crunches, signals ring,
Benchmarks measure everything.
New docs guide the code’s bright flight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: a new L3 communication-computation example.
Description check ✅ Passed The description directly explains the new L3 AllGather-GEMM example and its supported configurations.
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.

Shenggan and others added 2 commits August 6, 2026 20:58
Add the new N-rank L3 all-gather + GEMM example to the advanced and
index example pages, add the `# ci: devices=2` marker it needs to run
on the real a2a3 CI job (without it, task-submit borrows only one
card and the script's own world_size>=2 check fails), and align its
"chunked" wording with the "tiled" terminology used elsewhere.
@Shenggan Shenggan changed the title [WIP] Add: L3 communication-computation example Add: L3 communication-computation example Aug 6, 2026
@Shenggan
Shenggan marked this pull request as ready for review August 6, 2026 19:22

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

🤖 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 `@examples/advanced/l3_allgather_gemm.py`:
- Around line 234-240: Reset the persistent signal buffer before each repeated
benchmark launch in the kernel containing the all-gather loop and signal window
setup. Ensure each round clears or reinitializes signal values before the
`pld.system.wait` checks expecting 1, without changing the existing gathered
buffer or rank orchestration behavior.
- Around line 207-225: Update argument parsing for the comm_cores and gemm_cores
options to validate that their sum does not exceed the per-chip platform core
budget, in addition to the existing task-level checks. Reject invalid values
before overlap submissions run, using the platform’s established core-budget
symbol and preserving current validation for each option.
🪄 Autofix

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: 78f018e5-fb6c-4b50-957d-088bb4fd8267

📥 Commits

Reviewing files that changed from the base of the PR and between 222c9cf and 8fc355e.

📒 Files selected for processing (3)
  • docs/examples/advanced.md
  • docs/examples/index.md
  • examples/advanced/l3_allgather_gemm.py

Comment on lines +207 to +225
with pl.manual_scope():
_gathered, _ = pl.spmd_submit(
self.comm_local_shard,
local_a,
gathered,
signal,
core_num=comm_cores,
)
out, _ = pl.spmd_submit(
self.gemm_from_gathered,
local_a,
gathered,
signal,
weight,
out,
core_num=gemm_cores,
)

return out

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check spmd_submit semantics inside manual_scope and core-count constraints.
set -euo pipefail

rg -n -C10 'def spmd_submit' --glob '*.py' || true
rg -n -C6 'def manual_scope' --glob '*.py' || true

# Other examples that issue two spmd_submit calls in one manual_scope.
rg -n -C12 'spmd_submit' examples || true

# Core budget validation elsewhere in the repo.
rg -n -C4 'core_num|core_budget|MAX_CORE|aic_num|aiv_num' --glob '*.py' || true

Repository: hw-native-sys/pypto-lib

Length of output: 161


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files named pypto/CLAUDE.md and rules =="
fd -a 'CLAUDE\.md$|.*\.md$' .claude 2>/dev/null | sed 's#^\./##' | head -200 || true
wc -l .claude/CLAUDE.md 2>/dev/null || true

echo "== relevant pypto/coding style files =="
fd -a 'pypto-coding-style\.md$|.*\.md$' docs/pypto-coding 2>/dev/null | sed ' s#^\./##' || true

echo "== candidate files containing pypto imports/submit/manual_scope/gathered/core_num =="
rg -n -C5 'pl\.(manual_scope|spmd_submit)|spmd_submit|manual_scope|gathered|core_num' --glob '*.py' . || true

echo "== target file outline and relevant section =="
wc -l examples/advanced/l3_allgather_gemm.py 2>/dev/null || true
sed -n '1,280p' examples/advanced/l3_allgather_gemm.py 2>/dev/null || true

echo "== imports and namespace aliases in py files =="
rg -n 'import .* as pl|from .* import .* as pl|import pypto' --glob '*.py' . || true

Repository: hw-native-sys/pypto-lib

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file head =="
sed -n '1,80p' examples/advanced/l3_allgather_gemm.py 2>/dev/null || true

echo "== target function argument parsing and chip_orch call =="
sed -n '266,380p' examples/advanced/l3_allgather_gemm.py 2>/dev/null || true

echo "== focused search for spmd_submit/manual_scope definitions =="
rg -n -C12 '^\s*def spmd_submit|^\s*async def spmd_submit|^\s*def manual_scope|^\s*async def manual_scope|^spmd_submit\s*=|manual_scope\s*=' \
  --glob '*.py' . --glob '!examples/advanced/l3_allgather_gemm.py' --glob '!models/deepseek_v4_flash_mtp/*' --generic -g '!**/*.py' \
  | head -300 || true

echo "== focused search for core budget validation =="
rg -n -C5 'aic_num|aiv_num|MAX_CORE|core_num|core_budget|num_cores|total.*core|device.*core' \
  --glob '*.py' . || true

echo "== focused search for manual_scope usage around spmd =="
rg -n -C6 'pl\.manual_scope|with pl\.manual_scope|manual_scope' \
  --glob '*.py' . | awk 'f<60{print; f++}' || true

Repository: hw-native-sys/pypto-lib

Length of output: 20565


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

path = Path("examples/advanced/l3_allgather_gemm.py")
text = path.read_text()
M_TILES = 2048 // 128
print(f"M_TILES = {M_TILES}")
print(f"current_default_core_sum = {4 + 8}")

platforms = ["a2a3", "a2a3sim", "a5", "a5sim"]
for platform in platforms:
    # No platform-specific constants are referenced here.
    if 4 + 8 <= M_TILES:
        print(f"{platform}: default 4+8 <= M_TILES={M_TILES}")

required = "args.comm_cores > M_TILES"
print(f"comm_over_tiles_warns_condition_present = {required in text}")
required = "args.gemm_cores > gemm_tasks"
print(f("gemm_over_tasks_warns_condition_present = {required in text}"))

# Inspect dependency-like args around spmd_submit in this file.
lines = text.splitlines()
for i, line in enumerate(lines):
    if "spmd_submit" in line:
        print(f"spmd_submit at line {i+1}: {line.strip()}")

# Count manual_scope and spmd_submit occurrences in this file only.
print(f"manual_scope_count = {text.count('pl.manual_scope')}")
print(f"spmd_submit_count = {text.count('pl.spmd_submit')}")
PY

Repository: hw-native-sys/pypto-lib

Length of output: 490


🌐 Web query:

pypto platform core budget a2a3 a5 aic_num aiv_num manual_scope spmd_submit

💡 Result:

PyPTO (Parallel Tensor/Tile Operation) is a high-performance programming framework for AI accelerators [1] that utilizes a tile-based programming model [1] and MPMD (Multiple Program Multiple Data) execution scheduling [1] to run task graphs on platforms such as Ascend A2/A3 (a2a3) and A5 (a5) [2][3]. The terms provided relate to specific runtime, architectural, and compilation configurations within the PyPTO ecosystem: - Platform Variants: a2a3 and a5 refer to distinct Ascend hardware targets (e.g., Ascend 910B and 950 respectively), which differ in architectural constants, memory reservation requirements, and ISA implementations [4][2][5][6]. - Core Budget: Generally refers to the allocation of AICore (AIC) and Vector Core (AIV) resources managed by the runtime for task scheduling [4][7][1]. - aic_num and aiv_num: These are configuration parameters or metrics defining the number of AICore and AIV units available or utilized per task or die, often used to determine scheduling and communication strategies [4]. - manual_scope: A programming mode in PyPTO where resources (such as tiles or buffers) must be explicitly bound or managed by the developer [6], often used to optimize performance or handle complex dependencies that the automatic runtime cannot infer [8][6]. - spmd_submit: Relates to the submission of SPMD (Single Program Multiple Data) style tasks within the framework, often involving the orchestration of fused kernels [9]. Explicit dependency management via submission APIs (e.g., pl.submit(..., deps=[...])) is frequently used as a manual override to resolve data hazards (such as WAR/RAW) that the automatic dependency tracker misses [8]. These components are part of the PTO2 (Parallel Task Orchestration v2) runtime system [7], which coordinates task graphs through host-side compilation, device-side AICPU-based scheduling, and execution on AICores [7][1]. Performance debugging within these environments often involves monitoring task flow, buffer reservations, and synchronization fences (e.g., MTE3→V pipes) to avoid deadlocks or suboptimal execution [8][9][7].

Citations:


Validate the per-rank core budget before running overlap submissions.

The example only checks task-level overuse: --comm-cores > M_TILES and --gemm-cores > gemm_tasks. It does not validate comm_cores + gemm_cores <= the per-chip platform core budget, so users can pass arbitrary positive values that exceed available cores. Add that validation or error at argument parsing time.

🤖 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 `@examples/advanced/l3_allgather_gemm.py` around lines 207 - 225, Update
argument parsing for the comm_cores and gemm_cores options to validate that
their sum does not exceed the per-chip platform core budget, in addition to the
existing task-level checks. Reject invalid values before overlap submissions
run, using the platform’s established core-budget symbol and preserving current
validation for each option.

Comment on lines +234 to +240
gathered_buf = pld.alloc_window_buffer([MAT_M, MAT_K], dtype=pl.FP16)
signal_buf = pld.alloc_window_buffer([world_size, M_TILES], dtype=pl.INT32)

for rank in pl.range(pld.world_size()):
gathered = pld.window(gathered_buf, [MAT_M, MAT_K], dtype=pl.FP16)
signal = pld.window(signal_buf, [world_size, M_TILES], dtype=pl.INT32)
self.chip_orch(inputs[rank], weight, outputs[rank], gathered, signal, device=rank)

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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Determine window buffer initialization and lifetime across repeated launches.
set -euo pipefail

rg -n -C10 'def alloc_window_buffer|def window\(' --glob '*.py' || true

# Does any example or test reset a signal window between launches?
rg -n -C6 'signal' examples --glob '*.py' || true

# Benchmark launch loop: confirm the compiled program is re-executed in-process.
rg -n -C15 'def benchmark' --glob '*.py' | rg -n -C15 'rounds|warmup|for ' || true

Repository: hw-native-sys/pypto-lib

Length of output: 161


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | sed -n '1,120p'

echo "== target file excerpts =="
if [ -f examples/advanced/l3_allgather_gemm.py ]; then
  wc -l examples/advanced/l3_allgather_gemm.py
  sed -n '1,280p' examples/advanced/l3_allgather_gemm.py
fi

echo "== runtime_benchmark mentions =="
rg -n -C8 'runtime_benchmark|benchmark_rounds|benchmark_warmup|--benchmark-warmup|--benchmark-rounds' .

Repository: hw-native-sys/pypto-lib

Length of output: 22642


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate runtime benchmark implementation =="
fd -a 'benchmark.py|*.py$' . | sed -n '1,200p'
rg -n 'def benchmark|class BenchmarkStats|`@benchmark_round`|rounds|warmup' pypto pypto.runtime . --glob '*.py' || true

echo "== target runtime benchmark source snippets =="
rg -n -C80 'def benchmark|class BenchmarkStats|rounds|warmup|compiled' pypto --glob '*.py' || true

Repository: hw-native-sys/pypto-lib

Length of output: 518


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate runtime benchmark implementation =="
git ls-files '*.py' | rg 'pypto|runtime|benchmark' || true
rg -n 'def benchmark|class BenchmarkStats|`@benchmark_round`|rounds|warmup|alloc_window_buffer|window\(' . --glob '*.py' || true

echo "== target runtime paths snippets from all python files =="
for f in $(git ls-files '*.py'); do
  if rg -q 'def benchmark|class BenchmarkStats|rounds|warmup|alloc_window_buffer|window\(' "$f"; then
    echo "--- $f ---"
    wc -l "$f"
    rg -n -C12 'def benchmark|class BenchmarkStats|rounds|warmup|alloc_window_buffer|window\(' "$f" || true
  fi
done

Repository: hw-native-sys/pypto-lib

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== golden runner relevant region =="
sed -n '920,1085p' golden/runner.py

echo "== runtime benchmark symbol locations =="
rg -n 'def benchmark\(|class Benchmark|rounds=.*warmup|warmup.*rounds|runtime_benchmark|benchmark as' . --glob '*.py' --max-count 200 || true

Repository: hw-native-sys/pypto-lib

Length of output: 9698


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pypto runtime files =="
git ls-files 'pypto/runtime*' .runtime* benchmarks 2>/dev/null || true
rg -n 'def benchmark\(|def runtime_benchmark|class Benchmark|rounds:|warmup:|persistent|reset_persistent_windows|alloc_window_buffer|window\(' pypto . --glob '*.py' --max-count 300 || true

Repository: hw-native-sys/pypto-lib

Length of output: 50379


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== benchmark test region =="
sed -n '1245,1315p' tests/golden/test_runner.py
sed -n '1323,1430p' tests/golden/test_runner.py

echo "== main benchmark call region =="
wc -l examples/advanced/l3_allgather_gemm.py
sed -n '350,420p' examples/advanced/l3_allgather_gemm.py

Repository: hw-native-sys/pypto-lib

Length of output: 9022


Reset signal between benchmark rounds.

The benchmark path reuses the persistent program/window buffers by design, while this kernel leaves signal_buf untouched after each launch and waits with expected=1. Clear the signal window before every repeated benchmark launch, or use round-dependent pld.system.notify values and pld.system.wait thresholds instead.

🤖 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 `@examples/advanced/l3_allgather_gemm.py` around lines 234 - 240, Reset the
persistent signal buffer before each repeated benchmark launch in the kernel
containing the all-gather loop and signal window setup. Ensure each round clears
or reinitializes signal values before the `pld.system.wait` checks expecting 1,
without changing the existing gathered buffer or rank orchestration behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant