Skip to content

fix(pcie): retire capture channel aliases - #103

Closed
malaiwah wants to merge 12 commits into
local-inference-lab:masterfrom
malaiwah:fix/pcie-dcp-capture-channel-adoption-20260730
Closed

fix(pcie): retire capture channel aliases#103
malaiwah wants to merge 12 commits into
local-inference-lab:masterfrom
malaiwah:fix/pcie-dcp-capture-channel-adoption-20260730

Conversation

@malaiwah

@malaiwah malaiwah commented Jul 30, 2026

Copy link
Copy Markdown

Summary

Retire graph-owned DCP channel aliases when capture exits and derive DCP staging-slot ownership from device execution state so CUDA graph replay advances the slot.

Fixes #95. Also incorporates #101 so both reviewed PCIe corrections coexist on one stack.

Scope after re-review

Issue #95's original odd-operation corruption claim was retracted: MLA's mandatory TP reduction closes that proposed graph-boundary window, and AG/RS pairing is structural. Two defects remain actionable:

  1. _channels retained aliases written for torch-owned nested capture streams after the context exited. A recycled stream key could hand a later unwrapped capture a channel owned by a previous graph.
  2. Host-side slot selection executes once during graph capture, so graph replay does not advance DCP double-buffer ownership.

Change

  • Snapshot pre-capture stream mappings; on context exit, remove every alias to the graph-owned channel or restore the eager channel that capture temporarily replaced.
  • Keep graph channels in _all_channels for captured-kernel replay lifetime.
  • Pass both DCP staging slabs to both kernels and select from pre-increment device execution parity through one shared helper.
  • Preserve rank-specific AG/RS counter/grid pairing; every rank derives the same parity for a given operation.
  • Incorporate fix(pcie): prevent two-slot selector overflow #101's replay-safe reusable collective stack. One-shot/two-shot perform a fully resident launch-wide rendezvous inside each existing kernel, so graph replay advances one stable slab without a separate selector launch.
  • Remove the now-unused host selector and its standalone test after DCP migrates to device parity.

Invariants

  • Captured nodes retain valid IPC slabs until rollback/close.
  • Recycled stream keys never adopt a stale graph channel.
  • Eager mappings overwritten by capture are restored; unrelated and nested mappings remain correct.
  • Eager and captured DCP launches alternate slots by actual execution, including adjacent same-operation graph replays.
  • Reusable one-shot/two-shot selection is execution-owned and stable across every block in a launch.
  • Numerics, exported APIs, registered-buffer behavior, and latency-sensitive kernel launch counts remain unchanged.

Verification

  • Combined focused local suite: 44 passed, 2 skipped. Skips are opt-in live-GPU one-shot suites.
  • Current-head DCP A2A, one-shot, and two-shot CUDA extensions compiled and loaded together from a fresh cache against the pulled r12 image environment.
  • Changed Python files: Ruff format and lint pass.
  • DCP CPU ownership coverage includes nested capture restoration.
  • DCP and reusable-collective GPU regressions perform real graph replays and staging-slot observation; live multi-GPU execution is delegated to the separate field-test agent.

No rental or production-GPU result is claimed here. Production was not rebuilt or restarted.

Review follow-up

  • 22c11df: extracted the correctness-critical DCP staging selection into one shared device helper and added nested pool.capture() restoration coverage.
  • 7e17517: stacked fix(pcie): prevent two-slot selector overflow #101's execution-owned one-shot/two-shot selection.
  • 25b7810: removed the obsolete host selector after DCP migration and applied changed-file formatting.
  • 5c4f8b0: folded reusable selection into existing kernels, removing the reviewed extra GPU launch.

Stack

Merge #101 first. This branch contains #101 plus the DCP execution-owned parity and channel-lifetime commits; after #101 lands, GitHub will narrow this PR to the DCP-specific delta.

Summary by CodeRabbit

  • Bug Fixes

    • Improved PCIe communication reliability during CUDA Graph capture and replay.
    • Preserved and restored stream-channel mappings correctly across nested captures.
    • Ensured staging buffers alternate safely between graph replays.
    • Added validation for unsupported large-grid configurations.
  • Tests

    • Expanded coverage for all-gather, reduce-scatter, all-reduce, and fused operations.
    • Added checks for output correctness, staging-slot rotation, and capture cleanup.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

