Category
Technical Debt (cleanup, refactor)
Component
AICPU Scheduler
Description
tensormap_and_ringbuffer (tmr) 运行时有两份实现:src/a2a3/runtime/tensormap_and_ringbuffer/ 与 src/a5/runtime/tensormap_and_ringbuffer/。目标是两份尽量保持一致,仅在硬件/架构确有要求处才允许差异。
对 tmr 全树做内容级 diff(基线 upstream/main @ ca22a8f4)后的结论:文件结构相同(a5 仅多 urma 后端),差异全在实现内容。strace / timing / L2-swimlane / profiling 计装已代码级对齐(strace_timing、swimlane_converter.py 在 a5 可用),无需处理。
说明:下表行号用 A1..A9,避免与 GitHub 的 PR/issue 自动链接混淆。文中形如 #1328 的四位号才是真实 PR 引用。
方向判定方法(重要)
两棵树共享 git 历史:仓库初始大导入 commit 8b34712b(#1100) 一次性建立了 a2a3 与 a5 两棵树,且导入那一刻两树部分内容就已不同(同一 commit 里 a2a3/a5 版本各异)。此后多数 PR 用 (a2a3 + a5) 标题同时改两树,分叉只来自少数单边 PR。因此 git blame 会把所有行归到 #1100,不能用来判断方向。方向只能由“导入后单边 PR 到底改了哪棵树”来确定:
主表:a5 落后 a2a3(有单边 PR 证据,需从 a2a3 移植)
| 行 |
领域 |
a5 现状 vs a2a3 能力 |
影响 |
方向证据(a2a3 单边 PR,a5 改动=0) |
| A1 |
dispatch 热路径 |
a5 每次派发都 AsyncCtx::make+清 slab;a2a3 在 init() 按 (core,buf) 预填、每派发只写 task_token |
性能(每任务,最大) |
#1328 perf(a2a3/tmr): shrink dispatch cold-write cost;#1345 |
| A2 |
调度结构 |
a5 无正常 sync_start 车道,全走 stop-the-world drain;a2a3 有 ready_sync_queues[] Tier-0 + run_staging_order |
性能+结构(最大结构差) |
#1319(a2a3=4/a5=0);#1285/#1292/#1405 |
| A3 |
调度并发 |
a5 dummy 队列固定 thread 0(batch 16);a2a3 跨 sched 线程并行 thread_idx<3(batch 8) |
性能(a5 未用多余 sched 线程做 dep-only resolve;a5 串行是安全的,非竞态 bug) |
已证:#1263 同改两树,把 a2a3 从 thread0 改为 thread_idx<3 并行化,a5 有意保留 thread0 并加注“避免跨线程竞争”。a5 落后,但补齐需先具备并行安全前提(MPMC + per-slot 原子) |
| A5 |
AICore executor |
a5 旧合并型 L2 记录、DFX 关也每次读计时器、记录可能跨缓冲代;a2a3 reserve/commit 拆分+计时门控 |
正确性+性能 |
#1513(a2a3=1/a5=0) |
| A6 |
dispatch 微优化 |
a5 无 prefetch_block_dst;a2a3 有 |
性能(低风险) |
#1328(a2a3 单边,a5 无此符号) |
| A7 |
DFX 计数 |
a5 缺 phase_subretire_count(a2a3 的 SPMD 子块-retire 计数) |
可观测性(须与 swimlane_converter.py 同 PR,见 #1382) |
已证:a2a3 #1288 单边引入,a5 从未有 |
| A8 |
host 接口 |
a5 无 get_pipeline_contract()(Tier-C extern-C ABI,跨仓消费) |
能力缺失(需协调移植) |
#1463(a2a3=1/a5=0) |
| A9 |
AICPU 健壮性 |
a5 无 run() thread-idx 边界检查 |
健壮性(轻微) |
#1119(a2a3=3/a5=0) |
A4 已撤销(2026-07-29 核实):原判“a5 缺 gated MIX per-core split”为误报。去注释精确比对后,正常 MIX per-core placement(idle 核→running、busy 核→pending,即 #1308)、classify_mix_cluster 定义、drain 路径 mix_split 三处代码两树完全一致。原以为的差异实属 A2 的队列参数化(a2a3 disp_queues[] vs a5 硬编码 ready_queues)。唯一遗留:a5 scheduler_dispatch.cpp 一条注释自相矛盾(写“not a2a3 gated MIX split”但代码正是该 placement),可顺手修正。
导入即分叉:方向无 git 依据(原先误判为“a2a3 落后 a5”,已更正)
这些差异自 #1100 导入即存在、此后两树都无单边改动,-S 追踪只有 #1100 一条。不能断言谁落后——只是仓库诞生时两份代码就不同。需要的是人工决定以哪种写法为准并统一到两树(rule 10:一次提交、全部树),而不是当作 a5 领先来追。
| 项 |
a2a3 现状 |
a5 现状 |
需人工决定 |
PTO2_SCOPE_GUARD |
无参 () |
可变参 (...) |
以哪种为准 |
| payload 预取 |
成员 payload->prefetch() |
自由函数 prefetch_payload() |
以哪种为准 |
TaskSubmitResult alias |
存在(零使用) |
无 |
大概率两树都删 |
pto2_submitted_tasks/read_pto2_runtime_status |
保留 PTO2 前缀 |
已去前缀 |
按 rule 9/10 统一去前缀 |
sched_scan_cycle 计数 |
无(全历史从未有) |
有(#1100 导入即有) |
a5 独有、a2a3 从无——决定去留(非 a2a3 落后) |
init_from_layout 残留 |
3 处 |
2 处 |
基本一致,仅清理残留 |
补充:a5 注释 sizeof(PTO2TaskSlotState) 写"32 bytes"但 static_assert 为 64 —— 这是 a5 注释 bug,直接修 a5。
文档修正(代码已对,无需改码)
| 文档 |
问题 |
src/a5/.../docs/profiling_levels.md |
描述旧 complete_task 结合型 level-1,与 a5 自身 decoupled 代码矛盾 |
src/a5/.../docs/MULTI_RING.md |
写了不存在的 API pto2_make_task_id()(两树实际都用 PTO2TaskId::make) |
必要差异(arch 决定,不要同步)
| 项 |
原因 |
关联 |
AICore PMU per-task ring(pmu_aicore_record_task)a5 独有 |
a5 领先;a2a3 硬件能力不足,不 back-port |
— |
| a5 删除 cache invalidate/flush(deinit / async-wait counter-line / SDMA record / PMU record) |
a5 AICPU 与 DMA/HBM 缓存一致,顺序由 acquire/release 原子保证;a3 需要而 a5 不需要 |
#1235 (153daee6) |
core_num / s_block_idx / s_block_num |
a5 编译器要求(block_idx/block_num 为内建保留符),不能回退;如需统一只能 a2a3 采用 a5 |
— |
urma 后端 + backend_cookie |
a5 硬件专有 |
#1392 |
核数/频率常量、DMB MMIO 偏移 0xD0、头文件 guard SRC_A5_* |
dav-c310 硬件 |
— |
待验证:reserve_layout 的 task_window_sizes[] 重载方向("a5 缺失" vs "a5 删了 dead 参数")——动手前先确认。
Location
基线 upstream/main @ ca22a8f4。两树对照:
src/a2a3/runtime/tensormap_and_ringbuffer/
src/a5/runtime/tensormap_and_ringbuffer/
按主表定位:A1 runtime/scheduler/scheduler_dispatch.cpp,scheduler_cold_path.cpp;A2 runtime/scheduler/pto_scheduler.h,scheduler_dispatch.cpp,runtime/shared/pto_runtime2_init.cpp;A3/A4/A6 scheduler_dispatch.cpp;A5 aicore/aicore_executor.cpp;A7 runtime/scheduler/* + simpler_setup/.../swimlane_converter.py;A8 host/runtime_maker.cpp;A9 aicpu/aicpu_executor.cpp
Proposed Fix
拆成多个小 PR 分批落地(禁止一个大 diff)。推荐补齐顺序:
| 阶段 |
包含项 |
目标 |
前置 / 风险 |
| P0 热路径性能 |
A1, A5, A6(方向已证) |
补齐每任务开销最大的 AICPU/AICore dispatch 优化 |
A5 需与 a5 的 PMU-ring/lazy-head 协调;保留 a5 backend_cookie/s_block 命名 |
| P1 调度结构决策 |
A2, A3 |
补齐 sync_start 车道与 dummy-drain 并发 |
需 sync_start/dep-pool owner 签字(移植 a2a3 双车道 vs 采纳 a5 单车道);A3 是竞态需先确认 |
| P2 DFX 对齐 |
A7 |
swimlane 计数对齐(phase_subretire_count) |
必须与 swimlane_converter.py+文档同 PR(#1382) |
| P3 外部 ABI |
A8 |
补 get_pipeline_contract() |
Tier-C ABI,需跨仓协调,勿盲拷 |
| P4 命名/写法统一 |
“导入即分叉”表全部 |
消除生而不同的差异 |
先人工决定每项以哪种写法为准(非“a2a3 追 a5”);rule 10 一次提交全部树 |
| P5 文档 |
profiling_levels.md, MULTI_RING.md |
修文档 |
无依赖,可随时做 |
关联:#1548, #545。
Priority
Medium (minor risk, should fix in next few releases)
Category
Technical Debt (cleanup, refactor)
Component
AICPU Scheduler
Description
tensormap_and_ringbuffer(tmr) 运行时有两份实现:src/a2a3/runtime/tensormap_and_ringbuffer/与src/a5/runtime/tensormap_and_ringbuffer/。目标是两份尽量保持一致,仅在硬件/架构确有要求处才允许差异。对 tmr 全树做内容级 diff(基线
upstream/main@ca22a8f4)后的结论:文件结构相同(a5 仅多 urma 后端),差异全在实现内容。strace / timing / L2-swimlane / profiling 计装已代码级对齐(strace_timing、swimlane_converter.py在 a5 可用),无需处理。方向判定方法(重要)
两棵树共享 git 历史:仓库初始大导入 commit
8b34712b(#1100) 一次性建立了 a2a3 与 a5 两棵树,且导入那一刻两树部分内容就已不同(同一 commit 里 a2a3/a5 版本各异)。此后多数 PR 用(a2a3 + a5)标题同时改两树,分叉只来自少数单边 PR。因此git blame会把所有行归到 #1100,不能用来判断方向。方向只能由“导入后单边 PR 到底改了哪棵树”来确定:主表:a5 落后 a2a3(有单边 PR 证据,需从 a2a3 移植)
AsyncCtx::make+清 slab;a2a3 在 init() 按 (core,buf) 预填、每派发只写task_tokenperf(a2a3/tmr): shrink dispatch cold-write cost;#1345ready_sync_queues[]Tier-0 +run_staging_orderthread 0(batch 16);a2a3 跨 sched 线程并行thread_idx<3(batch 8)thread0改为thread_idx<3并行化,a5 有意保留 thread0 并加注“避免跨线程竞争”。a5 落后,但补齐需先具备并行安全前提(MPMC + per-slot 原子)prefetch_block_dst;a2a3 有phase_subretire_count(a2a3 的 SPMD 子块-retire 计数)swimlane_converter.py同 PR,见 #1382)get_pipeline_contract()(Tier-C extern-C ABI,跨仓消费)run()thread-idx 边界检查导入即分叉:方向无 git 依据(原先误判为“a2a3 落后 a5”,已更正)
这些差异自 #1100 导入即存在、此后两树都无单边改动,
-S追踪只有 #1100 一条。不能断言谁落后——只是仓库诞生时两份代码就不同。需要的是人工决定以哪种写法为准并统一到两树(rule 10:一次提交、全部树),而不是当作 a5 领先来追。PTO2_SCOPE_GUARD()(...)payload->prefetch()prefetch_payload()TaskSubmitResultaliaspto2_submitted_tasks/read_pto2_runtime_statussched_scan_cycle计数init_from_layout残留补充:a5 注释
sizeof(PTO2TaskSlotState)写"32 bytes"但static_assert为 64 —— 这是 a5 注释 bug,直接修 a5。文档修正(代码已对,无需改码)
src/a5/.../docs/profiling_levels.mdsrc/a5/.../docs/MULTI_RING.mdpto2_make_task_id()(两树实际都用PTO2TaskId::make)必要差异(arch 决定,不要同步)
pmu_aicore_record_task)a5 独有153daee6)core_num/s_block_idx/s_block_numblock_idx/block_num为内建保留符),不能回退;如需统一只能 a2a3 采用 a5backend_cookie0xD0、头文件 guardSRC_A5_*待验证:
reserve_layout的task_window_sizes[]重载方向("a5 缺失" vs "a5 删了 dead 参数")——动手前先确认。Location
基线
upstream/main@ca22a8f4。两树对照:src/a2a3/runtime/tensormap_and_ringbuffer/src/a5/runtime/tensormap_and_ringbuffer/按主表定位:A1
runtime/scheduler/scheduler_dispatch.cpp,scheduler_cold_path.cpp;A2runtime/scheduler/pto_scheduler.h,scheduler_dispatch.cpp,runtime/shared/pto_runtime2_init.cpp;A3/A4/A6scheduler_dispatch.cpp;A5aicore/aicore_executor.cpp;A7runtime/scheduler/*+simpler_setup/.../swimlane_converter.py;A8host/runtime_maker.cpp;A9aicpu/aicpu_executor.cppProposed Fix
拆成多个小 PR 分批落地(禁止一个大 diff)。推荐补齐顺序:
backend_cookie/s_block命名phase_subretire_count)swimlane_converter.py+文档同 PR(#1382)get_pipeline_contract()关联:#1548, #545。
Priority
Medium (minor risk, should fix in next few releases)