Skip to content

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

Open
doraemonmj wants to merge 2 commits into
hw-native-sys:mainfrom
doraemonmj:dfxbackpressure
Open

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

Conversation

@doraemonmj

@doraemonmj doraemonmj commented Jul 9, 2026

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).

Dual-Signal Backpressure Architecture

This implementation uses a dual-signal freeze mechanism that provides
independent control for both ready-queue-full (push gate) and
free-queue-empty (pop gate) scenarios:

  • Push Gate (RQ full): rq_freeze_active + rq_contended

    • Device marks rq_contended when ready queue is full
    • Host opens rq_freeze_active to freeze all lanes at their push gates
    • Host releases once ready queues are fully drained
  • Pop Gate (FQ empty): fq_freeze_active + fq_contended

    • Device marks fq_contended when free queue is empty
    • Host opens fq_freeze_active to freeze all lanes at their pop gates
    • Host releases once free queues are refilled to capacity

Key Components

  1. Per-subsystem coordination block (DfxBackpressureHeader):

    • Embedded in every DFX DataHeader
    • Four signals: rq_freeze_active, rq_contended, fq_freeze_active, fq_contended
    • Physical per-subsystem (each subsystem has its own shared-memory region)
  2. Host-side global-sync freeze state machine (update_backpressure_freeze):

    • On real buffer contention, device lane raises leader signal
    • Host opens corresponding freeze so every AICPU lane parks at its gate
    • Host releases once queues are drained/refilled — one aligned common-mode gap
  3. Unified timeout configuration:

    • PLATFORM_DFX_BACKPRESSURE_TIMEOUT_CYCLES = 30s @ 1000 MHz
    • Applies to both push and pop gates
    • Prevents infinite spin on host crash or hardware failure
  4. Device-side coordination (profiler_device_engine.h):

    • push_freeze_barrier(): park at push gate during rq_freeze_active
    • pop_freeze_barrier(): park at pop gate during fq_freeze_active
    • mark_rq_contended(): signal RQ-full contention
    • mark_fq_contended(): signal FQ-empty contention
  5. Subsystem integration:

    • All five DFX subsystems use the unified DfxBackpressureHeader
    • tensor_dump adds arena guard: dfx_arena_barrier prevents lapping
    • Consistent drop accounting via account_dropped()

Design Advantages

  1. Independent gate control: RQ and FQ freeze independently for precision
  2. Global synchronization: All lanes park at same gate type → aligned gap
  3. Timeout protection: 30s limit prevents indefinite hangs
  4. Zero overhead when disabled: Mechanism idle unless contention occurs
  5. Cross-subsystem consistency: Same header/semantics for all DFX collectors

Test Results

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

1. flag-OFF has no hot-path overhead — benchmarked merge-base 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
  • No systematic regression; the mechanism is free when not enabled

2. flag-ON dual-signal mechanism works correctly:

  • RQ-full contention correctly triggers rq_freeze_active → lanes park
  • FQ-empty contention correctly triggers fq_freeze_active → lanes park
  • Timeout protection prevents infinite waits
  • All subsystems handle both gate types safely

3. Full subsystem coverage — ran each DFX smoke with
--enable-dfx-backpressure and buffer rotation forced:

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.

Configuration Notes

  • Backpressure disabled by default (drops as before)
  • Enable via --enable-dfx-backpressure flag
  • 30-second timeout configurable via PLATFORM_DFX_BACKPRESSURE_TIMEOUT_CYCLES
  • System counter frequency: 1000 MHz (see PLATFORM_PROF_SYS_CNT_FREQ)

close #997

@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: c0e3647c-db37-44be-a501-fad6c7cfd4dd

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
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 Clear and specific: it summarizes the new unified block-on-contention backpressure across DFX subsystems.
Description check ✅ Passed It accurately describes the unified backpressure mechanism and the gated DFX subsystems changed in the PR.

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 Outdated
Comment thread src/common/platform/include/aicpu/profiler_device_engine.h Outdated
Comment thread src/common/platform/include/aicpu/profiler_device_engine.h Outdated
Comment thread src/common/platform/include/aicpu/profiler_device_engine.h Outdated
Comment thread src/common/platform/include/common/dfx_backpressure_device.h
Comment thread src/common/platform/include/common/dfx_backpressure_device.h Outdated
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 Outdated
Comment thread src/common/platform/include/host/tensor_dump_collector.h Outdated
@doraemonmj doraemonmj force-pushed the dfxbackpressure branch 10 times, most recently from 3568348 to 3b92bb3 Compare July 15, 2026 04:40
- Implement dual-signal backpressure: rq_freeze_active + fq_freeze_active
- Add host-side freeze release logic in profiler_base.h
- Integrate backpressure into DFX subsystems (PMU, L2 swimlane, dep_gen,
  scope_stats, args_dump)
- Update profiler_device_engine.h with dual-gate mechanism
- Add backpressure test cases in test_buffer_pool_manager.cpp
- Fix missing DfxBackpressureHeader member in test_profiler_base.cpp
- Set each subsystem's kBackpressureWaitCycles to 30s, expressed
  frequency-relative (PLATFORM_PROF_SYS_CNT_FREQ * 30) so the duration is
  correct on both a2a3 (50 MHz) and a5 (1000 MHz) system counters

Configures a 30-second backpressure timeout for both push gate (RQ full)
and pop gate (FQ empty) scenarios. Prevents infinite spin on host crash or
hardware failure while ensuring global synchronization freeze across all
AICPU lanes.
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.

[Feature] DFX global backpressure mode (block-on-contention instead of dropping records)

1 participant