PCIe DCP A2A, one-shot, and two-shot collectives now select alternating staging slots on the device. Capture lifecycle logic restores eager channel mappings after nested graph capture. GPU tests inspect staging markers and validate CUDA Graph replay alternation.

Changes

PCIe staging and capture behavior

Layer / File(s) Summary
DCP device-selected staging
sparkinfer/comm/pcie/pcie_dcp_a2a.cu, tests/comm/test_pcie_dcp_a2a_gpu.py
DCP A2A kernels use DoubleStaging and select slabs from device execution-counter parity. Tests validate adjacent eager operations and alternating graph replay slots.
Capture channel mapping restoration
sparkinfer/comm/pcie/pcie_dcp_a2a.py, tests/comm/test_pcie_dcp_a2a.py
Capture snapshots eager mappings, restores existing aliases, removes new aliases, and validates nested capture cleanup.
One-shot device-selected staging
sparkinfer/comm/pcie/pcie_oneshot.cu, tests/comm/test_pcie_oneshot_fused_rmsnorm_gpu.py, tests/comm/test_pcie_oneshot_torture.py
Regular and fused allreduce kernels use dual rank-data slots with device-side generation coordination. Graph tests inspect eager markers across replays.
Two-shot device-selected staging
sparkinfer/comm/pcie/pcie_twoshot.cu, tests/comm/test_pcie_twoshot.py
Reduce-scatter and all-gather use GPU-coordinated dual staging pointers. Collectives enforce kMaxBlocks, and graph tests validate alternating slots.

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

Sequence Diagram(s)

sequenceDiagram
  participant Capture
  participant PCIeCollective
  participant DeviceSelector
  participant CUDAGraph
  Capture->>PCIeCollective: Capture collective with dual staging metadata
  PCIeCollective->>CUDAGraph: Record kernel arguments
  CUDAGraph->>DeviceSelector: Replay kernel launch
  DeviceSelector->>DeviceSelector: Coordinate generation and select slot
  DeviceSelector-->>PCIeCollective: Publish selected staging pointers
Loading

Possibly related PRs

Suggested reviewers: lukealonso

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The one-shot and two-shot kernel and test changes are not required by linked issue #95 and expand the PR beyond DCP A2A capture hardening. Move the one-shot and two-shot changes to a linked PR, or add their issue requirements and resolve the reported one-shot replay failures before merging.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately identifies capture-channel alias retirement, which is a primary change in the pull request.
Linked Issues check ✅ Passed The DCP changes address both #95 objectives: device-side staging-slot parity and capture-alias restoration or removal.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
sparkinfer/comm/pcie/pcie_dcp_a2a.cu (1)

176-186: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Identical staging-slot-selection block duplicated across both kernels.

The 7-line block (shared staging decl, thread-0 parity load + peer-pointer copy, __syncthreads()) is byte-for-byte identical in dcp_lse_reduce_kernel (Lines 176-186) and all_gather_heads_kernel (Lines 317-327). Since this logic encodes the correctness-critical parity contract (which slot a given execution must use), keeping it in one place would reduce the risk of the two copies silently diverging under future edits.

♻️ Proposed extraction into a shared device helper
+template <int world_size>
+DINLINE void select_staging(RankStaging &staging,
+                             const DoubleStaging &staging_options,
+                             Signal *self) {
+  if (threadIdx.x == 0) {
+    const int slot =
+        int(load_flag(&self->self_counter[blockIdx.x][0]) & FlagType{1});
+#pragma unroll
+    for (int peer = 0; peer < world_size; ++peer) {
+      staging.ptrs[peer] = staging_options.slots[slot].ptrs[peer];
+    }
+  }
+  __syncthreads();
+}

Then in each kernel:

   __shared__ RankStaging staging;
-  if (threadIdx.x == 0) {
-    const int slot =
-        int(load_flag(&self->self_counter[blockIdx.x][0]) & FlagType{1});
-#pragma unroll
-    for (int peer = 0; peer < world_size; ++peer) {
-      staging.ptrs[peer] = staging_options.slots[slot].ptrs[peer];
-    }
-  }
-  __syncthreads();
+  select_staging<world_size>(staging, staging_options, self);

Also applies to: 317-327

