Skip to content

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

Open
ccyywwen wants to merge 8 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 8 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 builds on the previous PR #1291 and finishes
the onboard side of the same direct-data-path model.

Relative to the sim refactor PR, this change:

  • Extends L3-L2 primitive regions to onboard platforms with ACL IPC.
    The L2 Host allocates the child-owned GM region, exports it through ACL IPC,
    authorizes the L3 Host process, and the L3 Host imports it for direct parent
    operations.

  • Routes onboard payload and counter operations through the L3 Host direct
    backend.
    Payload reads/writes and counter notify/test/wait no longer go through the
    old L2 Host service command path. Onboard uses ACL copy operations against
    the imported GM region; sim keeps using the parent-side mapped backing.

  • Handles a2a3/a5 ACL IPC differences.
    ACL IPC peer access is enabled only where supported, so a5 imports avoid the
    unsupported peer-access flag.

  • Removes the old persistent child service path.
    This drops the request/response service structs, service bootstrap/shutdown
    C APIs, worker-side service lifecycle plumbing, service implementation, and
    service-specific C++ runner tests.

  • Tightens lifecycle and cleanup behavior.
    Region create rolls back child allocations when reply decode/import/validation
    fails, mapped-region close remains retryable on cleanup failure, and primitive
    helpers release the GIL around blocking mapped-region operations.

  • Updates Python/C++ tests and docs to cover the direct mapped backend as the
    shared model across sim and onboard.

Relationship to the sim refactor PR

The previous PR introduced the public region descriptor model and the direct
L3 Host mapped data path for simulation. This PR preserves that API and swaps
out the remaining onboard-only L2 Host-mediated steady-state path for the same
parent-side direct primitive model.

After this PR, both sim and onboard use the same high-level behavior:

  • L2 still owns the descriptor-visible payload/counter addresses consumed by
    the L2 AICPU endpoint.
  • L3 Host operations use private parent-side transport metadata.
  • Queue payload movement delegates to the primitive region backend.
  • Poisoning, timeout, STOP, ERROR, backpressure, and peer-abort semantics remain
    covered at the wrapper/unit-test level.

@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: c162e6eb-b7ce-44ba-b10b-3ee53acb5e11

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
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.
Title check ✅ Passed The title clearly points to the onboard L3-L2 orch comm data-path refactor, despite the typo.
Description check ✅ Passed The description matches the onboard direct data-path work, including ACL IPC, routing changes, cleanup, docs, and 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.

@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 thread python/simpler/l3_l2_orch_comm.py Outdated
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 ccyywwen force-pushed the l3-l2-comm-datapath-refactor-onboard-impl branch 3 times, most recently from 688f053 to b6699e4 Compare July 10, 2026 08:23
ccyywwen added 7 commits July 13, 2026 16:45
- 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.
- 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.
- 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.
@ccyywwen ccyywwen force-pushed the l3-l2-comm-datapath-refactor-onboard-impl branch 2 times, most recently from 7902bf0 to 7284f7b Compare July 13, 2026 09:42
- Release the GIL around primitive L3 Host mapped-region helpers and keep mapped-region close retryable on cleanup failure.

- Roll back child regions when create reply decode or validation fails after allocation.

- Sync docs and focused unit coverage with the direct mapped data path.
@ccyywwen ccyywwen force-pushed the l3-l2-comm-datapath-refactor-onboard-impl branch from 7284f7b to ec9fafe Compare July 13, 2026 10:25
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