Refactor(a5): align profiling stack with a2a3 (host CRTP + stable ring) - #777
Merged
ChaoWao merged 1 commit intoMay 18, 2026
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the profiling framework for the a5 architecture, centralizing host-side infrastructure for PMU, L2Perf, and TensorDump collectors. Key architectural changes include migrating profiling state from the runtime handshake to KernelArgs, introducing stable AICore staging rings to decouple writes from buffer rotations, and implementing a host-shadow transport mechanism to support systems without SVM. Review feedback recommends adding warning logs for null headers during buffer switches and utilizing store barriers when initializing hardware registers to prevent race conditions on weak memory model architectures.
ChaoZheng109
force-pushed
the
refactor/a5-profiling-framework-alignment
branch
4 times, most recently
from
May 18, 2026 02:52
c0630d2 to
0572269
Compare
…ICore ring, profiling off Handshake) Brings a5 to the same shape as a2a3's PR [hw-native-sys#705](hw-native-sys#705) / [hw-native-sys#709](hw-native-sys#709) / [hw-native-sys#714](hw-native-sys#714): host-side collectors share a ProfilerBase<Derived, Module> + BufferPoolManager<Module> framework; AICore writes through a stable per-core L2PerfAicoreRing / PmuAicoreRing decoupled from AICPU buffer rotation; profiling state moves off Handshake onto KernelArgs + AICore platform-owned slots (aicore_profiling_state.h). a5's transport channel deviates only in MemoryOps carrying copy_to_device / copy_from_device, the mgmt loop mirroring the shm region per tick, and release_owned_buffers freeing the paired host shadow. AICore now resolves its own PMU MMIO base at kernel entry directly from KernelArgs::regs[get_physical_core_id()] (the per-physical-core register-base table the host already fills for AICPU), instead of indexing a separate pmu_reg_addrs table that AICPU filled during handshake. The resolved base is valid from Phase 1 onward, so aicore_execute caches it at Phase 3 alongside the rings rather than re-reading per PMU record. Drops KernelArgs::pmu_reg_addrs, set/get_platform_pmu_reg_addrs, and the corresponding host-side table allocation in PmuCollector.
ChaoZheng109
force-pushed
the
refactor/a5-profiling-framework-alignment
branch
from
May 18, 2026 03:00
0572269 to
a5a594b
Compare
ChaoWao
approved these changes
May 18, 2026
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
May 21, 2026
Port the tiered L2 swimlane perf_level feature from hw-native-sys#782 (a2a3-only) to the a5 platform, so a5 onboard and a5sim now honor the integer perf_level (0-4) instead of treating --enable-l2-swimlane as a plain boolean. Mirror the a2a3 wiring on a5: - L2PerfDataHeader::l2_perf_level carries the level into shared memory; AICPU promotes it in l2_perf_aicpu_init and exposes it via get_l2_perf_level(). - Host-side L2PerfCollector caches the level to gate JSON sections and stamps the JSON "version" field directly from perf_level. - Apply level gates throughout AICPU code paths: skip dispatch/finish timestamps and fanout copies below AICPU_TIMING, scheduler phase records below SCHED_PHASES, and orchestrator phase records below ORCH_PHASES. - Plumb perf_level through DeviceRunner / pto_runtime_c_api on both onboard and sim backends. - Move l2_perf_aicpu_init out of the dispatch one-time-init block into SchedulerContext::init() in scheduler_cold_path.cpp, matching a2a3 so the orchestrator thread reads a promoted level when caching rt->orchestrator.l2_perf_level. - Remove the end-of-function wmb() in l2_perf_aicpu_record_phase (introduced by hw-native-sys#777, not present in a2a3). Measured ~1.1 ms reduction in L4 orch_cost on paged_attention_unroll Case1. Update docs (l2-swimlane-profiling.md, profiling_levels.md, testing.md) to drop the "a5 is boolean-only" caveat and document the unified integer interface across a2a3 and a5.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
May 22, 2026
Port the tiered L2 swimlane perf_level feature from hw-native-sys#782 (a2a3-only) to the a5 platform, so a5 onboard and a5sim now honor the integer perf_level (0-4) instead of treating --enable-l2-swimlane as a plain boolean. Mirror the a2a3 wiring on a5: - L2PerfDataHeader::l2_perf_level carries the level into shared memory; AICPU promotes it in l2_perf_aicpu_init and exposes it via get_l2_perf_level(). - Host-side L2PerfCollector caches the level to gate JSON sections and stamps the JSON "version" field directly from perf_level. - Apply level gates throughout AICPU code paths: skip dispatch/finish timestamps and fanout copies below AICPU_TIMING, scheduler phase records below SCHED_PHASES, and orchestrator phase records below ORCH_PHASES. - Plumb perf_level through DeviceRunner / pto_runtime_c_api on both onboard and sim backends. - Move l2_perf_aicpu_init out of the dispatch one-time-init block into SchedulerContext::init() in scheduler_cold_path.cpp, matching a2a3 so the orchestrator thread reads a promoted level when caching rt->orchestrator.l2_perf_level. - Align l2_perf_aicpu_record_phase to a2a3 byte-for-byte: remove the end-of-function wmb() and the 3 dropped-path wmbs (all introduced by hw-native-sys#777, none present in a2a3), and unify the accounting comment + brace style. Measured ~1.1 ms reduction in L4 orch_cost on paged_attention_unroll Case1. Update docs (l2-swimlane-profiling.md, profiling_levels.md, testing.md) to drop the "a5 is boolean-only" caveat and document the unified integer interface across a2a3 and a5.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
May 25, 2026
Port the tiered L2 swimlane perf_level feature from hw-native-sys#782 (a2a3-only) to the a5 platform, so a5 onboard and a5sim now honor the integer perf_level (0-4) instead of treating --enable-l2-swimlane as a plain boolean. Mirror the a2a3 wiring on a5: - L2PerfDataHeader::l2_perf_level carries the level into shared memory; AICPU promotes it in l2_perf_aicpu_init and exposes it via get_l2_perf_level(). - Host-side L2PerfCollector caches the level to gate JSON sections and stamps the JSON "version" field directly from perf_level. - Apply level gates throughout AICPU code paths: skip dispatch/finish timestamps and fanout copies below AICPU_TIMING, scheduler phase records below SCHED_PHASES, and orchestrator phase records below ORCH_PHASES. - Plumb perf_level through DeviceRunner / pto_runtime_c_api on both onboard and sim backends. - Move l2_perf_aicpu_init out of the dispatch one-time-init block into SchedulerContext::init() in scheduler_cold_path.cpp, matching a2a3 so the orchestrator thread reads a promoted level when caching rt->orchestrator.l2_perf_level. - Align l2_perf_aicpu_record_phase to a2a3 byte-for-byte: remove the end-of-function wmb() and the 3 dropped-path wmbs (all introduced by hw-native-sys#777, none present in a2a3), and unify the accounting comment + brace style. Measured ~1.1 ms reduction in L4 orch_cost on paged_attention_unroll Case1. - Align l2_perf_aicpu_complete_record with a2a3: add thread_idx parameter (routed from both host_build_graph and tensormap_and_ringbuffer callers), introduce an AICPU-private s_perf_records_buffers[] cache as the records-buffer SoT, rename switch_buffer -> switch_records_buffer and rotate after the write so the just-committed record is preserved, and surface ring/task_id mismatch as a dedicated LOG_ERROR (completion-before-dispatch invariant violation) separate from capacity drops. init / flush_buffers maintain s_perf_records_buffers[] in lockstep with state->current_buf_ptr so flush deterministically halts subsequent commits. Update docs (l2-swimlane-profiling.md, profiling_levels.md, testing.md) to drop the "a5 is boolean-only" caveat and document the unified integer interface across a2a3 and a5.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
May 25, 2026
Port the tiered L2 swimlane perf_level feature from [hw-native-sys#782](hw-native-sys#782) (a2a3-only) to the a5 platform, so a5 onboard and a5sim now honor the integer perf_level (0-4) instead of treating --enable-l2-swimlane as a plain boolean. Mirror the a2a3 wiring on a5: - L2PerfDataHeader::l2_perf_level carries the level into shared memory; AICPU promotes it in l2_perf_aicpu_init and exposes it via get_l2_perf_level(). - Host-side L2PerfCollector caches the level to gate JSON sections and stamps the JSON "version" field directly from perf_level. - Apply level gates throughout AICPU code paths: skip dispatch/finish timestamps and fanout copies below AICPU_TIMING, scheduler phase records below SCHED_PHASES, and orchestrator phase records below ORCH_PHASES. - Plumb perf_level through DeviceRunner / pto_runtime_c_api on both onboard and sim backends. - Move l2_perf_aicpu_init out of the dispatch one-time-init block into SchedulerContext::init() in scheduler_cold_path.cpp, matching a2a3 so the orchestrator thread reads a promoted level when caching rt->orchestrator.l2_perf_level. - Align l2_perf_aicpu_record_phase to a2a3 byte-for-byte: remove the end-of-function wmb() and the 3 dropped-path wmbs (all introduced by [hw-native-sys#777](hw-native-sys#777), none present in a2a3), and unify the accounting comment + brace style. Measured ~1.1 ms reduction in L4 orch_cost on paged_attention_unroll Case1. - Align l2_perf_aicpu_complete_record with a2a3: add thread_idx parameter (routed from both host_build_graph and tensormap_and_ringbuffer callers), introduce an AICPU-private s_perf_records_buffers[] cache as the records-buffer SoT, rename switch_buffer -> switch_records_buffer and rotate after the write so the just-committed record is preserved, and surface ring/task_id mismatch as a dedicated LOG_ERROR (completion-before-dispatch invariant violation) separate from capacity drops. init / flush_buffers maintain s_perf_records_buffers[] in lockstep with state->current_buf_ptr so flush deterministically halts subsequent commits. Update docs (l2-swimlane-profiling.md, profiling_levels.md, testing.md) to drop the "a5 is boolean-only" caveat and document the unified integer interface across a2a3 and a5.
ChaoZheng109
pushed a commit
that referenced
this pull request
May 25, 2026
Port the tiered L2 swimlane perf_level feature from [#782](#782) (a2a3-only) to the a5 platform, so a5 onboard and a5sim now honor the integer perf_level (0-4) instead of treating --enable-l2-swimlane as a plain boolean. Mirror the a2a3 wiring on a5: - L2PerfDataHeader::l2_perf_level carries the level into shared memory; AICPU promotes it in l2_perf_aicpu_init and exposes it via get_l2_perf_level(). - Host-side L2PerfCollector caches the level to gate JSON sections and stamps the JSON "version" field directly from perf_level. - Apply level gates throughout AICPU code paths: skip dispatch/finish timestamps and fanout copies below AICPU_TIMING, scheduler phase records below SCHED_PHASES, and orchestrator phase records below ORCH_PHASES. - Plumb perf_level through DeviceRunner / pto_runtime_c_api on both onboard and sim backends. - Move l2_perf_aicpu_init out of the dispatch one-time-init block into SchedulerContext::init() in scheduler_cold_path.cpp, matching a2a3 so the orchestrator thread reads a promoted level when caching rt->orchestrator.l2_perf_level. - Align l2_perf_aicpu_record_phase to a2a3 byte-for-byte: remove the end-of-function wmb() and the 3 dropped-path wmbs (all introduced by [#777](#777), none present in a2a3), and unify the accounting comment + brace style. Measured ~1.1 ms reduction in L4 orch_cost on paged_attention_unroll Case1. - Align l2_perf_aicpu_complete_record with a2a3: add thread_idx parameter (routed from both host_build_graph and tensormap_and_ringbuffer callers), introduce an AICPU-private s_perf_records_buffers[] cache as the records-buffer SoT, rename switch_buffer -> switch_records_buffer and rotate after the write so the just-committed record is preserved, and surface ring/task_id mismatch as a dedicated LOG_ERROR (completion-before-dispatch invariant violation) separate from capacity drops. init / flush_buffers maintain s_perf_records_buffers[] in lockstep with state->current_buf_ptr so flush deterministically halts subsequent commits. Update docs (l2-swimlane-profiling.md, profiling_levels.md, testing.md) to drop the "a5 is boolean-only" caveat and document the unified integer interface across a2a3 and a5.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
May 28, 2026
Port the dep_gen (SubmitTrace) feature from a2a3 to a5 so the
tensormap_and_ringbuffer runtime on a5 can produce deps.json and feed
flow events into swimlane_converter.py. Without this, --enable-dep-gen
was a no-op on a5 and merged_swimlane_*.json had no dependency arrows.
Reused from a2a3 verbatim (byte-identical):
- Shared-memory ABI: common/dep_gen.h (DepGenRecord 2624 B, overflow
chain, SPSC free_queue, per-thread ready_queue)
- AICPU writer: aicpu/dep_gen_collector_aicpu.{h,cpp}
- Runtime replay: runtime/tensormap_and_ringbuffer/host/dep_gen_replay
- Orchestrator capture point + aicpu_executor lifecycle hooks
- 5 platform_config constants + PROFILING_FLAG_DEP_GEN bit
Specialized for a5 (no SVM, see profiling_common diff vs a2a3):
- dep_gen_collector.cpp uses alloc_single_buffer (malloc shadow +
profiling_copy_to_device) instead of identity-mapping when
register_cb is null — matches a5's PMU/L2Perf/Dump collectors.
- Two-phase set_memory_context: callbacks first, then shm pointers
once the region is committed, so start(tf) gates correctly.
- reconcile_counters explicitly copy_from_device's the BufferState +
current_buf before reading (mgmt thread is stopped by then).
- finalize lets BufferPoolManager::clear_mappings() be the single
source of truth for host-shadow lifetime — no per-collector dedup.
Sim path: dlsym set_platform_dep_gen_base / set_dep_gen_enabled out of
the AICPU .so and forward kernel_args.dep_gen_data_base + enable flag
at boot, mirroring the existing pmu / dump / l2_perf setters.
Onboard kernel.cpp adds two lines to forward dep_gen_data_base +
PROFILING_FLAG_DEP_GEN into the AICPU writer's globals, mirroring the
existing PMU / L2 / Dump setters.
c_api: run_prepared's enable_dep_gen parameter is no longer ignored —
wired to runner->set_dep_gen_enabled() on both onboard and sim.
Tests:
- tests/st/a5/.../dfx/dep_gen/test_dep_gen.py: 6-edge validation
against vector_example orchestration (byte-identical to a2a3 — same
expected edge set).
- tests/st/a5/.../dfx/dep_gen/test_dep_gen_chain.py: overflow chain
regression for >64 explicit deps.
Docs:
- docs/dfx/dep_gen.md: §8 Architecture Touchpoints now lists both
platforms; "Currently a2a3 only" line removed.
- src/a5/runtime/.../docs/profiling_levels.md: Code Locations point
at src/a5/ (was stale src/a2a3/ refs from PR hw-native-sys#777 cleanup) and
add a dep_gen entry.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
May 31, 2026
Port the dep_gen (SubmitTrace) feature from a2a3 to a5 so the
tensormap_and_ringbuffer runtime on a5 can produce deps.json and feed
flow events into swimlane_converter.py. Without this, --enable-dep-gen
was a no-op on a5 and merged_swimlane_*.json had no dependency arrows.
Reused from a2a3 verbatim (byte-identical):
- Shared-memory ABI: common/dep_gen.h (DepGenRecord 2624 B, overflow
chain, SPSC free_queue, per-thread ready_queue)
- AICPU writer: aicpu/dep_gen_collector_aicpu.{h,cpp}
- Runtime replay: runtime/tensormap_and_ringbuffer/host/dep_gen_replay
- Orchestrator capture point + aicpu_executor lifecycle hooks
- 5 platform_config constants + PROFILING_FLAG_DEP_GEN bit
Specialized for a5 (no SVM, see profiling_common diff vs a2a3):
- dep_gen_collector.cpp uses alloc_single_buffer (malloc shadow +
profiling_copy_to_device) instead of identity-mapping when
register_cb is null — matches a5's PMU/L2Perf/Dump collectors.
- Two-phase set_memory_context: callbacks first, then shm pointers
once the region is committed, so start(tf) gates correctly.
- reconcile_counters explicitly copy_from_device's the BufferState +
current_buf before reading (mgmt thread is stopped by then).
- finalize lets BufferPoolManager::clear_mappings() be the single
source of truth for host-shadow lifetime — no per-collector dedup.
Sim path: dlsym set_platform_dep_gen_base / set_dep_gen_enabled out of
the AICPU .so and forward kernel_args.dep_gen_data_base + enable flag
at boot, mirroring the existing pmu / dump / l2_perf setters.
Onboard kernel.cpp adds two lines to forward dep_gen_data_base +
PROFILING_FLAG_DEP_GEN into the AICPU writer's globals, mirroring the
existing PMU / L2 / Dump setters.
c_api: run_prepared's enable_dep_gen parameter is no longer ignored —
wired to runner->set_dep_gen_enabled() on both onboard and sim.
Tests:
- tests/st/a5/.../dfx/dep_gen/test_dep_gen.py: 6-edge validation
against vector_example orchestration (byte-identical to a2a3 — same
expected edge set).
- tests/st/a5/.../dfx/dep_gen/test_dep_gen_chain.py: overflow chain
regression for >64 explicit deps.
Docs:
- docs/dfx/dep_gen.md: §8 Architecture Touchpoints now lists both
platforms; "Currently a2a3 only" line removed.
- src/a5/runtime/.../docs/profiling_levels.md: Code Locations point
at src/a5/ (was stale src/a2a3/ refs from PR hw-native-sys#777 cleanup) and
add a dep_gen entry.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
Jun 1, 2026
Port the dep_gen (SubmitTrace) feature from a2a3 to a5 so the
tensormap_and_ringbuffer runtime on a5 can produce deps.json and feed
flow events into swimlane_converter.py. Without this, --enable-dep-gen
was a no-op on a5 and merged_swimlane_*.json had no dependency arrows.
Reused from a2a3 verbatim (byte-identical):
- Shared-memory ABI: common/dep_gen.h (DepGenRecord 2624 B, overflow
chain, SPSC free_queue, per-thread ready_queue)
- AICPU writer: aicpu/dep_gen_collector_aicpu.{h,cpp}
- Runtime replay: runtime/tensormap_and_ringbuffer/host/dep_gen_replay
- Orchestrator capture point + aicpu_executor lifecycle hooks
- 5 platform_config constants + PROFILING_FLAG_DEP_GEN bit
Specialized for a5 (no SVM, see profiling_common diff vs a2a3):
- dep_gen_collector.cpp uses alloc_single_buffer (malloc shadow +
profiling_copy_to_device) instead of identity-mapping when
register_cb is null — matches a5's PMU/L2Perf/Dump collectors.
- Two-phase set_memory_context: callbacks first, then shm pointers
once the region is committed, so start(tf) gates correctly.
- reconcile_counters explicitly copy_from_device's the BufferState +
current_buf before reading (mgmt thread is stopped by then).
- finalize lets BufferPoolManager::clear_mappings() be the single
source of truth for host-shadow lifetime — no per-collector dedup.
Sim path: dlsym set_platform_dep_gen_base / set_dep_gen_enabled out of
the AICPU .so and forward kernel_args.dep_gen_data_base + enable flag
at boot, mirroring the existing pmu / dump / l2_perf setters.
Onboard kernel.cpp adds two lines to forward dep_gen_data_base +
PROFILING_FLAG_DEP_GEN into the AICPU writer's globals, mirroring the
existing PMU / L2 / Dump setters.
c_api: run_prepared's enable_dep_gen parameter is no longer ignored —
wired to runner->set_dep_gen_enabled() on both onboard and sim.
Tests:
- tests/st/a5/.../dfx/dep_gen/test_dep_gen.py: 6-edge validation
against vector_example orchestration (byte-identical to a2a3 — same
expected edge set).
- tests/st/a5/.../dfx/dep_gen/test_dep_gen_chain.py: overflow chain
regression for >64 explicit deps.
Docs:
- docs/dfx/dep_gen.md: §8 Architecture Touchpoints now lists both
platforms; "Currently a2a3 only" line removed.
- src/a5/runtime/.../docs/profiling_levels.md: Code Locations point
at src/a5/ (was stale src/a2a3/ refs from PR hw-native-sys#777 cleanup) and
add a dep_gen entry.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
Jun 1, 2026
Port the dep_gen (SubmitTrace) feature from a2a3 to a5 so the
tensormap_and_ringbuffer runtime on a5 can produce deps.json and feed
flow events into swimlane_converter.py. Without this, --enable-dep-gen
was a no-op on a5 and merged_swimlane_*.json had no dependency arrows.
Reused from a2a3 (code-identical; the .cpp files are byte-for-byte
copies, the headers differ only in include-guard names and
L2Swimlane->L2Perf / a2a3->a5 comment refs):
- Shared-memory ABI: common/dep_gen.h (DepGenRecord 2624 B, overflow
chain, SPSC free_queue, per-thread ready_queue) — layout byte-identical
- AICPU writer: aicpu/dep_gen_collector_aicpu.{h,cpp} (.cpp identical)
- Runtime replay: runtime/tensormap_and_ringbuffer/host/dep_gen_replay
(.cpp identical)
- Orchestrator capture point + aicpu_executor lifecycle hooks
- 5 platform_config constants + PROFILING_FLAG_DEP_GEN bit
Specialized for a5 (no SVM, see profiling_common diff vs a2a3):
- dep_gen_collector.cpp uses alloc_single_buffer (malloc shadow +
profiling_copy_to_device) instead of identity-mapping when
register_cb is null — matches a5's PMU/L2Perf/Dump collectors.
- Two-phase set_memory_context: callbacks first, then shm pointers
once the region is committed, so start(tf) gates correctly.
- reconcile_counters explicitly copy_from_device's the BufferState +
current_buf before reading (mgmt thread is stopped by then).
- finalize lets BufferPoolManager::clear_mappings() be the single
source of truth for host-shadow lifetime — no per-collector dedup.
Sim path: dlsym set_platform_dep_gen_base / set_dep_gen_enabled out of
the AICPU .so and forward kernel_args.dep_gen_data_base + enable flag
at boot, mirroring the existing pmu / dump / l2_perf setters.
Onboard kernel.cpp adds two lines to forward dep_gen_data_base +
PROFILING_FLAG_DEP_GEN into the AICPU writer's globals, mirroring the
existing PMU / L2 / Dump setters.
c_api: a5's DeviceRunner now overrides set_dep_gen_enabled() (was the
base no-op), so run_prepared's already-present enable_dep_gen call is
honored on a5 instead of being silently dropped. The shared
c_api_shared.cpp / device_runner_base.h changes are comment-only —
refreshing stale "a2a3-only" notes to reflect both arches now wire it.
Tests:
- tests/st/a5/.../dfx/dep_gen/test_dep_gen.py: 6-edge validation
against vector_example orchestration (byte-identical to a2a3 — same
expected edge set).
- tests/st/a5/.../dfx/dep_gen/test_dep_gen_chain.py
(+ kernels/orchestration/chain_barrier_orch.cpp): overflow chain
regression for >64 explicit deps.
- tests/st/a2a3/.../dfx/dep_gen/test_dep_gen.py: harden the existing
a2a3 gate — a missing deps.json under --enable-dep-gen now fails
loudly (assert) instead of silently skipping, so a
capture->reconcile->replay regression can no longer pass green
(hw-native-sys#742).
Docs:
- docs/dfx/dep_gen.md: §8 Architecture Touchpoints now lists both
platforms; "Currently a2a3 only" line removed.
- src/a5/runtime/.../docs/profiling_levels.md: Code Locations point
at src/a5/ (was stale src/a2a3/ refs from PR hw-native-sys#777 cleanup) and
add a dep_gen entry.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
Jun 1, 2026
Port the dep_gen (SubmitTrace) feature from a2a3 to a5 so the
tensormap_and_ringbuffer runtime on a5 can produce deps.json and feed
flow events into swimlane_converter.py. Without this, --enable-dep-gen
was a no-op on a5 and merged_swimlane_*.json had no dependency arrows.
Reused from a2a3 (code-identical; the .cpp files are byte-for-byte
copies, the headers differ only in include-guard names and
L2Swimlane->L2Perf / a2a3->a5 comment refs):
- Shared-memory ABI: common/dep_gen.h (DepGenRecord 2624 B, overflow
chain, SPSC free_queue, per-thread ready_queue) — layout byte-identical
- AICPU writer: aicpu/dep_gen_collector_aicpu.{h,cpp} (.cpp identical)
- Runtime replay: runtime/tensormap_and_ringbuffer/host/dep_gen_replay
(.cpp identical)
- Orchestrator capture point + aicpu_executor lifecycle hooks
- 5 platform_config constants + PROFILING_FLAG_DEP_GEN bit
Specialized for a5 (no SVM, see profiling_common diff vs a2a3):
- dep_gen_collector.cpp uses alloc_single_buffer (malloc shadow +
profiling_copy_to_device) instead of identity-mapping when
register_cb is null — matches a5's PMU/L2Perf/Dump collectors.
- Two-phase set_memory_context: callbacks first, then shm pointers
once the region is committed, so start(tf) gates correctly.
- reconcile_counters explicitly copy_from_device's the BufferState +
current_buf before reading (mgmt thread is stopped by then).
- finalize lets BufferPoolManager::clear_mappings() be the single
source of truth for host-shadow lifetime — no per-collector dedup.
Sim path: dlsym set_platform_dep_gen_base / set_dep_gen_enabled out of
the AICPU .so and forward kernel_args.dep_gen_data_base + enable flag
at boot, mirroring the existing pmu / dump / l2_perf setters.
Onboard kernel.cpp adds two lines to forward dep_gen_data_base +
PROFILING_FLAG_DEP_GEN into the AICPU writer's globals, mirroring the
existing PMU / L2 / Dump setters.
c_api: a5's DeviceRunner now overrides set_dep_gen_enabled() (was the
base no-op), so run_prepared's already-present enable_dep_gen call is
honored on a5 instead of being silently dropped. The shared
c_api_shared.cpp / device_runner_base.h changes are comment-only —
refreshing stale "a2a3-only" notes to reflect both arches now wire it.
Tests:
- tests/st/a5/.../dfx/dep_gen/test_dep_gen.py: 6-edge validation
against vector_example orchestration (byte-identical to a2a3 — same
expected edge set).
- tests/st/a5/.../dfx/dep_gen/test_dep_gen_chain.py
(+ kernels/orchestration/chain_barrier_orch.cpp): overflow chain
regression for >64 explicit deps.
- tests/st/a2a3/.../dfx/dep_gen/test_dep_gen.py: harden the existing
a2a3 gate — a missing deps.json under --enable-dep-gen now fails
loudly (assert) instead of silently skipping, so a
capture->reconcile->replay regression can no longer pass green
(hw-native-sys#742).
Docs:
- docs/dfx/dep_gen.md: §8 Architecture Touchpoints now lists both
platforms; "Currently a2a3 only" line removed.
- src/a5/runtime/.../docs/profiling_levels.md: Code Locations point
at src/a5/ (was stale src/a2a3/ refs from PR hw-native-sys#777 cleanup) and
add a dep_gen entry.
indigo1973
added a commit
to indigo1973/simpler
that referenced
this pull request
Jun 1, 2026
Port the dep_gen (SubmitTrace) feature from a2a3 to a5 so the
tensormap_and_ringbuffer runtime on a5 can produce deps.json and feed
flow events into swimlane_converter.py. Without this, --enable-dep-gen
was a no-op on a5 and merged_swimlane_*.json had no dependency arrows.
Reused from a2a3 (code-identical; the .cpp files are byte-for-byte
copies, the headers differ only in include-guard names and
L2Swimlane->L2Perf / a2a3->a5 comment refs):
- Shared-memory ABI: common/dep_gen.h (DepGenRecord 2624 B, overflow
chain, SPSC free_queue, per-thread ready_queue) — layout byte-identical
- AICPU writer: aicpu/dep_gen_collector_aicpu.{h,cpp} (.cpp identical)
- Runtime replay: runtime/tensormap_and_ringbuffer/host/dep_gen_replay
(.cpp identical)
- Orchestrator capture point + aicpu_executor lifecycle hooks
- 5 platform_config constants + PROFILING_FLAG_DEP_GEN bit
Specialized for a5 (no SVM, see profiling_common diff vs a2a3):
- dep_gen_collector.cpp uses alloc_single_buffer (malloc shadow +
profiling_copy_to_device) instead of identity-mapping when
register_cb is null — matches a5's PMU/L2Perf/Dump collectors.
- Two-phase set_memory_context: callbacks first, then shm pointers
once the region is committed, so start(tf) gates correctly.
- reconcile_counters explicitly copy_from_device's the BufferState +
current_buf before reading (mgmt thread is stopped by then).
- finalize lets BufferPoolManager::clear_mappings() be the single
source of truth for host-shadow lifetime — no per-collector dedup.
Sim path: dlsym set_platform_dep_gen_base / set_dep_gen_enabled out of
the AICPU .so and forward kernel_args.dep_gen_data_base + enable flag
at boot, mirroring the existing pmu / dump / l2_perf setters.
Onboard kernel.cpp adds two lines to forward dep_gen_data_base +
PROFILING_FLAG_DEP_GEN into the AICPU writer's globals, mirroring the
existing PMU / L2 / Dump setters.
c_api: a5's DeviceRunner now overrides set_dep_gen_enabled() (was the
base no-op), so run_prepared's already-present enable_dep_gen call is
honored on a5 instead of being silently dropped. The shared
c_api_shared.cpp / device_runner_base.h changes are comment-only —
refreshing stale "a2a3-only" notes to reflect both arches now wire it.
Tests:
- tests/st/a5/.../dfx/dep_gen/test_dep_gen.py: 6-edge validation
against vector_example orchestration (byte-identical to a2a3 — same
expected edge set).
- tests/st/a5/.../dfx/dep_gen/test_dep_gen_chain.py
(+ kernels/orchestration/chain_barrier_orch.cpp): overflow chain
regression for >64 explicit deps.
- tests/st/a2a3/.../dfx/dep_gen/test_dep_gen.py: harden the existing
a2a3 gate — a missing deps.json under --enable-dep-gen now fails
loudly (assert) instead of silently skipping, so a
capture->reconcile->replay regression can no longer pass green
([hw-native-sys#742](hw-native-sys#742)).
Docs:
- docs/dfx/dep_gen.md: §8 Architecture Touchpoints now lists both
platforms; "Currently a2a3 only" line removed.
- src/a5/runtime/.../docs/profiling_levels.md: Code Locations point
at src/a5/ (was stale src/a2a3/ refs from PR [hw-native-sys#777](hw-native-sys#777) cleanup) and
add a dep_gen entry.
nalinaly
pushed a commit
to nalinaly/simpler
that referenced
this pull request
Jul 31, 2026
…ICore ring, profiling off Handshake) (hw-native-sys#777) Brings a5 to the same shape as a2a3's PR [hw-native-sys#705](hw-native-sys#705) / [hw-native-sys#709](hw-native-sys#709) / [hw-native-sys#714](hw-native-sys#714): host-side collectors share a ProfilerBase<Derived, Module> + BufferPoolManager<Module> framework; AICore writes through a stable per-core L2PerfAicoreRing / PmuAicoreRing decoupled from AICPU buffer rotation; profiling state moves off Handshake onto KernelArgs + AICore platform-owned slots (aicore_profiling_state.h). a5's transport channel deviates only in MemoryOps carrying copy_to_device / copy_from_device, the mgmt loop mirroring the shm region per tick, and release_owned_buffers freeing the paired host shadow. AICore now resolves its own PMU MMIO base at kernel entry directly from KernelArgs::regs[get_physical_core_id()] (the per-physical-core register-base table the host already fills for AICPU), instead of indexing a separate pmu_reg_addrs table that AICPU filled during handshake. The resolved base is valid from Phase 1 onward, so aicore_execute caches it at Phase 3 alongside the rings rather than re-reading per PMU record. Drops KernelArgs::pmu_reg_addrs, set/get_platform_pmu_reg_addrs, and the corresponding host-side table allocation in PmuCollector.
nalinaly
pushed a commit
to nalinaly/simpler
that referenced
this pull request
Jul 31, 2026
…e-sys#841) Port the tiered L2 swimlane perf_level feature from [hw-native-sys#782](hw-native-sys#782) (a2a3-only) to the a5 platform, so a5 onboard and a5sim now honor the integer perf_level (0-4) instead of treating --enable-l2-swimlane as a plain boolean. Mirror the a2a3 wiring on a5: - L2PerfDataHeader::l2_perf_level carries the level into shared memory; AICPU promotes it in l2_perf_aicpu_init and exposes it via get_l2_perf_level(). - Host-side L2PerfCollector caches the level to gate JSON sections and stamps the JSON "version" field directly from perf_level. - Apply level gates throughout AICPU code paths: skip dispatch/finish timestamps and fanout copies below AICPU_TIMING, scheduler phase records below SCHED_PHASES, and orchestrator phase records below ORCH_PHASES. - Plumb perf_level through DeviceRunner / pto_runtime_c_api on both onboard and sim backends. - Move l2_perf_aicpu_init out of the dispatch one-time-init block into SchedulerContext::init() in scheduler_cold_path.cpp, matching a2a3 so the orchestrator thread reads a promoted level when caching rt->orchestrator.l2_perf_level. - Align l2_perf_aicpu_record_phase to a2a3 byte-for-byte: remove the end-of-function wmb() and the 3 dropped-path wmbs (all introduced by [hw-native-sys#777](hw-native-sys#777), none present in a2a3), and unify the accounting comment + brace style. Measured ~1.1 ms reduction in L4 orch_cost on paged_attention_unroll Case1. - Align l2_perf_aicpu_complete_record with a2a3: add thread_idx parameter (routed from both host_build_graph and tensormap_and_ringbuffer callers), introduce an AICPU-private s_perf_records_buffers[] cache as the records-buffer SoT, rename switch_buffer -> switch_records_buffer and rotate after the write so the just-committed record is preserved, and surface ring/task_id mismatch as a dedicated LOG_ERROR (completion-before-dispatch invariant violation) separate from capacity drops. init / flush_buffers maintain s_perf_records_buffers[] in lockstep with state->current_buf_ptr so flush deterministically halts subsequent commits. Update docs (l2-swimlane-profiling.md, profiling_levels.md, testing.md) to drop the "a5 is boolean-only" caveat and document the unified integer interface across a2a3 and a5.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings a5's profiling stack to the same shape as a2a3 (PRs #705 / #709 / #714):
L2PerfCollector/PmuCollector/TensorDumpCollectornow derive fromProfilerBase<Derived, Module>over a sharedBufferPoolManager<Module>undersrc/a5/platform/include/host/profiling_common/. Mgmt + poll threads + buffer pool logic deduplicated across three collectors.L2PerfAicoreRing/PmuAicoreRingallocated once by the host; address is published viaKernelArgs::aicore_*_ring_addrs[block_idx]and never reassigned. Decouples AICore writes from AICPU's rotating records buffer, and fixes the latent PMU buffer-flip bug where AICore kept writing to the stale buffer.Handshake: enablement bits + per-core address arrays moved from runtimeHandshaketoKernelArgs+ AICore platform-owned slots (aicore_profiling_state.h). Adding a new profiling field no longer touches the runtime sync protocol. AICore resolves its PMU MMIO base directly from the existingKernelArgs::regstable at kernel entry (regs[get_physical_core_id()]), so there is no separate per-corepmu_reg_addrstable and no AICPU-fill-after-handshake dependency — the reg base is stable from Phase 1, andaicore_executecaches it at Phase 3 alongside the rings.L2PerfBufferStateandPmuBufferStatenow tracktotal / dropped / mismatch; collectors cross-checkcollected + dropped + mismatch == device_totalper pool, matching a2a3.a5's transport channel still differs from a2a3 (no
halHostRegisteron DAV_3510). The framework absorbs that as:MemoryOpscarries 5 callbacks (addscopy_to_device/copy_from_device)profiling_copy.hrelease_owned_buffersfrees the paired host-shadowmalloc()Docs
docs/profiling-framework.md§8 — new a5-specifics sectiondocs/dfx/{pmu-profiling,l2-swimlane-profiling,tensor-dump}.md§5.x — a5 transport channel + lifecycle + reconcile semantics updated to match the code as it standsNaming note
a5's new
KernelArgsfields are named*_addrs(plural) for the per-core address arrays:aicore_l2_perf_ring_addrs,aicore_pmu_ring_addrs. a2a3'saicore_ring_addr(singular but pointing to an array) is logged for a follow-up a2a3 rename PR; not touched here per the arch-independence rule.Test plan
python -m simpler_setup.build_runtimes --platform a5sim— host_build_graph + tensormap_and_ringbuffer build clean./ci.sh -p a5sim)collected + dropped + mismatch == device_totalmatches per pool on a representative case