🤖 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 `@sparkinfer/comm/pcie/pcie_dcp_a2a.cu` around lines 176 - 186, Extract the
duplicated staging-slot-selection logic from dcp_lse_reduce_kernel and
all_gather_heads_kernel into one shared device helper, including the shared
staging declaration, parity-based slot selection, peer-pointer copy, and
synchronization. Update both kernels to call the helper while preserving the
existing staging_options, self_counter, blockIdx.x, and world_size behavior.
sparkinfer/comm/pcie/pcie_dcp_a2a.py (1)

767-805: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add nested-capture restoration coverage. Sequential capture tests already validate eager mapping restoration, but capture() allows recursive use from for_stream() and its restore logic removes every matching alias independently; add a regression test that nests with pool.capture(...): and asserts the inner alias is fully unwound before the outer one restores.

🤖 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 `@sparkinfer/comm/pcie/pcie_dcp_a2a.py` around lines 767 - 805, The capture
restoration tests lack coverage for recursively nested pool.capture contexts and
alias cleanup. Add a regression test using nested with pool.capture(...) blocks
that verifies the inner capture’s stream alias is removed or restored before the
outer context exits, while preserving the outer mapping until its own
restoration; target the capture method and existing eager mapping restoration
test setup.
🤖 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.

Nitpick comments:
In `@sparkinfer/comm/pcie/pcie_dcp_a2a.cu`:
- Around line 176-186: Extract the duplicated staging-slot-selection logic from
dcp_lse_reduce_kernel and all_gather_heads_kernel into one shared device helper,
including the shared staging declaration, parity-based slot selection,
peer-pointer copy, and synchronization. Update both kernels to call the helper
while preserving the existing staging_options, self_counter, blockIdx.x, and
world_size behavior.

In `@sparkinfer/comm/pcie/pcie_dcp_a2a.py`:
- Around line 767-805: The capture restoration tests lack coverage for
recursively nested pool.capture contexts and alias cleanup. Add a regression
test using nested with pool.capture(...) blocks that verifies the inner
capture’s stream alias is removed or restored before the outer context exits,
while preserving the outer mapping until its own restoration; target the capture
method and existing eager mapping restoration test setup.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 49521d6b-65fb-4f1f-8cea-973dda78003d

📥 Commits

Reviewing files that changed from the base of the PR and between 6a2babc and 3e5ef42.

📒 Files selected for processing (4)
  • sparkinfer/comm/pcie/pcie_dcp_a2a.cu
  • sparkinfer/comm/pcie/pcie_dcp_a2a.py
  • tests/comm/test_pcie_dcp_a2a.py
  • tests/comm/test_pcie_dcp_a2a_gpu.py

…60730' into HEAD

# Conflicts:
#	sparkinfer/comm/pcie/pcie_dcp_a2a.cu
@malaiwah

Copy link
Copy Markdown
Author

Addressed both CodeRabbit nitpicks in 22c11dfba845.

  • Extracted the duplicated parity load, peer-pointer selection, and block synchronization into one select_staging<world_size> device helper used by both DCP kernels.
  • Added test_pool_restores_nested_capture_mappings, which proves the inner capture aliases are removed before the outer context exits, the outer mapping remains usable, and the eager mapping is restored after the outer exit.

Current-head verification:

  • CPU-isolated DCP ownership + bounded-selector suites: 13 passed
  • Fresh-cache DCP CUDA extension compile/load: sparkinfer_pcie_dcp_a2a_ext
  • Changed-file Ruff lint: pass

No live multi-GPU replay result is claimed; the production service was not rebuilt or restarted.

@malaiwah

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

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 `@sparkinfer/comm/pcie/pcie_oneshot.cu`:
- Line 691: Replace host-side staging-slot selection via
dbuf_slot_selector_.take() at sparkinfer/comm/pcie/pcie_oneshot.cu:691 and :768,
and the reduce-scatter/all-gather selections at
sparkinfer/comm/pcie/pcie_twoshot.cu:319 and :335, with replay-safe device-owned
parity selection while passing both eager slabs; alternatively reject graph
capture for these paths. Preserve CUDA graph capture/replay support as the
required behavior.
🪄 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: 4cb63097-54d1-497b-a464-be28fb05da3b

📥 Commits

Reviewing files that changed from the base of the PR and between 3e5ef42 and 22c11df.

📒 Files selected for processing (7)
  • sparkinfer/comm/pcie/pcie_dcp_a2a.cu
  • sparkinfer/comm/pcie/pcie_oneshot.cu
  • sparkinfer/comm/pcie/pcie_twoshot.cu
  • sparkinfer/comm/pcie/two_slot_selector.h
  • tests/comm/test_pcie_dcp_a2a.py
  • tests/comm/test_pcie_dcp_a2a_gpu.py
  • tests/comm/test_pcie_two_slot_selector.py

