Skip to content

Refacror: onboard implementation for L3-L2 orch comm data path #1305

Open
ccyywwen wants to merge 10 commits into
hw-native-sys:mainfrom
ccyywwen:l3-l2-comm-datapath-refactor-onboard-impl
Open

Refacror: onboard implementation for L3-L2 orch comm data path #1305
ccyywwen wants to merge 10 commits into
hw-native-sys:mainfrom
ccyywwen:l3-l2-comm-datapath-refactor-onboard-impl

Conversation

@ccyywwen

@ccyywwen ccyywwen commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR implements the onboard L3-L2 direct data path on top of PR #1291.

  • Add child-owned onboard GM region export through ACL IPC.
  • Import the ACL IPC region in the L3 Host parent and keep parent-private
    mapping metadata.
  • Route onboard payload transfer through parent-side ACL copy helpers.
  • Route onboard counter operations through conservative 4-byte ACL copies.
  • Update L3-L2 orch/message-queue docs and add Python UT coverage for onboard
    direct import behavior.

Counter Access Strategy

Counter read/write on onboard does not directly dereference the imported
device pointer.

The current implementation uses ACL memcpy for 4-byte counter operations:

  • Set: host-to-device 4-byte ACL copy.
  • test/wait: device-to-host 4-byte ACL copy polling.
  • Add: device-to-host 4-byte read, host-side add, then host-to-device
    4-byte write.

This intentionally avoids CPU direct dereference of imported GM counters and
avoids atomic read-modify-write on the imported region. The path is conservative
for a2a3 onboard stability. a5 currently reuses the same ACL IPC + ACL copy
scheme by assumption; if a5 onboard CI exposes a platform difference, that can
be handled in a follow-up.

jvjhfhg and others added 2 commits July 9, 2026 11:49
- Template L3L2QueueEndpoint on MaxInflight and remove runtime config
- Move active input tracking to a fixed ring with STOP extra capacity
- Unify L3-L2 helper namespaces, error metadata, cache, and time helpers
- Link public AICPU helper sources into JIT orchestration builds
- Update docs, examples, and C++ UT coverage
@coderabbitai

coderabbitai Bot commented Jul 9, 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

Run ID: 6ff69c22-a213-4a70-9b3a-d55ad8b2a764

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a direct host-mapped-region protocol for L3↔L2 communication, bypassing mailbox-based payload/counter transfers when available. It refactors cache maintenance and device timing into shared platform headers, converts message-queue/endpoint error handling to typed enums, wires region create/release controls through the worker manager and Python bindings, updates the message-queue example for multi-input windowed processing, and revises related documentation and tests.

Changes

L3-L2 Direct Region and Platform Refactor

