Skip to content

feat(dfx): unified block-on-contention backpressure across DFX subsystems#1313

Open
doraemonmj wants to merge 1 commit into
hw-native-sys:mainfrom
doraemonmj:dfxbackpressure
Open

feat(dfx): unified block-on-contention backpressure across DFX subsystems#1313
doraemonmj wants to merge 1 commit into
hw-native-sys:mainfrom
doraemonmj:dfxbackpressure

Conversation

@doraemonmj

Copy link
Copy Markdown
Contributor

What

Unify the five DFX subsystems (L2 swimlane, PMU, dep_gen, scope_stats,
tensor_dump) onto a single block-on-contention backpressure mechanism,
gated behind enable_dfx_backpressure (default off — drops as before).

  • A per-subsystem DfxBackpressureHeader{block_on_contention, freeze_active, contended} is embedded in every DFX DataHeader.
  • Host-side global-sync freeze state machine (update_backpressure_freeze):
    on real buffer contention a device lane raises the leader signal, the host
    opens a freeze so every AICPU lane parks at its next buffer-switch gate,
    then releases once all lanes drained and free_queues refilled — one
    lane-aligned common-mode gap instead of scattered per-lane record loss.
  • tensor_dump additionally guards its payload arena: a predictive lap check
    (dfx_arena_barrier) flushes + parks + resets the epoch before overwriting
    not-yet-drained payloads; freeze release adds a collector_inflight()==0
    predicate so the device cannot lap the arena before the collector has pulled
    it into host memory.

Test results

Verified on a2a3 silicon (device isolated via task-submit).

1. flag-OFF has no hot-path overhead — benchmarked merge-base (no
backpressure code) vs this change, both flag-off, same device, 100 rounds,
8 cases (tensormap_and_ringbuffer), all 8/8 pass:

  • max |ΔEffective| = 2.18% — entirely within run-to-run noise.
  • Heaviest case qwen3_14b_decode/StressBatch16Seq3500: ΔEffective −0.03%.
  • No systematic regression; the mechanism is free when not enabled.

2. flag-ON is safe across all 5 subsystems — ran each subsystem's DFX
smoke with --enable-dfx-backpressure and all records-per-buffer knobs
shrunk to 4 (forces buffer rotation / contention):

subsystem result
dep_gen pass, no hang
l2_swimlane pass, no hang
pmu pass, no hang
scope_stats pass, no hang (asserts dropped == 0)
tensor_dump (args_dump) pass, no hang

No HandleTaskTimeout / Task Allocator Deadlock / 507018 /
Timeout(cycles) on any run — the block path is deadlock-free and loses no
records when engaged. Heavy-contention drop→0 evidence (swimlane 4590→0,
PMU 28744→0) was captured during development.

Re-verified the full flag-ON matrix after rebasing onto latest main
(which landed L2-swimlane rotation/wmb changes) — all 5 still pass, no hang.

@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: 917ffa64-8156-465a-9eec-528129b94a2f

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 change adds opt-in DFX backpressure configuration, extends shared-memory headers and collector initialization, and coordinates device contention with host queue draining, freeze release, collector inflight tracking, and tensor-dump arena epoch barriers.

Changes

DFX backpressure configuration

Layer / File(s) Summary
Configuration and runner plumbing
conftest.py, python/bindings/task_interface.cpp, python/simpler/worker.py, simpler_setup/scene_test.py, src/common/task_interface/call_config.h, src/common/platform/.../device_runner_base.*
Adds enable_dfx_backpressure to the Python/API configuration, mailbox wire format, pytest pipeline, and onboard/simulation runner state.

Shared-memory and runtime coordination