Comment thread sparkinfer/comm/pcie/pcie_oneshot.cu Outdated
@malaiwah

Copy link
Copy Markdown
Author

Final stacked-head update at 5c4f8b0:

Verification on the current stack: 44 passed, 2 opt-in GPU skips; DCP A2A, one-shot, and two-shot CUDA extensions compiled and loaded together from a fresh cache; six changed Python files pass Ruff format/lint. Multi-GPU execution is owned by the separate field-test agent; no rental/production result is claimed here.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@malaiwah, I will review the current stacked head and the reported verification scope.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@malaiwah

malaiwah commented Jul 31, 2026

Copy link
Copy Markdown
Author

Rental-machine validation — FAIL (strict safety review supersedes earlier PASS)

Public PR head: 8fd90a4f687895e705bdf52fcff84ef653a5abf0
Repair runtime tested: 45029f6f101ce8b733d088d2694d3320836b924b
Test/benchmark lineage reviewed: c32da63ea589f32a33e5cc06dabdc9fb87f7f820
Host: Vast.ai, 4× RTX PRO 6000 Blackwell 96 GB, NODE/NUMA0
Driver/CUDA/PyTorch: 610.43.02 / runtime 13.2 (driver API 13.3) / 2.12.0+cu132

The previous comment proved that the corrected scratch-reuse oracle passes, but a strict synchronization/lifecycle review found P1 defects outside that oracle:

  • fix(pcie): retire capture channel aliases #103 selects DCP parity per worker block. A large→small→large grid sequence leaves returning blocks one operation behind; under rank skew they can overwrite the smaller operation before its peer finishes consuming it.
  • DCP teardown suppresses dispose/unmap/free errors while discarding ownership, and rollback removes retryable ownership before coordinated close.
  • one-shot/two-shot/DCP partial setup is not an all-ranks transaction; exports can be freed while a peer import remains mapped.
  • GC can unmap IPC pointers without a local completion edge for queued asynchronous work.
  • _group_ranks() sorts an already group-rank-ordered PyTorch result, breaking nonmonotonic process groups.
  • 36/64-block cross-device barriers still depend on an unproved full-grid residency assumption on smaller/MIG partitions.

Useful positive evidence remains valid but is not acceptance evidence: DCP2/DCP4 basic numerical smoke, fused add+RMS graph at 2/4 ranks, fresh first-use capture at 2/4 ranks, 1,025 four-rank opposite-order and 17-collective replay tests, and two-shot correctness. The first fused graph run also exposed and retained a CUDA 13.3 Python-binding harness incompatibility; the version-neutral edge/geometry inspector then passed.

Immutable evidence and chronology:

A replacement now uses one operation-wide same-stream DCP control node plus collective setup rollback, retryable teardown, GC retention and exact group ordering. I will not push it until fresh-cache deterministic large↔small skewed DCP2/DCP4 and independent review both pass.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (4)
tests/comm/test_pcie_twoshot.py (2)

65-80: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add assertion messages to the slot checks.

Both assertions fail without context. tests/comm/test_pcie_oneshot_torture.py line 151 includes the observed slot list in the message. Include snapshots and changed_slots here for the same diagnostic value.