Layer / File(s) Summary
Shared cache/time platform headers
src/common/platform/include/aicpu/cache_maintenance.h, src/common/platform/include/aicpu/device_time.h, src/common/platform/onboard/aicpu/cache_ops.cpp, src/common/platform/sim/aicpu/cache_ops.cpp, src/a2a3/...platform_regs.h, src/a5/...platform_regs.h, simpler_setup/toolchain.py, tests/ut/cpp/stubs/test_stubs.cpp, docs/hardware/cache-coherency.md
New common cache-maintenance and device-time headers replace per-platform inline helpers; platform_regs.h files delegate to the shared header; stubs/toolchain and docs updated accordingly.
Message queue & endpoint enum-based errors
src/common/platform/include/aicpu/l3_l2_message_queue.h, .../l3_l2_orch_endpoint.h, .../common/l3_l2_orch_comm.h, examples/.../l3_l2_orch_comm_orch.cpp, tests/ut/cpp/common/*
L3L2QueueError/L3L2EndpointError switch from string ops/pointers to typed enums and fixed message buffers; timing switches to shared device-time helpers; new namespace wrapper helpers added; tests updated.
Region wire contracts
src/common/platform/include/host/l3_l2_orch_region_access.h, tests/ut/cpp/common/test_l3_l2_orch_comm.cpp
New header defines L3L2RegionAccessProfile, mapping handle, and create request/reply structs with fixed byte sizes; layout tests added.
Worker manager control plane
src/common/hierarchical/worker_manager.{h,cpp}, src/common/hierarchical/worker.h
Adds region create/release control sub-commands and methods across WorkerEndpoint, LocalMailboxEndpoint, WorkerThread, WorkerManager.
Python/C++ bindings
python/bindings/task_interface.cpp, python/bindings/worker_bind.h
Adds nanobind functions for mapped-region import/close, payload read/write, counter notify/test/wait, ACL IPC export/close, and _Worker region control bindings.
Orch-comm direct mapped-region model
python/simpler/l3_l2_orch_comm.py
Adds region-create request/reply/mapping dataclasses, validation, and routes counters/payloads through direct mapped operations when available.
Worker.py region lifecycle
python/simpler/worker.py
Adds chip-side region create/release/sweep handling and rewrites create_l3_l2_region/cleanup to use the direct protocol with rollback.
Message-queue staging
python/simpler/l3_l2_message_queue.py, simpler_setup/kernel_compiler.py, tests/ut/py/test_worker/test_l3_l2_message_queue.py
Refactors input/output queue staging to delegate to helper methods and use direct host mapping; compiler links platform helper sources.
Direct-region tests
tests/ut/py/test_worker/test_l3_l2_orch_comm.py
Adds fake direct C-worker and sim/onboard tests for lifecycle, rollback, poisoning, and cleanup ordering.
Multi-input example kernel
examples/workers/l3/l3_l2_message_queue/kernels/..., examples/workers/l3/l3_l2_message_queue/test_l3_l2_message_queue.py
Rewrites AIV/orchestration kernels for two-input windowed operations and updates test harness/payload packing.
Documentation
docs/l3-l2-message-queue.md, docs/l3-l2-orch-comm.md
Updates queue/orch-comm docs for input-window semantics, host buffer requirements, control-path lifecycle, and new example section.

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

Possibly related PRs

  • hw-native-sys/simpler#1130: Both PRs document and define the same L3↔L2 message-queue protocol (STOP/release semantics, region/payload/counter layout, and input-window behavior).
  • hw-native-sys/simpler#1187: Builds on the same lazy host-buffer staging logic in the L3-L2 message queue module updated in this PR.

Poem

A rabbit hops through mapped-out lanes,
No mailbox now, direct terrain! 🐇
Counters tick in ARM's own beat,
Cache flushed clean, no stale repeat.
STOP drains the queue, the window closes tight—
Hop on, dear code, review's alright! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and correctly points to the onboard L3-L2 orch comm data path refactor.
Description check ✅ Passed The description directly matches the PR's onboard direct data path, ACL IPC, counter strategy, docs, and tests.
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.

@gemini-code-assist

Copy link
Copy Markdown

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
tests/ut/cpp/common/test_l3_l2_orch_comm.cpp (1)

174-190: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding offset checks for all fields to match existing test thoroughness.

The existing RequestAndResponseAreFixedSizePodDescriptorsOnly test checks every field offset for L3L2OrchCommRequest and L3L2OrchCommResponse. The new test only checks magic_version and payload_bytes for the request, and skips request_bytes, counter_bytes, and l3_host_pid offsets. Adding these would catch field reordering regressions more precisely.

♻️ Optional: add missing offset checks
     EXPECT_EQ(offsetof(L3L2RegionCreateRequest, magic_version), 0u);
+    EXPECT_EQ(offsetof(L3L2RegionCreateRequest, request_bytes), sizeof(uint64_t));
     EXPECT_EQ(offsetof(L3L2RegionCreateRequest, payload_bytes), sizeof(uint64_t) * 2);
+    EXPECT_EQ(offsetof(L3L2RegionCreateRequest, counter_bytes), sizeof(uint64_t) * 3);
+    EXPECT_EQ(offsetof(L3L2RegionCreateRequest, l3_host_pid), sizeof(uint64_t) * 4);
     EXPECT_EQ(sizeof(L3L2RegionCreateRequest), 40u);
     EXPECT_EQ(offsetof(L3L2RegionCreateReply, desc), 0u);
     EXPECT_EQ(offsetof(L3L2RegionCreateReply, access_profile), sizeof(uint64_t) * 6);
+    EXPECT_EQ(offsetof(L3L2RegionCreateReply, reserved), sizeof(uint64_t) * 6 + sizeof(uint32_t));
     EXPECT_EQ(offsetof(L3L2RegionCreateReply, device_id), sizeof(uint64_t) * 6 + sizeof(uint32_t) * 2);
+    EXPECT_EQ(offsetof(L3L2RegionCreateReply, export_key), sizeof(uint64_t) * 6 + sizeof(uint32_t) * 2 + sizeof(int32_t));
     EXPECT_EQ(offsetof(L3L2RegionCreateReply, backing_shm), sizeof(uint64_t) * 6 + sizeof(uint32_t) * 2 + 4u + 65u);
     EXPECT_EQ(offsetof(L3L2RegionCreateReply, mapping_bytes), 160u);
     EXPECT_EQ(sizeof(L3L2RegionCreateReply), 168u);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ut/cpp/common/test_l3_l2_orch_comm.cpp` around lines 174 - 190, The new
fixed-layout test for L3L2RegionCreateRequest/L3L2RegionCreateReply is
incomplete compared with the existing
RequestAndResponseAreFixedSizePodDescriptorsOnly coverage. In
LifecycleCreateWireStructsHaveFixedLayout, add offset assertions for the
remaining L3L2RegionCreateRequest fields such as request_bytes, counter_bytes,
and l3_host_pid so the test catches any field reordering or padding regressions,
using the existing offsetof checks alongside the current static_asserts and size
checks.
python/simpler/worker.py (1)

1226-1230: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Log best-effort cleanup failures.

These direct-region cleanup paths intentionally preserve the original error, but silently swallowing close/release failures makes leaked shared memory, ACL exports, or mappings hard to diagnose. Emit a warning to stderr while continuing best-effort cleanup. Based on learnings, silent exception swallowing should be treated as a diagnostic-consistency issue rather than cited as an active Ruff rule.

Also applies to: 1251-1252, 1273-1277, 3810-3817, 3826-3827, 3868-3869

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/worker.py` around lines 1226 - 1230, The best-effort cleanup
exception handlers are silently swallowing failures, which makes leaked shared
memory, ACL exports, or mappings hard to diagnose. Update the affected cleanup
paths around cw.free(region.dev_ptr) and the other direct-region release blocks
to catch the exception, emit a warning to stderr with enough context to identify
the cleanup step, and then continue preserving the original error flow. Apply
the same stderr warning pattern consistently in all listed cleanup handlers
rather than using bare pass.

Sources: Learnings, Linters/SAST tools

src/common/platform/include/aicpu/l3_l2_message_queue.h (1)

793-799: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

op parameter of ensure_live() is unused.

ensure_live(L3L2QueueOp op) only reads error_.kind; op is discarded via (void)op. Harmless, but the parameter doesn't do anything — worth removing or actually using it for diagnostics in a future pass. Not blocking.

🤖 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 `@src/common/platform/include/aicpu/l3_l2_message_queue.h` around lines 793 -
799, The ensure_live(L3L2QueueOp op) helper in l3_l2_message_queue.h ignores its
op argument and only checks error_.kind, so either remove the unused parameter
from ensure_live and its callers or use L3L2QueueOp in the check/logging path
instead of discarding it with (void)op. Keep the behavior unchanged while
cleaning up the signature in the L3L2 queue error-handling code.
src/common/platform/include/aicpu/l3_l2_orch_endpoint.h (1)

271-289: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Busy-wait polls the timer every iteration, unlike the sibling throttled pattern.

signal_wait() calls device_time_now_ticks() on every spin iteration. The message-queue endpoint added in the same cohort (l3_l2_message_queue.h's InputQueue::peek() / OutputQueue::reserve()) throttles this via spins & 1023ull == 0 before re-reading the clock. On non-__aarch64__ builds device_time_now_ticks() goes through std::chrono::steady_clock::now(), so calling it unconditionally in a tight compare/timeout loop is comparatively more expensive than the throttled sibling implementation.

♻️ Suggested consistency fix
         uint64_t start = device_time_now_ticks();
         uint64_t frequency_hz = device_time_frequency_hz();
+        uint64_t spins = 0;
         while (true) {
             int32_t current = load_counter(counter_addr);
             *observed = current;
             if (l3_l2_orch_comm::compare_counter(current, cmp_value, cmp)) {
                 return true;
             }
-            uint64_t now = device_time_now_ticks();
-            if (timeout == 0 || sys_cnt_elapsed_ns(start, now, frequency_hz) >= timeout) {
-                set_error(...);
-                return false;
+            spins += 1;
+            if (timeout == 0 || (spins & 1023ull) == 0) {
+                uint64_t now = device_time_now_ticks();
+                if (timeout == 0 || sys_cnt_elapsed_ns(start, now, frequency_hz) >= timeout) {
+                    set_error(...);
+                    return false;
+                }
             }
         }
🤖 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 `@src/common/platform/include/aicpu/l3_l2_orch_endpoint.h` around lines 271 -
289, The busy-wait in signal_wait() is re-reading the clock on every spin,
unlike the throttled pattern used in l3_l2_message_queue.h. Update the loop in
l3_l2_orch_endpoint.h’s signal_wait() to only call device_time_now_ticks()
periodically (for example, after a fixed spin count like InputQueue::peek() and
OutputQueue::reserve()), while still preserving timeout handling through
sys_cnt_elapsed_ns and set_error on timeout.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/simpler/l3_l2_orch_comm.py`:
- Around line 265-280: The onboard reply path in validate_region_create_reply
only checks mapping_bytes for SIM_POSIX_SHM, so the descriptor layout can drift
for onboard exports. Update this function to validate reply.mapping_bytes
against the computed total_bytes for all access profiles, using the existing
helper logic around desc, _align_up, and _checked_add_u64, so both SIM and
onboard replies must match the same region layout.

In `@python/simpler/worker.py`:
- Around line 3784-3788: The onboard import path in
_l3_host_mapped_region_import_onboard is using total_bytes from descriptor
fields instead of the reply’s authoritative mapping_bytes, which can truncate
the import request. Update the call site in worker.py to pass
reply.mapping_bytes for onboard imports, matching the sim path and preserving
any padding or metadata in the exported ACL mapping size.
- Around line 1186-1192: The export-key validation in
`_l3_child_onboard_region_export()` handling leaves an already-created ACL
export open when the key is too long. Update the region onboarding flow in
`worker.py` so that if the `len(export_key)` check fails, the code explicitly
closes/rolls back the export before raising the `RuntimeError`, using the same
cleanup path that would normally run after `region.export_key` is assigned.

---

Nitpick comments:
In `@python/simpler/worker.py`:
- Around line 1226-1230: The best-effort cleanup exception handlers are silently
swallowing failures, which makes leaked shared memory, ACL exports, or mappings
hard to diagnose. Update the affected cleanup paths around
cw.free(region.dev_ptr) and the other direct-region release blocks to catch the
exception, emit a warning to stderr with enough context to identify the cleanup
step, and then continue preserving the original error flow. Apply the same
stderr warning pattern consistently in all listed cleanup handlers rather than
using bare pass.

In `@src/common/platform/include/aicpu/l3_l2_message_queue.h`:
- Around line 793-799: The ensure_live(L3L2QueueOp op) helper in
l3_l2_message_queue.h ignores its op argument and only checks error_.kind, so
either remove the unused parameter from ensure_live and its callers or use
L3L2QueueOp in the check/logging path instead of discarding it with (void)op.
Keep the behavior unchanged while cleaning up the signature in the L3L2 queue
error-handling code.

In `@src/common/platform/include/aicpu/l3_l2_orch_endpoint.h`:
- Around line 271-289: The busy-wait in signal_wait() is re-reading the clock on
every spin, unlike the throttled pattern used in l3_l2_message_queue.h. Update
the loop in l3_l2_orch_endpoint.h’s signal_wait() to only call
device_time_now_ticks() periodically (for example, after a fixed spin count like
InputQueue::peek() and OutputQueue::reserve()), while still preserving timeout
handling through sys_cnt_elapsed_ns and set_error on timeout.

In `@tests/ut/cpp/common/test_l3_l2_orch_comm.cpp`:
- Around line 174-190: The new fixed-layout test for
L3L2RegionCreateRequest/L3L2RegionCreateReply is incomplete compared with the
existing RequestAndResponseAreFixedSizePodDescriptorsOnly coverage. In
LifecycleCreateWireStructsHaveFixedLayout, add offset assertions for the
remaining L3L2RegionCreateRequest fields such as request_bytes, counter_bytes,
and l3_host_pid so the test catches any field reordering or padding regressions,
using the existing offsetof checks alongside the current static_asserts and size
checks.
🪄 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

Run ID: b1906a51-80dc-4f47-ba25-3b281ed89fca

📥 Commits

Reviewing files that changed from the base of the PR and between a18e812 and ed8c2d8.

📒 Files selected for processing (33)
  • docs/hardware/cache-coherency.md
  • docs/l3-l2-message-queue.md
  • docs/l3-l2-orch-comm.md
  • examples/workers/l3/l3_l2_message_queue/kernels/aiv/kernel_queue_transform.cpp
  • examples/workers/l3/l3_l2_message_queue/kernels/orchestration/l3_l2_message_queue_orch.cpp
  • examples/workers/l3/l3_l2_message_queue/test_l3_l2_message_queue.py
  • examples/workers/l3/l3_l2_orch_comm_stream/kernels/orchestration/l3_l2_orch_comm_orch.cpp
  • python/bindings/task_interface.cpp
  • python/bindings/worker_bind.h
  • python/simpler/l3_l2_message_queue.py
  • python/simpler/l3_l2_orch_comm.py
  • python/simpler/worker.py
  • simpler_setup/kernel_compiler.py
  • simpler_setup/toolchain.py
  • src/a2a3/platform/include/aicpu/platform_regs.h
  • src/a5/platform/include/aicpu/platform_regs.h
  • src/common/hierarchical/worker.h
  • src/common/hierarchical/worker_manager.cpp
  • src/common/hierarchical/worker_manager.h
  • src/common/platform/include/aicpu/cache_maintenance.h
  • src/common/platform/include/aicpu/device_time.h
  • src/common/platform/include/aicpu/l3_l2_message_queue.h
  • src/common/platform/include/aicpu/l3_l2_orch_endpoint.h
  • src/common/platform/include/common/l3_l2_orch_comm.h
  • src/common/platform/include/host/l3_l2_orch_region_access.h
  • src/common/platform/onboard/aicpu/cache_ops.cpp
  • src/common/platform/sim/aicpu/cache_ops.cpp
  • tests/ut/cpp/common/test_l3_l2_message_queue.cpp
  • tests/ut/cpp/common/test_l3_l2_orch_comm.cpp
  • tests/ut/cpp/common/test_l3_l2_orch_endpoint.cpp
  • tests/ut/cpp/stubs/test_stubs.cpp
  • tests/ut/py/test_worker/test_l3_l2_message_queue.py
  • tests/ut/py/test_worker/test_l3_l2_orch_comm.py
💤 Files with no reviewable changes (1)
  • simpler_setup/toolchain.py

Comment on lines +265 to +280
def validate_region_create_reply(reply: L3L2RegionCreateReply) -> tuple[int, int]:
desc = reply.desc
if desc.payload_bytes <= 0:
raise RuntimeError("create_l3_l2_region: reply payload_bytes must be positive")
if desc.counter_bytes <= 0 or desc.counter_bytes % 4 != 0:
raise RuntimeError("create_l3_l2_region: reply counter_bytes must be positive and a multiple of 4")
counter_offset = _align_up(desc.payload_bytes, _REGION_LAYOUT_ALIGNMENT)
total_bytes = _checked_add_u64(counter_offset, desc.counter_bytes)
expected_counter_base = _checked_add_u64(desc.payload_base, counter_offset)
if desc.counter_base != expected_counter_base:
raise RuntimeError("create_l3_l2_region: reply counter_base does not match fixed region layout")
if desc.counter_base % _REGION_LAYOUT_ALIGNMENT != 0:
raise RuntimeError("create_l3_l2_region: reply counter_base must be 64-byte aligned")
if reply.access_profile == L3L2RegionAccessProfile.SIM_POSIX_SHM and reply.mapping_bytes != total_bytes:
raise RuntimeError("create_l3_l2_region: sim reply mapping_bytes does not match descriptor layout")
return counter_offset, total_bytes

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

Validate onboard mapping_bytes against the descriptor layout too.

SIM replies reject mismatched mapping_bytes, but onboard replies can advertise a different export size and still import using computed total_bytes. That lets parent-side bounds diverge from the child’s exported GM region size.

Suggested fix
-    if reply.access_profile == L3L2RegionAccessProfile.SIM_POSIX_SHM and reply.mapping_bytes != total_bytes:
-        raise RuntimeError("create_l3_l2_region: sim reply mapping_bytes does not match descriptor layout")
+    if reply.mapping_bytes != total_bytes:
+        raise RuntimeError("create_l3_l2_region: reply mapping_bytes does not match descriptor layout")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def validate_region_create_reply(reply: L3L2RegionCreateReply) -> tuple[int, int]:
desc = reply.desc
if desc.payload_bytes <= 0:
raise RuntimeError("create_l3_l2_region: reply payload_bytes must be positive")
if desc.counter_bytes <= 0 or desc.counter_bytes % 4 != 0:
raise RuntimeError("create_l3_l2_region: reply counter_bytes must be positive and a multiple of 4")
counter_offset = _align_up(desc.payload_bytes, _REGION_LAYOUT_ALIGNMENT)
total_bytes = _checked_add_u64(counter_offset, desc.counter_bytes)
expected_counter_base = _checked_add_u64(desc.payload_base, counter_offset)
if desc.counter_base != expected_counter_base:
raise RuntimeError("create_l3_l2_region: reply counter_base does not match fixed region layout")
if desc.counter_base % _REGION_LAYOUT_ALIGNMENT != 0:
raise RuntimeError("create_l3_l2_region: reply counter_base must be 64-byte aligned")
if reply.access_profile == L3L2RegionAccessProfile.SIM_POSIX_SHM and reply.mapping_bytes != total_bytes:
raise RuntimeError("create_l3_l2_region: sim reply mapping_bytes does not match descriptor layout")
return counter_offset, total_bytes
def validate_region_create_reply(reply: L3L2RegionCreateReply) -> tuple[int, int]:
desc = reply.desc
if desc.payload_bytes <= 0:
raise RuntimeError("create_l3_l2_region: reply payload_bytes must be positive")
if desc.counter_bytes <= 0 or desc.counter_bytes % 4 != 0:
raise RuntimeError("create_l3_l2_region: reply counter_bytes must be positive and a multiple of 4")
counter_offset = _align_up(desc.payload_bytes, _REGION_LAYOUT_ALIGNMENT)
total_bytes = _checked_add_u64(counter_offset, desc.counter_bytes)
expected_counter_base = _checked_add_u64(desc.payload_base, counter_offset)
if desc.counter_base != expected_counter_base:
raise RuntimeError("create_l3_l2_region: reply counter_base does not match fixed region layout")
if desc.counter_base % _REGION_LAYOUT_ALIGNMENT != 0:
raise RuntimeError("create_l3_l2_region: reply counter_base must be 64-byte aligned")
if reply.mapping_bytes != total_bytes:
raise RuntimeError("create_l3_l2_region: reply mapping_bytes does not match descriptor layout")
return counter_offset, total_bytes
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/l3_l2_orch_comm.py` around lines 265 - 280, The onboard reply
path in validate_region_create_reply only checks mapping_bytes for
SIM_POSIX_SHM, so the descriptor layout can drift for onboard exports. Update
this function to validate reply.mapping_bytes against the computed total_bytes
for all access profiles, using the existing helper logic around desc, _align_up,
and _checked_add_u64, so both SIM and onboard replies must match the same region
layout.

Comment thread python/simpler/worker.py
Comment on lines +1186 to +1192
export_key = _l3_child_onboard_region_export(dev_ptr, total_bytes, request.l3_host_pid)
if isinstance(export_key, str):
export_key = export_key.encode("utf-8")
export_key = bytes(export_key).split(b"\x00", 1)[0]
if len(export_key) >= ACL_IPC_EXPORT_KEY_BYTES:
raise RuntimeError("CTRL_L3_L2_REGION_CREATE ACL IPC export key is too long")
region.export_key = export_key

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

Close the ACL export if export-key validation fails.

_l3_child_onboard_region_export() has already created an export here, but region.export_key is only assigned after the length check. If the key is too long, rollback frees dev_ptr without closing the ACL export.

Proposed fix
             export_key = _l3_child_onboard_region_export(dev_ptr, total_bytes, request.l3_host_pid)
             if isinstance(export_key, str):
                 export_key = export_key.encode("utf-8")
             export_key = bytes(export_key).split(b"\x00", 1)[0]
+            region.export_key = export_key
             if len(export_key) >= ACL_IPC_EXPORT_KEY_BYTES:
                 raise RuntimeError("CTRL_L3_L2_REGION_CREATE ACL IPC export key is too long")
-            region.export_key = export_key
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export_key = _l3_child_onboard_region_export(dev_ptr, total_bytes, request.l3_host_pid)
if isinstance(export_key, str):
export_key = export_key.encode("utf-8")
export_key = bytes(export_key).split(b"\x00", 1)[0]
if len(export_key) >= ACL_IPC_EXPORT_KEY_BYTES:
raise RuntimeError("CTRL_L3_L2_REGION_CREATE ACL IPC export key is too long")
region.export_key = export_key
export_key = _l3_child_onboard_region_export(dev_ptr, total_bytes, request.l3_host_pid)
if isinstance(export_key, str):
export_key = export_key.encode("utf-8")
export_key = bytes(export_key).split(b"\x00", 1)[0]
region.export_key = export_key
if len(export_key) >= ACL_IPC_EXPORT_KEY_BYTES:
raise RuntimeError("CTRL_L3_L2_REGION_CREATE ACL IPC export key is too long")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/worker.py` around lines 1186 - 1192, The export-key validation
in `_l3_child_onboard_region_export()` handling leaves an already-created ACL
export open when the key is too long. Update the region onboarding flow in
`worker.py` so that if the `len(export_key)` check fails, the code explicitly
closes/rolls back the export before raising the `RuntimeError`, using the same
cleanup path that would normally run after `region.export_key` is assigned.

Comment thread python/simpler/worker.py Outdated
Comment on lines +3784 to +3788
handle = _l3_host_mapped_region_import_onboard(
int(reply.device_id),
reply.export_key.decode("utf-8", "strict"),
int(total_bytes),
# Onboard imports use peer access so one parent policy covers same-device and cross-device

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

Use the reply’s mapping_bytes for onboard imports.

The sim path imports reply.mapping_bytes, but the onboard path imports total_bytes derived from descriptor fields. If the exported ACL mapping size ever includes padding/metadata, this truncates the import request despite the reply carrying the authoritative mapping size.

Proposed fix
                     handle = _l3_host_mapped_region_import_onboard(
                         int(reply.device_id),
                         reply.export_key.decode("utf-8", "strict"),
-                        int(total_bytes),
+                        int(reply.mapping_bytes),
                         # Onboard imports use peer access so one parent policy covers same-device and cross-device
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
handle = _l3_host_mapped_region_import_onboard(
int(reply.device_id),
reply.export_key.decode("utf-8", "strict"),
int(total_bytes),
# Onboard imports use peer access so one parent policy covers same-device and cross-device
handle = _l3_host_mapped_region_import_onboard(
int(reply.device_id),
reply.export_key.decode("utf-8", "strict"),
int(reply.mapping_bytes),
# Onboard imports use peer access so one parent policy covers same-device and cross-device
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/simpler/worker.py` around lines 3784 - 3788, The onboard import path
in _l3_host_mapped_region_import_onboard is using total_bytes from descriptor
fields instead of the reply’s authoritative mapping_bytes, which can truncate
the import request. Update the call site in worker.py to pass
reply.mapping_bytes for onboard imports, matching the sim path and preserving
any padding or metadata in the exported ACL mapping size.

ccyywwen added 6 commits July 10, 2026 10:56
- Convert non-null L3-L2 endpoint and queue outputs to references
- Harden descriptor arithmetic, magic constants, and alignment helpers
- Move queue cursors into direction-local queue state and keep release lookup O(1)
- Update examples, docs, and focused C++ unit coverage
- Add the direct parent data path design for L3-L2 orch comm
- Add an implementation plan with lifecycle controls, sim/onboard migration split, cleanup ordering, and validation scope
- Add lifecycle create/release controls and fixed create wire structs
- Implement sim L2 Host owned region allocation with L3 Host mapping helpers
- Route sim payload and counter operations through mapped-region helpers
- Keep queue staging behavior behind primitive payload transfer
- Add focused Python and C++ coverage for lifecycle and mapped access
- Describe L3 Host mapped-region behavior for simulation platforms
- Clarify onboard payload buffers and L2 Host-mediated operations
- Move queue payload-transfer staging wording to the primitive backend
- Split queue input enqueue payload handling to satisfy ruff branch limits.
- Narrow optional L3 Host mapping and SharedMemory buffer types for pyright.
- Apply ruff import ordering and test type narrowing.
- Export child-owned onboard GM regions through ACL IPC and import them in the L3 Host parent.
- Route onboard payload and counter operations through parent-side direct helpers using ACL copies.
- Document the selected counter path for the onboard direct data path.
@ccyywwen ccyywwen force-pushed the l3-l2-comm-datapath-refactor-onboard-impl branch 2 times, most recently from 016a679 to 688f053 Compare July 10, 2026 08:16
- Keep ACL IPC export keys as bytes across bindings and worker cleanup/import paths.

- Enable ACL IPC peer access only for a2a3 so A5 imports avoid the unsupported flag.

- Keep queue unit tests on the legacy fake-client path while direct-path coverage stays in orch comm tests.

- Use explicit uint64 overflow checks so macOS C++ UTs reject wrapped payload ranges.
@ccyywwen ccyywwen force-pushed the l3-l2-comm-datapath-refactor-onboard-impl branch from 688f053 to b6699e4 Compare July 10, 2026 08:23
- Remove the persistent L3-L2 child shared-memory service bootstrap and steady-state command path from production code.

- Route primitive and queue behavior through the direct L3 Host mapped backend and keep behavior tests for timeout, poison, STOP, ERROR, backpressure, and peer abort semantics.

- Drop old service sources and service-specific tests from production and unit-test builds.
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.

2 participants