Layer / File(s) Summary
Shared-memory contracts and sizing
src/common/platform/include/common/*, src/a2a3/platform/include/common/*, src/a5/platform/include/common/*
Adds DfxBackpressureHeader, epoch offsets, shared-memory fields, and buffer sizing assertions across DFX subsystems.
Collector initialization wiring
src/common/platform/include/host/*collector.h, src/common/platform/shared/host/*collector.cpp, src/a2a3/.../device_runner.cpp, src/a5/.../device_runner.cpp
Extends collector initialization APIs and passes the contention flag into onboard and simulation collectors.
Host freeze coordination
src/common/platform/include/host/profiler_base.h, src/common/platform/include/host/buffer_pool_manager.h, src/common/platform/include/aicpu/profiler_device_engine.h
Adds device contention signaling, collector-inflight accounting, queue draining, and host-controlled freeze release.
Tensor arena contention barrier
src/common/platform/shared/aicpu/tensor_dump_aicpu.cpp
Flushes metadata and waits for host release before resetting tensor arena epochs when payload writes would lap the current epoch.

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

Possibly related issues

  • simpler issue 997 — Covers the opt-in global DFX backpressure mode implemented across the five DFX subsystems.

Possibly related PRs

Poem

A rabbit hops where buffers flow,
Freeze the lanes when pressures grow.
Queues drain clean, epochs reset,
No arena payloads overwrite yet.
“Backpressure!” I thump with cheer—
The DFX path is hopping clear!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.56% 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 clearly summarizes the main change: unified block-on-contention backpressure across DFX subsystems.
Description check ✅ Passed The description matches the changeset and describes the unified DFX backpressure work and tensor_dump protection.
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 gemini-code-assist 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.

Code Review

This pull request introduces a unified DFX backpressure mechanism (block-on-contention and global-sync freeze) across several DFX subsystems, including L2 swimlane, PMU, tensor dump, dep_gen, and scope_stats. The changes span configuration structures, Python bindings, and host/device-side coordination logic. The reviewer provided critical feedback to address issues in the tight spin loops within profiler_device_engine.h, where reading the system counter on every iteration causes high MMIO overhead and can lead to premature timeouts; gating these reads periodically resolves both issues. Additionally, the reviewer recommended adding read memory barriers (rmb()) in dfx_backpressure_device.h to ensure proper memory visibility on weak-ordering architectures like aarch64, and optimizing host-side checks in profiler_base.h by consolidating multiple DMA reads into a single contiguous operation on non-SVM platforms.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/common/platform/include/aicpu/profiler_device_engine.h
Comment thread src/common/platform/include/aicpu/profiler_device_engine.h
Comment thread src/common/platform/include/aicpu/profiler_device_engine.h
Comment thread src/common/platform/include/aicpu/profiler_device_engine.h
Comment thread src/common/platform/include/common/dfx_backpressure_device.h
Comment thread src/common/platform/include/common/dfx_backpressure_device.h
Comment thread src/common/platform/include/common/dfx_backpressure_device.h
Comment thread src/common/platform/include/host/profiler_base.h

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
simpler_setup/scene_test.py (1)

1335-1360: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Standalone run_module path is missing --enable-dfx-backpressure.

The pytest path (test_run) correctly reads and threads enable_dfx_backpressure, but the standalone run_module entry point neither registers the --enable-dfx-backpressure argparse argument nor forwards it to run_class_cases. All other DFX flags (--enable-l2-swimlane, --dump-args, --enable-dep-gen, --enable-pmu, --enable-scope-stats, --enable-swimlane-overhead) are present in both paths. Standalone users will silently never get backpressure since run_class_cases defaults enable_dfx_backpressure=False.

🔧 Add the missing argparse argument and forwarding

Add the argparse argument near the other DFX flags (after --enable-dep-gen):

     parser.add_argument(
         "--enable-dep-gen",
         action="store_true",
         help="Enable dep_gen capture (SubmitTrace ring, first round only)",
     )
+    parser.add_argument(
+        "--enable-dfx-backpressure",
+        action="store_true",
+        default=False,
+        help="DFX backpressure: block-on-contention instead of dropping records "
+        "(currently wired for L2 swimlane). Requires a diagnostic (e.g. --enable-l2-swimlane).",
+    )
     parser.add_argument(

Then forward it in the run_class_cases call inside run_module:

                         run_class_cases(
                             worker,
                             inst,
                             [case],
                             callable_obj=callable_obj,
                             sub_handles=sub_handles,
                             rounds=args.rounds,
                             skip_golden=args.skip_golden,
                             enable_l2_swimlane=args.enable_l2_swimlane,
                             enable_dump_args=args.dump_args,
                             enable_pmu=args.enable_pmu,
                             enable_dep_gen=args.enable_dep_gen,
                             enable_scope_stats=args.enable_scope_stats,
+                            enable_dfx_backpressure=args.enable_dfx_backpressure,
                             enable_swimlane_overhead=args.enable_swimlane_overhead,
                         )

Also applies to: 1549-1563

🤖 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 `@simpler_setup/scene_test.py` around lines 1335 - 1360, Standalone run_module
lacks the DFX backpressure option and does not pass it through. Add an
--enable-dfx-backpressure argparse flag alongside the other DFX options in
run_module, then read its value and forward it as enable_dfx_backpressure in the
run_class_cases call; keep behavior consistent with test_run.
🧹 Nitpick comments (2)
src/common/platform/include/aicpu/profiler_device_engine.h (1)

53-59: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Add spin_relax() to block-mode spin loops.

Both block-mode contention paths (wait_for_ready_queue_space and wait_for_free_queue_entry) spin via continue without a relax hint, unlike peer_freeze_barrier and wait_for_release in dfx_backpressure_device.h which both call spin_relax(). The tight load loop wastes power on aarch64 and pins a core at 100% on x86_64 sim. Adding dfx_backpressure::spin_relax() before continue is consistent with the other DFX spin paths and is a one-line change per loop.

♻️ Proposed fix for both spin loops

In wait_for_ready_queue_space (line 56-58):

             if (dfx_backpressure::block_on_contention(header)) {
                 dfx_backpressure::mark_contended(header, &contended_signalled);
+                dfx_backpressure::spin_relax();
                 continue;
             }

In wait_for_free_queue_entry (line 92-94):

             if (dfx_backpressure::block_on_contention(header)) {
                 dfx_backpressure::mark_contended(header, &contended_signalled);
+                dfx_backpressure::spin_relax();
                 continue;
             }

Also applies to: 89-95

🤖 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/profiler_device_engine.h` around lines 53 -
59, Add dfx_backpressure::spin_relax() immediately before continue in both
block-mode spin loops, wait_for_ready_queue_space and wait_for_free_queue_entry,
matching the existing relaxation pattern used by peer_freeze_barrier and
wait_for_release.
src/common/platform/include/common/dfx_backpressure_device.h (1)

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

Consider adding a block_on_contention guard to mark_contended for API consistency.

peer_freeze_barrier and wait_for_release both self-guard with block_on_contention(header), but mark_contended only checks *signalled and header != nullptr. If called in drop mode, it would write contended = 1 to shared memory unnecessarily. Current callers (e.g., dfx_arena_barrier in tensor_dump_aicpu.cpp) gate before calling, so this isn't a live bug — but the inconsistency means the function's contract relies on caller discipline rather than being self-enforcing like its peers.

♻️ Optional: add self-guard to `mark_contended`
 template <typename Header>
 inline void mark_contended(Header *header, bool *signalled) {
-    if (!*signalled && header != nullptr) {
+    if (!*signalled && block_on_contention(header)) {
         header->backpressure.contended = 1;
         *signalled = true;
     }
 }
🤖 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/common/dfx_backpressure_device.h` around lines 91
- 97, mark_contended should self-enforce the block-on-contention policy like
peer_freeze_barrier and wait_for_release. Update mark_contended to require
block_on_contention(header) before writing header->backpressure.contended, while
preserving the existing signalled and null-header checks.
🤖 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 `@src/common/platform/include/host/profiler_base.h`:
- Around line 442-443: Make the freeze state accessed by the drain threads and
mgmt_replenish_loop use a host-side atomic or mutex-protected variable instead
of directly sharing header->backpressure.freeze_active; update the device header
from that synchronized host state with the required memory ordering, and have
the drain path consult the synchronized state before calling top_up_free_queue.

In `@src/common/platform/include/host/tensor_dump_collector.h`:
- Around line 222-225: Update the block_on_contention documentation in the
tensor dump collector header to state that arena-lap protection is included
through the epoch-barrier behavior; clarify that only payloads exceeding the
per-thread payload arena remain subject to truncation, removing the statement
that the payload arena is out of scope.

---

Outside diff comments:
In `@simpler_setup/scene_test.py`:
- Around line 1335-1360: Standalone run_module lacks the DFX backpressure option
and does not pass it through. Add an --enable-dfx-backpressure argparse flag
alongside the other DFX options in run_module, then read its value and forward
it as enable_dfx_backpressure in the run_class_cases call; keep behavior
consistent with test_run.

---

Nitpick comments:
In `@src/common/platform/include/aicpu/profiler_device_engine.h`:
- Around line 53-59: Add dfx_backpressure::spin_relax() immediately before
continue in both block-mode spin loops, wait_for_ready_queue_space and
wait_for_free_queue_entry, matching the existing relaxation pattern used by
peer_freeze_barrier and wait_for_release.

In `@src/common/platform/include/common/dfx_backpressure_device.h`:
- Around line 91-97: mark_contended should self-enforce the block-on-contention
policy like peer_freeze_barrier and wait_for_release. Update mark_contended to
require block_on_contention(header) before writing
header->backpressure.contended, while preserving the existing signalled and
null-header 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: b20556bc-c604-4553-adf5-1374657a04eb

📥 Commits

Reviewing files that changed from the base of the PR and between 1111660 and 230e9de.

📒 Files selected for processing (41)
  • conftest.py
  • python/bindings/task_interface.cpp
  • python/simpler/worker.py
  • simpler_setup/scene_test.py
  • src/a2a3/platform/include/common/dep_gen.h
  • src/a2a3/platform/include/common/l2_swimlane_profiling.h
  • src/a2a3/platform/include/common/platform_config.h
  • src/a2a3/platform/include/common/pmu_profiling.h
  • src/a2a3/platform/include/common/tensor_dump.h
  • src/a2a3/platform/include/host/pmu_collector.h
  • src/a2a3/platform/onboard/host/device_runner.cpp
  • src/a2a3/platform/shared/host/pmu_collector.cpp
  • src/a2a3/platform/sim/host/device_runner.cpp
  • src/a5/platform/include/common/dep_gen.h
  • src/a5/platform/include/common/l2_swimlane_profiling.h
  • src/a5/platform/include/common/pmu_profiling.h
  • src/a5/platform/include/common/tensor_dump.h
  • src/a5/platform/include/host/pmu_collector.h
  • src/a5/platform/onboard/host/device_runner.cpp
  • src/a5/platform/shared/host/pmu_collector.cpp
  • src/a5/platform/sim/host/device_runner.cpp
  • src/common/platform/include/aicpu/profiler_device_engine.h
  • src/common/platform/include/common/dfx_backpressure_device.h
  • src/common/platform/include/common/scope_stats.h
  • src/common/platform/include/host/buffer_pool_manager.h
  • src/common/platform/include/host/dep_gen_collector.h
  • src/common/platform/include/host/l2_swimlane_collector.h
  • src/common/platform/include/host/profiler_base.h
  • src/common/platform/include/host/scope_stats_collector.h
  • src/common/platform/include/host/tensor_dump_collector.h
  • src/common/platform/onboard/host/device_runner_base.cpp
  • src/common/platform/onboard/host/device_runner_base.h
  • src/common/platform/shared/aicpu/l2_swimlane_collector_aicpu.cpp
  • src/common/platform/shared/aicpu/tensor_dump_aicpu.cpp
  • src/common/platform/shared/host/dep_gen_collector.cpp
  • src/common/platform/shared/host/l2_swimlane_collector.cpp
  • src/common/platform/shared/host/scope_stats_collector.cpp
  • src/common/platform/shared/host/tensor_dump_collector.cpp
  • src/common/platform/sim/host/device_runner_base.cpp
  • src/common/platform/sim/host/device_runner_base.h
  • src/common/task_interface/call_config.h

Comment thread src/common/platform/include/host/profiler_base.h
Comment thread src/common/platform/include/host/tensor_dump_collector.h Outdated
@doraemonmj doraemonmj force-pushed the dfxbackpressure branch 2 times, most recently from 046005f to 48a8278 Compare July 10, 2026 07:46
…tems

Add a per-subsystem DfxBackpressureHeader{block_on_contention, freeze_active,
contended} embedded in every DFX DataHeader, plus a host-side global-sync freeze
state machine (update_backpressure_freeze). On real buffer contention a device
lane raises the leader signal; the host opens a freeze so every AICPU lane parks
at its next buffer-switch gate, then releases once all lanes drained and
free_queues refilled — one lane-aligned common-mode gap instead of scattered
per-lane sparseness. Gated behind enable_dfx_backpressure (default off, drops as
before).

tensor_dump additionally guards its payload arena: a pre-write predictive lap
check (dfx_arena_barrier) flushes + parks + resets the epoch before overwriting
not-yet-drained payloads, and the freeze release adds a per-subsystem predicate
(collector_inflight()==0) so the device cannot lap the arena before the
collector has synchronously pulled it into host memory.
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