♻️ Proposed message additions
-    assert all(len(changed) == 1 for changed in changed_slots)
-    assert all(
-        changed_slots[index] != changed_slots[index + 1]
-        for index in range(len(changed_slots) - 1)
-    )
+    assert all(len(changed) == 1 for changed in changed_slots), (
+        f"each operation must change exactly one staging slot: {changed_slots} "
+        f"from {snapshots}"
+    )
+    assert all(
+        changed_slots[index] != changed_slots[index + 1]
+        for index in range(len(changed_slots) - 1)
+    ), f"staging slots did not alternate: {changed_slots}"
🤖 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/comm/test_pcie_twoshot.py` around lines 65 - 80, Update
_assert_alternating_slots so both assertions include diagnostic messages
containing snapshots and changed_slots, matching the contextual style used by
the oneshot torture test; preserve the existing assertion conditions.

25-62: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive the staging layout from the production module.

_local_staging_words recomputes pack_stride, scale_offset, scale_stride, slot_bytes, and signal_bytes with the same formulas as sparkinfer/comm/pcie/pcie_twoshot.py from_exchange_group. The test also hardcodes the alignment 256 while the module uses IPC_SLAB_ALIGNMENT. If the layout or the alignment constant changes, this helper reads the wrong offset and the slot assertions become meaningless instead of failing.

Expose the layout computation from sparkinfer/comm/pcie/pcie_twoshot.py and call it here, or at least import IPC_SLAB_ALIGNMENT and _align_up.

🤖 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/comm/test_pcie_twoshot.py` around lines 25 - 62, Update
_local_staging_words to reuse the production staging-layout computation from
from_exchange_group in pcie_twoshot.py, including IPC_SLAB_ALIGNMENT and
_align_up, instead of duplicating pack_stride, scale_offset, scale_stride,
slot_bytes, and signal_bytes formulas. Expose a suitable layout helper if
needed, then use its returned offsets and sizes so the test remains synchronized
with production changes.
tests/comm/test_pcie_oneshot_fused_rmsnorm_gpu.py (1)

75-91: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Share _local_eager_words instead of copying it.

tests/comm/test_pcie_oneshot_torture.py lines 46-60 contain the same function body. Move it into a shared test helper module so both tests read the staging markers through one implementation.

🤖 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/comm/test_pcie_oneshot_fused_rmsnorm_gpu.py` around lines 75 - 91, The
helper _local_eager_words is duplicated across the PCIe oneshot tests. Move its
implementation into a shared test helper module, then import and reuse that
helper in both test_pcie_oneshot_fused_rmsnorm_gpu.py and
test_pcie_oneshot_torture.py, removing the local definitions while preserving
its current behavior.
tests/comm/test_pcie_oneshot_torture.py (1)

120-151: 🩺 Stability & Availability | 🔵 Trivial

The reported deterministic failure is in this function.

The PR description reports that one-shot eager, graph, and multistream replay tests fail deterministically in _run_graph_scratch_reuse on rented multi-GPU hardware, and that the head should not merge as-is. The new marker logic here is self-consistent: 17 layers alternate slots, so the last two layer markers must exchange positions on each replay.

Record the failing assertion text and the observed final_slots or snapshot values against the current head. That evidence separates a kernel parity defect from a test expectation defect. I can prepare a reduced two-layer repro that isolates one device selection per replay, if that helps.

🤖 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/comm/test_pcie_oneshot_torture.py` around lines 120 - 151, Run the
failing one-shot eager, graph, and multistream replay cases on the current head,
especially _run_graph_scratch_reuse, and capture the exact assertion text plus
observed final_slots and snapshot values from the marker checks. Do not change
the alternating-slot expectation yet; use the collected evidence to determine
whether the failure is in kernel parity or the test expectation.
🤖 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 `@sparkinfer/comm/pcie/pcie_oneshot.cu`:
- Around line 199-220: The staged selectors require full grid residency and a
zero-entry staging counter. In sparkinfer/comm/pcie/pcie_oneshot.cu:199-220, add
a host-side occupancy-based residency limit using
cudaOccupancyMaxActiveBlocksPerMultiprocessor and multiProcessorCount, then
clamp blocks for the SPARKINFER_PCIE_ONESHOT_BLOCK_LIMIT and rows * ctas_per_row
launch paths. In sparkinfer/comm/pcie/pcie_twoshot.cu:97-118, apply the same
clamp in reduce_scatter and all_gather, including the default block_limit of 64
with 512 threads, and document that staging_arrive requires single-stream
ownership.

---

Nitpick comments:
In `@tests/comm/test_pcie_oneshot_fused_rmsnorm_gpu.py`:
- Around line 75-91: The helper _local_eager_words is duplicated across the PCIe
oneshot tests. Move its implementation into a shared test helper module, then
import and reuse that helper in both test_pcie_oneshot_fused_rmsnorm_gpu.py and
test_pcie_oneshot_torture.py, removing the local definitions while preserving
its current behavior.

In `@tests/comm/test_pcie_oneshot_torture.py`:
- Around line 120-151: Run the failing one-shot eager, graph, and multistream
replay cases on the current head, especially _run_graph_scratch_reuse, and
capture the exact assertion text plus observed final_slots and snapshot values
from the marker checks. Do not change the alternating-slot expectation yet; use
the collected evidence to determine whether the failure is in kernel parity or
the test expectation.

In `@tests/comm/test_pcie_twoshot.py`:
- Around line 65-80: Update _assert_alternating_slots so both assertions include
diagnostic messages containing snapshots and changed_slots, matching the
contextual style used by the oneshot torture test; preserve the existing
assertion conditions.
- Around line 25-62: Update _local_staging_words to reuse the production
staging-layout computation from from_exchange_group in pcie_twoshot.py,
including IPC_SLAB_ALIGNMENT and _align_up, instead of duplicating pack_stride,
scale_offset, scale_stride, slot_bytes, and signal_bytes formulas. Expose a
suitable layout helper if needed, then use its returned offsets and sizes so the
test remains synchronized with production changes.
🪄 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: 68d2ebcd-2210-413b-95a2-16c2c640e949

📥 Commits

Reviewing files that changed from the base of the PR and between 22c11df and 8fd90a4.

📒 Files selected for processing (8)
  • sparkinfer/comm/pcie/pcie_dcp_a2a.py
  • sparkinfer/comm/pcie/pcie_oneshot.cu
  • sparkinfer/comm/pcie/pcie_twoshot.cu
  • tests/comm/test_pcie_dcp_a2a.py
  • tests/comm/test_pcie_dcp_a2a_gpu.py
  • tests/comm/test_pcie_oneshot_fused_rmsnorm_gpu.py
  • tests/comm/test_pcie_oneshot_torture.py
  • tests/comm/test_pcie_twoshot.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/comm/test_pcie_dcp_a2a_gpu.py
  • tests/comm/test_pcie_dcp_a2a.py
  • sparkinfer/comm/pcie/pcie_dcp_a2a.py

Comment on lines +199 to +220
template <int ngpus>
DINLINE void select_rank_data(RankData& selected, const DoubleRankData& options, Signal* self_sg) {
if (threadIdx.x == 0) {
// Every supported staging grid fits concurrently on the target Blackwell
// GPU. The last arriving block publishes one launch-wide generation, so
// variable grid sizes cannot split a launch across two slabs.
const FlagType generation = ld_flag_acquire_gpu(&self_sg->staging_generation);
const FlagType prior = atomicAdd(&self_sg->staging_arrive, FlagType{1});
if (prior == static_cast<FlagType>(gridDim.x - 1)) {
self_sg->staging_arrive = 0;
__threadfence();
atomicAdd(&self_sg->staging_generation, FlagType{1});
} else {
while (ld_flag_acquire_gpu(&self_sg->staging_generation) == generation) {
}
}
const RankData* source = options.slots[generation & FlagType{1}];
#pragma unroll
for (int peer = 0; peer < ngpus; ++peer) selected.ptrs[peer] = source->ptrs[peer];
}
__syncthreads();
}

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.

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Unbounded launch-wide rendezvous in both selectors. Both files implement the same protocol: each block's thread 0 increments staging_arrive, and every block except the last arriver spins on staging_generation with no exit path. The shared root cause is that correctness depends on two unchecked preconditions — full grid residency and a zero staging_arrive at entry — asserted only in comments.

  • sparkinfer/comm/pcie/pcie_oneshot.cu#L199-L220: add a host-side residency check before the staged launches (cudaOccupancyMaxActiveBlocksPerMultiprocessor times multiProcessorCount) and clamp blocks, including the SPARKINFER_PCIE_ONESHOT_BLOCK_LIMIT and rows * ctas_per_row paths.
  • sparkinfer/comm/pcie/pcie_twoshot.cu#L97-L118: apply the same residency clamp in reduce_scatter and all_gather, where block_limit defaults to 64 with 512 threads, and document the single-stream ownership requirement for the shared staging_arrive counter.
📍 Affects 2 files
  • sparkinfer/comm/pcie/pcie_oneshot.cu#L199-L220 (this comment)
  • sparkinfer/comm/pcie/pcie_twoshot.cu#L97-L118
🤖 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 `@sparkinfer/comm/pcie/pcie_oneshot.cu` around lines 199 - 220, The staged
selectors require full grid residency and a zero-entry staging counter. In
sparkinfer/comm/pcie/pcie_oneshot.cu:199-220, add a host-side occupancy-based
residency limit using cudaOccupancyMaxActiveBlocksPerMultiprocessor and
multiProcessorCount, then clamp blocks for the
SPARKINFER_PCIE_ONESHOT_BLOCK_LIMIT and rows * ctas_per_row launch paths. In
sparkinfer/comm/pcie/pcie_twoshot.cu:97-118, apply the same clamp in
reduce_scatter and all_gather, including the default block_limit of 64 with 512
threads, and document that staging_arrive requires single-stream ownership.

Source: Coding guidelines

@malaiwah

Copy link
Copy Markdown
Author

Frozen replacement qualification — PASS (candidate only)

This is not a PASS for the current public #103 head
8fd90a4f687895e705bdf52fcff84ef653a5abf0. It qualifies frozen replacement
31fa6a48116471ce423f0338047453ec1032c202, based on
b38a60ecd5cb026f05ec27fc96433c9eb5ed326e and containing the reconciled
#101/#103 stack plus the subsequent transactional IPC/lifecycle repairs. It
supersedes rejected repair runtime 45029f6f101ce8b733d088d2694d3320836b924b
and every unqualified intermediate through 5b4d0d4b6109eea88de11be417a1728b105d0c9c.

Frozen source: 31fa6a48116471ce423f0338047453ec1032c202
on fork branch codex/pr101-103-safe-successor-31fa6a4 (published without
moving either rejected PR head); review is now isolated in draft successor
#105.

Host: Vast.ai 46335896, Ubuntu 24.04 / Linux 7.0, 4× RTX PRO 6000 Blackwell
96 GB, NODE/NUMA0. Driver 610.43.02; CUDA 13.2 runtime (13.3 driver API);
PyTorch 2.12.0+cu132. Candidate worktree clean; fresh extension cache
/workspace/field-review-tests/cache/sparkinfer-successor-31fa6a4-atomic.

Exact commands and results

With CUDA_VISIBLE_DEVICES=0,1,2,3, candidate PYTHONPATH, and the fresh
TORCH_EXTENSIONS_DIR above:

  • SPARKINFER_RUN_PCIE_ONESHOT_OPPOSITE_ORDER=1 SPARKINFER_PCIE_OPPOSITE_EAGER_ITERS=128 SPARKINFER_PCIE_OPPOSITE_GRAPH_REPLAYS=1025 python -m pytest -q tests/comm/test_pcie_oneshot_opposite_order_gpu.py1 passed in 6.36 s.
  • SPARKINFER_RUN_PCIE_DCP_A2A_TEST=1 SPARKINFER_PCIE_DCP_A2A_WORLD_SIZE=4 SPARKINFER_PCIE_DCP_GRAPH_REPLAYS=64 SPARKINFER_PCIE_DCP_TEST_TEARDOWN_RETRY=1 python -m pytest -q tests/comm/test_pcie_dcp_a2a_gpu.py::test_pcie_dcp_a2a_eager_and_cuda_graph_correctness1 passed in 115.01 s.
  • SPARKINFER_PCIE_TEST_COLLECTIVE_VALIDATION=1 python -m pytest -q tests/comm/test_pcie_collective_validation_gpu.py::test_asymmetric_argument_failures_reject_all_ranks_before_ipc and the DCP4 one-rank preflight node — both passed before IPC allocation.
  • SPARKINFER_RUN_PCIE_DCP_A2A_TEST=1 SPARKINFER_PCIE_DCP_A2A_WORLD_SIZE=4 SPARKINFER_PCIE_DCP_TEST_EXPECT_RESIDENCY_REJECTION=1 SPARKINFER_PCIE_TEST_VISIBLE_SM_COUNT=32 python -m pytest -q tests/comm/test_pcie_dcp_a2a_gpu.py::test_pcie_dcp_a2a_rejects_reduced_sm_slice_before_ipc_allocation1 passed in 4.71 s.
  • python -m pytest -q tests/comm239 passed, 21 skipped in 4.34 s.

The first combined rejection invocation accidentally omitted
SPARKINFER_PCIE_TEST_VISIBLE_SM_COUNT=32; its two other nodes passed and the
residency node correctly continued on the real 188-SM GPUs, producing a harness
FAIL rather than a code failure. The corrected exact node above passed; both
logs are retained.

Paired vLLM integration used exact vLLM head
be1e289a8ca6cc043b582b26c788efc4b1f5d0a8:

PYTHONPATH=<vllm-be1e289-tree>:<sparkinfer-31fa6a4-tree> \
TORCH_EXTENSIONS_DIR=/workspace/field-review-tests/cache/sparkinfer-successor-31fa6a4-atomic \
python -m pytest -q \
  tests/distributed/test_b12x_fused_all_reduce.py \
  tests/distributed/test_dcp_a2a.py

Collect-only found exactly 64 nodes; execution was 64 passed in 102.17 s.
No Xid, hang, stale IPC handle, rank-order mismatch, capture-time allocation,
or failed retry cleanup was observed. Independent reviewers approved the
collective symmetry, allocation safety, and ordered retryable teardown.

Raw logs remain on the active rental under
/workspace/field-review-tests/artifacts/:

  • spark-31fa6a4-opposite-order-dcp4-1025.log — SHA-256 0f323a71f6c67aa4c8657b354c7b74b8f3b27ae10e9c243c60976e6e16e781f4
  • spark-31fa6a4-dcp4-64-teardown-retry.log016c893abd7ce2b9ee831dd3f1a295cc862dc77bf7c923ed1f80dd596d102664
  • spark-31fa6a4-reduced-sm-rejection-dcp4-corrected.log5e360d08470919bc9df7bef2d2d20369af54a7acac546d32b69c786cb0f1a8e3
  • spark-31fa6a4-linux-comm-full.loge5e351d96812f657e3fc5e177488efdc8bb8424f69550f354c65759dc06b9de1
  • atomic-vllm-be1e289-spark-31fa6a4-linux-gpu-full.log370b632ab712eefc43ca11c239bf0337c90f1694008b147c29b583db63097419

Conclusion: the frozen replacement passes the relevant live DCP4,
opposite-order, rejection, retryable-teardown, and paired-vLLM gates. This is a
correctness/lifecycle qualification; no memory or serving-throughput gain is
claimed. The public PR must be updated to the reviewed lineage before #103
itself can be marked passing. Durable log archival is still pending.

@malaiwah

Copy link
Copy Markdown
Author

Superseding field result: the frozen semantic-channel successor is not yet
deployable
.

The focused four-rank eager/capture/torture and atomic vLLM/SparkInfer suites
all passed, but the first full GLM-5.2 startup gate found a contract the focused
tests missed. During determine_available_memory()'s uncaptured warm-up, a
compiled TP all-reduce requested vllm:eager:allreduce on a physical CUDA
stream that was already owned by the active vllm:target:profile semantic
scope. Its descriptor warm-ups run before CUDA itself reports the stream as
capturing, so SparkInfer did not apply its active-scope override, selected the
static eager channel, and correctly refused to alias the two channels:

RuntimeError: CUDA stream key ... is already bound to another logical PCIe oneshot channel

The engine failed before KV allocation/health, so there is no performance or
deployability claim for SparkInfer 31fa6a4 + vLLM be1e289. The SHA-only
appliance image containing them will not be promoted.

The complete call trace makes the repair direction deliberately narrow:

  1. while a semantic capture scope is active, route a pre-capture warm-up on
    that scope's owner stream to its top logical channel;
  2. do not extend that routing to unrelated side streams, and retain hard
    failures for genuine out-of-scope stream/channel mismatches;
  3. apply the rule symmetrically to one-shot and DCP pools; and
  4. make failure-path teardown idempotent when Torch has already removed the
    process group from the world-group map.

Re-qualification will include the same full-model boot/traffic/shutdown gate,
not just focused tests.

Complete immutable server log and analysis:

@malaiwah

Copy link
Copy Markdown
Author

Closing as superseded, not merged. Public head 8fd90a4 remains rejected for standalone promotion. The reviewed replacement is #105 at bc62980, paired atomically with field vLLM f99e1e7b8636ca3811ab6d23084ac6da63420dc3 and its patch-identical clean upstream PR local-inference-lab/vllm#216. The final corrected pair passed the complete GLM gate; evidence and exact reproduction contract: https://github.com/malaiwah/glm52-exl3-vast/blob/5c76a2536e7fc9a5f1cb6bf182531889f5385e65/docs/field-review-results/2026-07-30-vast-46335896/UPSTREAM-REPAIR-CAMPAIGN.md and https://github.com/malaiwah/glm52-exl3-vast/blob/5c76a2536e7fc9a5f1cb6bf182531889f5385e65/docs/field-review-results/2026-07-30-vast-46335896/COUNTER-VALIDATION.md. Do not cherry-pick #103 alone and call it equivalent.

@malaiwah malaiwah closed this Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant