Skip to content

Refactor: finish the PTO2 retirement, one identifier per commit - #1980

Merged
ChaoWao merged 22 commits into
hw-native-sys:mainfrom
ChaoWao:refactor/retire-pto2-remaining
Aug 25, 2026
Merged

ChaoWao merged 22 commits into
hw-native-sys:mainfrom
ChaoWao:refactor/retire-pto2-remaining

Conversation

@ChaoWao

@ChaoWao ChaoWao commented Aug 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This finishes the PTO2 retirement. 21 commits, one identifier or one coherent cluster each, 313 files. Every PTO2 occurrence this repo reads is gone: 5795 -> 62 (git grep -Io -E "PTO2|pto2_" | wc -l, base vs head), across 17 files, and every one that remains is deliberate.

The commits, in order:

Commit Occ. Files
ResourceShape, NUM_RESOURCE_SHAPES 474 46
TaskDescriptor, TaskPayload, PreparedTask, 7 TASKPAYLOAD_* offsets 561 81
SharedMemoryHeader/RingHeader/Handle, SharedMemory, sm_layout 602 82
SchedulerState, SchedulerLayout, SchedProfilingData, SCHED_CYCLE_* 397 71
OrchestratorState, OrchestratorLayout, OrchProfilingData 236 42
ChipTensorMap + 5 satellites + 3 CHIP_TENSORMAP_* 445 61
ChipReadyQueue, ChipReadyQueueSlot, 2 caps, LocalReadyBuffer 212 32
ChipTaskState + 3 CHIP_TASK_* + 6 lifecycle flags 362 40
ChipTaskRing/ChipHeapRing/ChipRingSet/… 85 25
TaskAllocator, TaskAllocResult, ALLOC_DEADLOCK_TIMEOUT_CYCLES 84 33
FaninPool/FaninSpillEntry/FaninBuilder/…, CHIP_MAX_FANIN 327 53
DepListEntry, DepListPool, 4 CHIP_DEP_* 124 35
EarlyDispatchState/EarlySyncDrainState + 14 enumerators 356 25
SubtaskSlot, 4 SUBTASK_*, DispatchPayload, DISPATCH_MAX_ARGS 442 72
ScopeMode, CHIP_MAX_SCOPE_DEPTH, CHIP_SCOPE_TASKS_CAP, 2 SCOPE_STATS_* 176 62
CHIP_ALIGN_SIZE/CHIP_ALIGN_UP, PACKED_OUTPUT_ALIGN 343 70
15 remaining constants and types incl. CHIP_HEAP_SIZE, CHIP_TASK_WINDOW_SIZE 239 83
Fix: two dead environment variables — 2
Tier-A prose, log text, 4 file-local identifiers, 3 stale references — 64
Docs: rule 10's remaining surface — 1
Refactor: remove the PTO2_RING_* env knobs and retarget their diagnostics -283 lines 43

Bold = took a prefix rather than the bare name. The name check has three sources, and only the first is greppable in this repo:

  1. The host orchestrator under src/common/hierarchical/ already declares TensorMap, ReadyQueue, TaskState (bound into Python), HeapRing/Ring, AllocResult and MAX_SCOPE_DEPTH. Rule 13 gives those to the L3+ context and the chip runtime takes Chip / CHIP_.
  2. External headers the same translation units include. CANN defines ALIGN_UP in acl/ops/acl_dvpp.h and acl/dvpp/hi_media_common.h. Nothing inside this repository can see that.
  3. Object-like macros collide with any declaration, because a macro rewrites its identifier textually instead of colliding where the compiler can report it. So the macros in runtime/runtime_types.h keep CHIP_ even where the bare name is free, while inline constexpr siblings in submit_types.h take it.

The bug in my own process, and the fix

#define HEAP_SIZE (256 * 1024 * 1024) rewrote three cpput fixtures' static constexpr uint64_t HEAP_SIZE = 4096; into static constexpr uint64_t (256 * 1024 * 1024) = 4096;.

I did not catch it per-commit, because my gate was pip install --no-build-isolation -e . — which builds the four runtime .so files and not the C++ unit-test targets, a separate CMake project. So the gate now compiles both (.docs/gate.sh), and the affected commits were replayed with the corrected plan rather than patched afterwards, so every commit here builds both trees. Rule 10 records the three-source check so the next person does not re-derive it.

Two dead environment variables

Both surfaced only because this work made me read every PTO2_* string, and both failed silently — an unrecognised env var is ignored:

  • tools/benchmark_rounds.sh --serial-orch-sched set PTO2_SERIAL_ORCH_SCHED=1. The runtime reads SIMPLER_TMR_SERIAL_ORCH_SCHED_ENABLE. The serial arm therefore ran with serial orch→sched off: the script measured the parallel path twice and reported the pair as a serial-versus-parallel comparison. Any measurement taken through that flag is void.
  • error_hint(SIMPLER_ERROR_SCHEDULER_TIMEOUT) told users to raise PTO2_SCHEDULER_TIMEOUT_MS; the knob is SIMPLER_SCHEDULER_TIMEOUT_MS, which CI already sets by that name. Following the hint on a scheduler-timeout fatal changed nothing and made a slow kernel look like a deadlock.

Three references to things that do not exist

  • pto2_task_slot(sched, task_id) — cited by runtime_types.h and runtime_init.cpp as how to compute a slot. No such function; it is local_id masked by the window size, which the comment now says, including why the window is a power of two.
  • pto2_run_runtime — named five times in docs/task-flow.md as the L2 ABI edge. It is simpler_run.
  • pto2_init_* flags — listed in docs/dynamic-linking.md among what SchedulerContext::deinit() resets. It resets no such flag and none exists under any spelling.

Also: the four shared-memory layout diagrams that #1969 deliberately deferred are now correct, since every row (SharedMemoryHeader, TaskDescriptor[], TaskPayload[], ChipTaskSlotState[]) names a type that exists under exactly that spelling. The two multi-ring boxes widen by four columns to fit.

The ring env knobs are removed, not kept

The first version of this PR retained PTO2_RING_TASK_WINDOW / PTO2_RING_HEAP / PTO2_RING_DEP_POOL as Tier C. They are now gone, because they were never a contract worth keeping: CallConfig.runtime_env already carries the same three values per task, which is strictly more expressive — two tasks in one process can hold different ring sizes, which a process-wide export never allowed. The env layer was a second, weaker way to say the same thing.

The removal deletes the whole parsing path from all four host/runtime_maker.cpp copies (trim_copy, parse_uint_token, apply_env_ring_value[s], and the scalar / comma-separated grammar), leaving per-task entries over the compile-time default with nothing in between. Net -283 lines, and two includes that existed only for that grammar.

Every diagnostic that advertised those variables moved with them. Otherwise the removal would have manufactured the third instance of the exact defect this PR already fixes twice: a hint naming a variable nothing reads. So the device-side ring-buffer and orchestrator deadlock reports, the fanin-spill capacity report, five error_hint() strings, both capacity tables in docs/troubleshooting/, the running-onboard triage table and the runnable recipe in docs/dfx/scope-stats.md now name runtime_env.ring_task_window / ring_heap / ring_dep_pool. Two unit tests assert on that hint text and move with it. MULTI_RING.md loses the two env tiers from its precedence ladder and the env-fallback section that was the only documentation of the comma-separated grammar.

One warning replaces the read. An unrecognised environment variable is ignored, so a caller still exporting one would run on the 256 MB default with its requested sizing nowhere in evidence — and the symptom is a heap-exhaustion deadlock that reads as a runtime regression rather than a config change. warn_on_retired_ring_env() names each retired variable that is set, once per bind, and points at CallConfig.runtime_env. Verified live: with all three exported, an a2a3sim scene test logs all three warnings and passes — proving both that the warning fires and that PTO2_RING_TASK_WINDOW=64 is now genuinely inert.

⚠️ This has a cross-repo edge, and the repo documents it itself. The deepseek example's comment records that pypto-lib's daily CI sizes that network the same way, and .claude/skills/multi-repo-qwen-setup told you to export PTO2_RING_HEAP=4294967296 for batch-16 qwen prefill — 4 GiB against a 256 MB default. That skill now gives the values as CallConfig.runtime_env fields and says outright that a runner still exporting the old names deadlocks exactly as its own gotcha section describes. A pypto-lib / pypto-serving change has to land for those paths; the warning is what makes the gap visible rather than silent, and is deletable once no caller sets them.

What is left

PTO2_MANUAL_MAX_SEQ (pypto-lib's knob, documented here and never read here), this rule file's own examples of the banned spelling, the retired-name list inside the warning, and prose recording that these names are gone. Rule 10 previously described a "~6.6k occurrences across 367 files" backlog; it now says the retirement is complete, so a new PTO2 match is a defect rather than leftover backlog for a regression to hide behind.

Cross-repo

RuntimeContext-style names are reachable from orchestration sources outside this repo. As with #1963, #1966 and #1969, this lands without compatibility aliases; matching renames and merge order are coordinated outside this PR.

⚠️ At 313 files the bot reviewer will skip this (100-file limit), as it did on #1963 and #1969. Splitting it into three stacked PRs is possible — say so and I will — but each would then block on the one below it. Every commit is independently reviewable and independently builds.

Testing

All at the final commit, rebased onto main, after pip install --no-build-isolation -e .:

  • all four runtime variants build; cpput targets build (the new gate) at every commit
  • a2a3sim scene sweep — 59 passed, 8 skipped, and again with all three retired env vars exported (warnings fire, values ignored)
  • a5sim scene sweep — 52 passed
  • a2a3 onboard sweep (-m "not sdma" --exclude-level 4) — 153 passed, 1 skipped
  • a2a3 quarantined SDMA step — 2 passed
  • cpput — 117/117; hardware-labelled test_comm_lifecycle — 1/1
  • pyut — 1908 passed, 14 skipped
  • clang-format --dry-run --Werror over 246 sources, markdownlint-cli2 over 45 docs, ruff, bash -n — all clean

@coderabbitai

coderabbitai Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 315 files, which is 215 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

Usage-priced reviews support at most 300 files.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b6fd9164-eced-4821-9e70-5b12517b26ff

📥 Commits

Reviewing files that changed from the base of the PR and between 8109ab1 and 08589fb.

📒 Files selected for processing (315)
  • .claude/rules/codestyle.md
  • .claude/rules/running-onboard.md
  • .claude/skills/multi-repo-qwen-setup/SKILL.md
  • CMakeLists.txt
  • docs/buffer-abi.md
  • docs/dfx/dep-gen.md
  • docs/dfx/profiling-config-naming.md
  • docs/dfx/scope-stats.md
  • docs/dynamic-linking.md
  • docs/investigations/2026-07-aicore-fills-all-args-ready-path.md
  • docs/investigations/2026-07-local-buffer-removal-ep-combine-regression.md
  • docs/investigations/2026-08-hbg-graph-definition-single-upload.md
  • docs/investigations/2026-08-host-orch-phase-tail-is-page-faults.md
  • docs/investigations/README.md
  • docs/manual-scope.md
  • docs/orchestrator.md
  • docs/task-flow.md
  • docs/troubleshooting/device-error-codes.md
  • docs/troubleshooting/device-error-codes/capacity.md
  • docs/troubleshooting/device-error-codes/stall.md
  • docs/troubleshooting/device-error-codes/untested.md
  • examples/a2a3/host_build_graph/deepseek_v4_flash_decode/kernels/orchestration/decode_fwd_graph.cpp
  • examples/a2a3/host_build_graph/qwen3_14b_decode/kernels/orchestration/decode_fwd_layers.cpp
  • examples/a2a3/tensormap_and_ringbuffer/deepseek_v4_flash_decode/kernels/orchestration/decode_fwd.cpp
  • examples/a2a3/tensormap_and_ringbuffer/deepseek_v4_flash_decode/test_deepseek_v4_flash_decode.py
  • examples/a2a3/tensormap_and_ringbuffer/paged_attention_manual_scope/README.md
  • examples/a2a3/tensormap_and_ringbuffer/paged_attention_manual_scope/kernels/orchestration/paged_attention_orch.cpp
  • examples/a2a3/tensormap_and_ringbuffer/paged_attention_ringbuffer/README.md
  • examples/a2a3/tensormap_and_ringbuffer/paged_attention_ringbuffer/test_paged_attention_ringbuffer.py
  • examples/a2a3/tensormap_and_ringbuffer/paged_attention_unroll_manual_scope/README.md
  • examples/a2a3/tensormap_and_ringbuffer/paged_attention_unroll_manual_scope/kernels/orchestration/paged_attention_orch.cpp
  • examples/a2a3/tensormap_and_ringbuffer/qwen3_14b_decode/kernels/orchestration/decode_fwd_layers.cpp
  • examples/a5/host_build_graph/qwen3_14b_decode/kernels/orchestration/decode_fwd_layers.cpp
  • examples/a5/tensormap_and_ringbuffer/paged_attention_manual_scope/kernels/orchestration/paged_attention_orch.cpp
  • examples/a5/tensormap_and_ringbuffer/paged_attention_ringbuffer/README.md
  • examples/a5/tensormap_and_ringbuffer/paged_attention_ringbuffer/test_paged_attention_ringbuffer.py
  • examples/a5/tensormap_and_ringbuffer/paged_attention_unroll_manual_scope/kernels/orchestration/paged_attention_orch.cpp
  • examples/a5/tensormap_and_ringbuffer/qwen3_14b_decode/README.md
  • examples/a5/tensormap_and_ringbuffer/qwen3_14b_decode/kernels/orchestration/decode_fwd_layers.cpp
  • examples/workers/l2/per_task_runtime_env/main.py
  • examples/workers/l3/per_task_runtime_env/README.md
  • examples/workers/l3/per_task_runtime_env/main.py
  • python/bindings/task_interface.cpp
  • python/simpler/worker.py
  • simpler_setup/scene_test.py
  • simpler_setup/tools/sched_overhead_analysis.py
  • simpler_setup/tools/swimlane_converter.py
  • src/a2a3/docs/runtimes.md
  • src/a2a3/runtime/host_build_graph/aicore/aicore_executor.cpp
  • src/a2a3/runtime/host_build_graph/aicpu/aicpu_executor.cpp
  • src/a2a3/runtime/host_build_graph/build_config.py
  • src/a2a3/runtime/host_build_graph/common/intrinsic.h
  • src/a2a3/runtime/host_build_graph/docs/RUNTIME_LOGIC.md
  • src/a2a3/runtime/host_build_graph/docs/SUBMIT_BY_CLUSTER.md
  • src/a2a3/runtime/host_build_graph/docs/profiling_levels.md
  • src/a2a3/runtime/host_build_graph/host/dep_gen_host_graph.cpp
  • src/a2a3/runtime/host_build_graph/host/runtime_maker.cpp
  • src/a2a3/runtime/host_build_graph/orchestration/orchestration_api.h
  • src/a2a3/runtime/host_build_graph/runtime/aicore_completion_mailbox.h
  • src/a2a3/runtime/host_build_graph/runtime/aicore_completion_mailbox_types.h
  • src/a2a3/runtime/host_build_graph/runtime/async_kernel_api.h
  • src/a2a3/runtime/host_build_graph/runtime/async_wait.h
  • src/a2a3/runtime/host_build_graph/runtime/backend/sdma/sdma_completion_scheduler.h
  • src/a2a3/runtime/host_build_graph/runtime/constants.h
  • src/a2a3/runtime/host_build_graph/runtime/dep_compute.h
  • src/a2a3/runtime/host_build_graph/runtime/dep_gen_host_graph.h
  • src/a2a3/runtime/host_build_graph/runtime/dispatch_payload.h
  • src/a2a3/runtime/host_build_graph/runtime/orchestrator.h
  • src/a2a3/runtime/host_build_graph/runtime/orchestrator_core/orchestrator.cpp
  • src/a2a3/runtime/host_build_graph/runtime/orchestrator_core/ring_buffer.cpp
  • src/a2a3/runtime/host_build_graph/runtime/orchestrator_core/runtime_core.cpp
  • src/a2a3/runtime/host_build_graph/runtime/ring_buffer.h
  • src/a2a3/runtime/host_build_graph/runtime/runtime.h
  • src/a2a3/runtime/host_build_graph/runtime/runtime_core.h
  • src/a2a3/runtime/host_build_graph/runtime/runtime_types.h
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler.cpp
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler.h
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler_cold_path.cpp
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler_completion.cpp
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler_context.h
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler_dispatch.cpp
  • src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler_types.h
  • src/a2a3/runtime/host_build_graph/runtime/shared/runtime_init.cpp
  • src/a2a3/runtime/host_build_graph/runtime/shared/shared_memory.cpp
  • src/a2a3/runtime/host_build_graph/runtime/shared/tensormap.cpp
  • src/a2a3/runtime/host_build_graph/runtime/shared_memory.h
  • src/a2a3/runtime/host_build_graph/runtime/submit_types.h
  • src/a2a3/runtime/host_build_graph/runtime/tensormap.h
  • src/a2a3/runtime/host_build_graph/runtime/types.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/aicore/aicore_executor.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/build_config.py
  • src/a2a3/runtime/tensormap_and_ringbuffer/common/intrinsic.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/docs/MULTI_RING.md
  • src/a2a3/runtime/tensormap_and_ringbuffer/docs/RUNTIME_LOGIC.md
  • src/a2a3/runtime/tensormap_and_ringbuffer/docs/SCALAR_DATA_ACCESS.md
  • src/a2a3/runtime/tensormap_and_ringbuffer/docs/SUBMIT_BY_CLUSTER.md
  • src/a2a3/runtime/tensormap_and_ringbuffer/docs/device_log_profiling.md
  • src/a2a3/runtime/tensormap_and_ringbuffer/docs/profiling_levels.md
  • src/a2a3/runtime/tensormap_and_ringbuffer/host/dep_gen_replay.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/host/dep_gen_replay.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/orchestration/orchestration_api.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/aicore_completion_mailbox.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/aicore_completion_mailbox_types.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/async_kernel_api.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/async_wait.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/backend/sdma/sdma_completion_scheduler.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/constants.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/dep_compute.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/dispatch_payload.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/orchestrator.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/orchestrator.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/ring_buffer.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/ring_buffer.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/runtime.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/runtime_core.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/runtime_core.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/runtime_types.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_cold_path.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_completion.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_context.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_dispatch.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_types.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/shared/runtime_init.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/shared/shared_memory.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/shared/tensormap.cpp
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/shared_memory.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/submit_types.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/tensormap.h
  • src/a2a3/runtime/tensormap_and_ringbuffer/runtime/types.h
  • src/a5/docs/runtimes.md
  • src/a5/runtime/host_build_graph/aicore/aicore_executor.cpp
  • src/a5/runtime/host_build_graph/aicpu/aicpu_executor.cpp
  • src/a5/runtime/host_build_graph/build_config.py
  • src/a5/runtime/host_build_graph/common/intrinsic.h
  • src/a5/runtime/host_build_graph/docs/RUNTIME_LOGIC.md
  • src/a5/runtime/host_build_graph/docs/SUBMIT_BY_CLUSTER.md
  • src/a5/runtime/host_build_graph/docs/profiling_levels.md
  • src/a5/runtime/host_build_graph/host/dep_gen_host_graph.cpp
  • src/a5/runtime/host_build_graph/host/runtime_maker.cpp
  • src/a5/runtime/host_build_graph/orchestration/orchestration_api.h
  • src/a5/runtime/host_build_graph/runtime/aicore_completion_mailbox.h
  • src/a5/runtime/host_build_graph/runtime/aicore_completion_mailbox_types.h
  • src/a5/runtime/host_build_graph/runtime/async_kernel_api.h
  • src/a5/runtime/host_build_graph/runtime/async_wait.h
  • src/a5/runtime/host_build_graph/runtime/constants.h
  • src/a5/runtime/host_build_graph/runtime/dep_compute.h
  • src/a5/runtime/host_build_graph/runtime/dep_gen_host_graph.h
  • src/a5/runtime/host_build_graph/runtime/dispatch_payload.h
  • src/a5/runtime/host_build_graph/runtime/orchestrator.h
  • src/a5/runtime/host_build_graph/runtime/orchestrator_core/orchestrator.cpp
  • src/a5/runtime/host_build_graph/runtime/orchestrator_core/ring_buffer.cpp
  • src/a5/runtime/host_build_graph/runtime/orchestrator_core/runtime_core.cpp
  • src/a5/runtime/host_build_graph/runtime/ring_buffer.h
  • src/a5/runtime/host_build_graph/runtime/runtime.h
  • src/a5/runtime/host_build_graph/runtime/runtime_core.h
  • src/a5/runtime/host_build_graph/runtime/runtime_types.h
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler.cpp
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler.h
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler_cold_path.cpp
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler_completion.cpp
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler_context.h
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler_dispatch.cpp
  • src/a5/runtime/host_build_graph/runtime/scheduler/scheduler_types.h
  • src/a5/runtime/host_build_graph/runtime/shared/runtime_init.cpp
  • src/a5/runtime/host_build_graph/runtime/shared/shared_memory.cpp
  • src/a5/runtime/host_build_graph/runtime/shared/tensormap.cpp
  • src/a5/runtime/host_build_graph/runtime/shared_memory.h
  • src/a5/runtime/host_build_graph/runtime/submit_types.h
  • src/a5/runtime/host_build_graph/runtime/tensormap.h
  • src/a5/runtime/host_build_graph/runtime/types.h
  • src/a5/runtime/tensormap_and_ringbuffer/aicore/aicore_executor.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/build_config.py
  • src/a5/runtime/tensormap_and_ringbuffer/common/intrinsic.h
  • src/a5/runtime/tensormap_and_ringbuffer/docs/MULTI_RING.md
  • src/a5/runtime/tensormap_and_ringbuffer/docs/RUNTIME_LOGIC.md
  • src/a5/runtime/tensormap_and_ringbuffer/docs/SCALAR_DATA_ACCESS.md
  • src/a5/runtime/tensormap_and_ringbuffer/docs/SUBMIT_BY_CLUSTER.md
  • src/a5/runtime/tensormap_and_ringbuffer/docs/device_log_profiling.md
  • src/a5/runtime/tensormap_and_ringbuffer/docs/profiling_levels.md
  • src/a5/runtime/tensormap_and_ringbuffer/host/dep_gen_replay.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/host/dep_gen_replay.h
  • src/a5/runtime/tensormap_and_ringbuffer/host/runtime_maker.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/orchestration/orchestration_api.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/aicore_completion_mailbox.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/aicore_completion_mailbox_types.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/async_kernel_api.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/async_wait.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/backend/urma/urma_completion_scheduler.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/constants.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/dep_compute.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/dispatch_payload.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/orchestrator.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/orchestrator.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/ring_buffer.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/ring_buffer.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime_core.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime_core.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/runtime_types.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_cold_path.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_completion.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_context.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_dispatch.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler_types.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/shared/runtime_init.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/shared/shared_memory.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/shared/tensormap.cpp
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/shared_memory.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/submit_types.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/tensormap.h
  • src/a5/runtime/tensormap_and_ringbuffer/runtime/types.h
  • src/common/hierarchical/orchestrator.h
  • src/common/hierarchical/ring.h
  • src/common/hierarchical/scope.h
  • src/common/hierarchical/tensormap.h
  • src/common/hierarchical/types.h
  • src/common/host_build_graph/docs/GRAPH_EXECUTION.md
  • src/common/host_build_graph/graph_execution.cpp
  • src/common/host_build_graph/graph_execution.h
  • src/common/platform/include/aicpu/args_dump_aicpu.h
  • src/common/platform/include/aicpu/chip_swimlane_collector_aicpu.h
  • src/common/platform/include/common/args_dump.h
  • src/common/platform/include/common/chip_swimlane_profiling.h
  • src/common/platform/include/common/dep_gen.h
  • src/common/platform/include/common/scope_stats.h
  • src/common/platform/onboard/host/device_runner_base.cpp
  • src/common/platform/onboard/host/device_runner_base.h
  • src/common/platform/shared/aicpu/dep_gen_collector_aicpu.cpp
  • src/common/platform/shared/aicpu/scope_stats_collector_aicpu.cpp
  • src/common/platform/shared/host/scope_stats_collector.cpp
  • src/common/platform/sim/host/device_runner_base.cpp
  • src/common/platform/sim/host/device_runner_base.h
  • src/common/runtime_status/error_names.h
  • src/common/task_interface/buffer.h
  • src/common/task_interface/call_config.h
  • src/common/task_interface/data_type.h
  • src/common/task_interface/task_args.h
  • src/common/task_interface/tensor.h
  • src/common/utils/device_arena.h
  • src/common/worker/runtime_c_api.h
  • tests/st/a2a3/host_build_graph/available_aicore_counts/kernels/orchestration/available_aicore_counts_orch.cpp
  • tests/st/a2a3/host_build_graph/dfx/dep_gen/test_dep_gen.py
  • tests/st/a2a3/host_build_graph/paged_attention/test_paged_attention.py
  • tests/st/a2a3/tensormap_and_ringbuffer/available_aicore_counts/kernels/orchestration/available_aicore_counts_orch.cpp
  • tests/st/a2a3/tensormap_and_ringbuffer/dfx/chip_swimlane/kernels/orchestration/sync_start_early_local_owner_orch.cpp
  • tests/st/a2a3/tensormap_and_ringbuffer/dfx/dep_gen/kernels/orchestration/chain_barrier_orch.cpp
  • tests/st/a2a3/tensormap_and_ringbuffer/dfx/dep_gen/test_dep_gen.py
  • tests/st/a2a3/tensormap_and_ringbuffer/dummy_task/kernels/orchestration/dummy_task_orch.cpp
  • tests/st/a2a3/tensormap_and_ringbuffer/spmd_sync_start_early_dispatch/kernels/orchestration/spmd_sync_start_early_dispatch_orch.cpp
  • tests/st/a5/host_build_graph/paged_attention/test_paged_attention.py
  • tests/st/a5/tensormap_and_ringbuffer/available_aicore_counts/kernels/orchestration/available_aicore_counts_orch.cpp
  • tests/st/a5/tensormap_and_ringbuffer/dfx/chip_swimlane/kernels/orchestration/sync_start_early_local_owner_orch.cpp
  • tests/st/a5/tensormap_and_ringbuffer/dfx/dep_gen/kernels/orchestration/chain_barrier_orch.cpp
  • tests/st/a5/tensormap_and_ringbuffer/dfx/dep_gen/test_dep_gen.py
  • tests/st/a5/tensormap_and_ringbuffer/dummy_task/kernels/orchestration/dummy_task_orch.cpp
  • tests/st/a5/tensormap_and_ringbuffer/spmd_sync_start_early_dispatch/kernels/orchestration/spmd_sync_start_early_dispatch_orch.cpp
  • tests/st/runtime_fatal_codes/kernels/orchestration/dep_pool_overflow_orch.cpp
  • tests/st/runtime_fatal_codes/kernels/orchestration/require_sync_start_orch.cpp
  • tests/st/runtime_fatal_codes/kernels/orchestration/tensor_wait_timeout_orch.cpp
  • tests/st/runtime_fatal_codes/test_runtime_fatal_codes.py
  • tests/ut/cpp/CMakeLists.txt
  • tests/ut/cpp/a2a3/test_a2a3_fatal.cpp
  • tests/ut/cpp/a2a3/test_aicore_completion_mailbox.cpp
  • tests/ut/cpp/a2a3/test_dep_list_pool.cpp
  • tests/ut/cpp/a2a3/test_fanin_pool.cpp
  • tests/ut/cpp/a2a3/test_graph_activation.cpp
  • tests/ut/cpp/a2a3/test_hbg_submit_poison.cpp
  • tests/ut/cpp/a2a3/test_hbg_task_allocator.cpp
  • tests/ut/cpp/a2a3/test_hbg_tensormap.cpp
  • tests/ut/cpp/a2a3/test_orchestrator_fanin.cpp
  • tests/ut/cpp/a2a3/test_ready_queue.cpp
  • tests/ut/cpp/a2a3/test_scheduler_state.cpp
  • tests/ut/cpp/a2a3/test_shared_memory.cpp
  • tests/ut/cpp/a2a3/test_task_allocator.cpp
  • tests/ut/cpp/a2a3/test_task_state.cpp
  • tests/ut/cpp/a2a3/test_task_timing_slots.cpp
  • tests/ut/cpp/a2a3/test_tensormap.cpp
  • tests/ut/cpp/a2a3/test_wiring.cpp
  • tests/ut/cpp/a5/test_a5_fatal.cpp
  • tests/ut/cpp/a5/test_aicore_completion_mailbox.cpp
  • tests/ut/cpp/a5/test_dep_list_pool.cpp
  • tests/ut/cpp/a5/test_fanin_pool.cpp
  • tests/ut/cpp/a5/test_graph_activation.cpp
  • tests/ut/cpp/a5/test_hbg_submit_poison.cpp
  • tests/ut/cpp/a5/test_orchestrator_fanin.cpp
  • tests/ut/cpp/a5/test_ready_queue.cpp
  • tests/ut/cpp/a5/test_scheduler_state.cpp
  • tests/ut/cpp/a5/test_shared_memory.cpp
  • tests/ut/cpp/a5/test_task_allocator.cpp
  • tests/ut/cpp/a5/test_task_state.cpp
  • tests/ut/cpp/a5/test_tensormap.cpp
  • tests/ut/cpp/a5/test_wiring.cpp
  • tests/ut/cpp/common/test_hbg_core_tracker.cpp
  • tests/ut/cpp/common/test_hbg_graph_async_submit.cpp
  • tests/ut/cpp/common/test_hbg_graph_cache.cpp
  • tests/ut/cpp/common/test_hbg_graph_definition_arena.cpp
  • tests/ut/cpp/common/test_hbg_graph_submit_failure.cpp
  • tests/ut/cpp/common/test_hbg_ready_queue_seed.cpp
  • tests/ut/cpp/common/test_hbg_scheduler_drain.cpp
  • tests/ut/cpp/common/test_hbg_self_relative_ptr.cpp
  • tests/ut/cpp/common/test_hbg_slot_claim.cpp
  • tests/ut/cpp/common/test_hbg_sm_compaction.cpp
  • tests/ut/cpp/common/test_scope_deadlock_detection.cpp
  • tests/ut/cpp/common/test_trb_runtime_temp_buffer.cpp
  • tests/ut/cpp/stubs/test_stubs.cpp
  • tests/ut/py/test_resource_failure_summary.py
  • tests/ut/py/test_worker/test_host_worker.py
  • tools/benchmark_rounds.sh

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


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.

@ChaoWao
ChaoWao force-pushed the refactor/retire-pto2-remaining branch 2 times, most recently from 6d93b70 to 4e15283 Compare August 24, 2026 12:05
ChaoWao and others added 21 commits August 24, 2026 18:02
`PTO2ResourceShape` becomes `ResourceShape` and `PTO2_NUM_RESOURCE_SHAPES` becomes
`NUM_RESOURCE_SHAPES`. Both names are free: nothing else in the tree, in the CANN
headers, or in pto-isa spells either of them, so this is a plain prefix strip. 474
occurrences across 46 files.

The constant is that enum's cardinality, so it moves with the type rather than in
a commit of its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TaskDescriptor` -> `TaskDescriptor`, `PTO2TaskPayload` -> `TaskPayload`,
`PTO2PreparedTask` -> `PreparedTask`, and the seven `PTO2_TASKPAYLOAD_*` field
offsets lose the prefix with them. All plain strips: no declaration anywhere in
the tree, in the CANN headers or in pto-isa holds any of these names. 561
occurrences across 81 files.

The offset macros describe the layout of the payload the AICore reads, so they
belong to `TaskPayload` and move with it rather than in a commit of their own.

The shared-memory layout diagrams in `runtime/shared_memory.h` and
`docs/RUNTIME_LOGIC.md` already write `TaskDescriptor[]` and `TaskPayload[]`, so
two of their three rows become literally true here. They are corrected once, in
the commit that renames `SharedMemoryHeader`, when every name in the box is a name
that exists.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2SharedMemoryHeader` -> `SharedMemoryHeader`, `PTO2SharedMemoryRingHeader` ->
`SharedMemoryRingHeader`, `PTO2SharedMemoryHandle` -> `SharedMemoryHandle`,
`PTO2SharedMemory` -> `SharedMemory`, and the `pto2_sm_layout` namespace becomes
`sm_layout`. All plain strips; 602 occurrences across 82 files.

The namespace is the case rule 9 has in mind when it asks for "clear names or a
`namespace`" in place of the prefix: `sm_layout::ring_segment_offsets` is already
qualified, so the `pto2_` on the namespace itself was pure noise.

This is also where the shared-memory layout diagrams become true, which is what
the `ChipTaskSlotState` commit deferred them for. Every row of those boxes now
names a type that exists under exactly that spelling — `SharedMemoryHeader`,
`TaskDescriptor[]`, `TaskPayload[]`, `ChipTaskSlotState[]` — in all four
`runtime/shared_memory.h` copies and in the `sizeof` formula in both
`tensormap_and_ringbuffer/docs/RUNTIME_LOGIC.md` copies. The two multi-ring boxes
widen by four columns because the corrected name no longer fits beside the
`Ring N:` prefix.

The bare `TaskSlotState` that remains in `docs/orchestrator.md`,
`docs/callable-identity-registration.md` and `docs/hierarchical-level-runtime.md`
is the host orchestrator's own type and stays as it is.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2SchedulerState` -> `SchedulerState`, `PTO2SchedulerLayout` ->
`SchedulerLayout`, `PTO2SchedProfilingData` -> `SchedProfilingData`, and the two
`PTO2_SCHED_CYCLE_*` markers lose the prefix with them. All plain strips: no
declaration in the tree, in the CANN headers or in pto-isa holds any of these
names. 397 occurrences across 71 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2OrchestratorState` -> `OrchestratorState`, `PTO2OrchestratorLayout` ->
`OrchestratorLayout`, `PTO2OrchProfilingData` -> `OrchProfilingData`. All plain
strips; 236 occurrences across 42 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TensorMap` becomes `ChipTensorMap` — not `TensorMap`, because
`src/common/hierarchical/tensormap.h:46` already declares a `class TensorMap`:
the host orchestrator's producer lookup, which resolves `TensorKey` to a host
`TaskSlot`. This one is the chip runtime's lazily-invalidated device-side map that
the AICPU orchestrator walks to infer dependencies. Two maps, two contexts, so
`.claude/rules/codestyle.md` rule 13 gives the bare name to the L3+ side and the
`Chip` prefix to this one.

Its satellites take the same prefix, so the cluster reads one way throughout:
`ChipTensorMapEntry`, `ChipTensorMapLayout`, `ChipTensorMapProfilingData`,
`chip_tensormap_get_profiling`, and the three capacity constants
`CHIP_TENSORMAP_POOL_SIZE` / `CHIP_TENSORMAP_NUM_BUCKETS` /
`CHIP_TENSORMAP_CLEANUP_INTERVAL`. `PTO2LookupResult` is a plain strip to
`LookupResult`: it names no map of its own and nothing else claims the name.

445 occurrences across 61 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2ReadyQueue` becomes `ChipReadyQueue` — not `ReadyQueue`, because
`src/common/hierarchical/types.h:509` already declares a `class ReadyQueue` for
the host orchestrator. This one is the device-side sharded queue the AICPU
scheduler threads claim from. Rule 13 gives the bare name to the L3+ side.

`ChipReadyQueueSlot` and the two capacity constants `CHIP_READY_QUEUE_SIZE` /
`CHIP_PROF_READYQUEUE_SIZE` follow it, so the queue and its slot type read the same
way. `PTO2LocalReadyBuffer` is a plain strip to `LocalReadyBuffer` — it is a
per-thread staging buffer rather than a queue, and nothing else claims the name.

212 occurrences across 32 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TaskState` becomes `ChipTaskState`, with its three enumerators
`CHIP_TASK_PENDING` / `CHIP_TASK_COMPLETED` / `CHIP_TASK_CONSUMED`. `TaskState` is
not available: `src/common/hierarchical/types.h:203` declares an `enum class
TaskState` for the host orchestrator, and that one is bound into Python — both
`python/simpler/task_interface.py` and `tests/ut/py/test_task_interface.py` import
the name. Rule 13 gives the bare name to the L3+ side; the enumerators keep the
type's prefix so a reader cannot mistake a chip-side PENDING for the host's.

The lifecycle flags in the same header are plain strips —
`TaskLifecycleFlag`, `LIFECYCLE_FLAGS_NONE`, `READY_CLAIMED`, `COMPLETION_DONE`,
`SUBTASK_DEFERRED`, `DISPATCH_PROPAGATED` — because nothing else in the tree, in
the CANN headers or in pto-isa claims any of them. They move here rather than in a
commit of their own: they are the other half of the same 64-byte slot's state word.

362 occurrences across 40 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The five ring types take the `Chip` prefix as one cluster: `ChipTaskRing`,
`ChipHeapRing`, `ChipRingSet`, `ChipRingFlowControl`, `ChipRingSegmentOffsets`.

`HeapRing` is the name that forces it — `src/common/hierarchical/ring.h:151`
declares a `struct HeapRing` inside the host orchestrator's `class Ring`, which
owns `mmap`ed host slabs with a mutex and condition variable. The chip runtime's
rings live in the device shared-memory image and are advanced by atomic counters.
Rule 13 gives the bare names to the L3+ side.

The other four do not collide on their own, but they are the same ring: splitting
the cluster would leave `ChipHeapRing` and `RingFlowControl` as fields of one
struct, which reads as two subsystems rather than one.

85 occurrences across 25 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2TaskAllocator` -> `TaskAllocator`, `PTO2TaskAllocResult` -> `TaskAllocResult`,
`PTO2_ALLOC_DEADLOCK_TIMEOUT_CYCLES` -> `ALLOC_DEADLOCK_TIMEOUT_CYCLES`. 84
occurrences across 33 files.

All three are plain strips, and `TaskAllocResult` is the one worth naming: the host
orchestrator has a `struct AllocResult` in `src/common/hierarchical/ring.h:86`, so
dropping `Task` as well as the prefix would have collided. Keeping it distinguishes
the chip runtime's ring allocation from the host's heap-slab allocation without
needing the `Chip` prefix.

The timeout is the reclaim backstop that allocator enforces, so it moves with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2FaninPool` -> `FaninPool`, `PTO2FaninSpillEntry` -> `FaninSpillEntry`,
`PTO2FaninBuilder` -> `FaninBuilder`, `PTO2FaninForEachReturn` ->
`FaninForEachReturn`, `PTO2FaninCallbackResult` -> `FaninCallbackResult`, and the
`FANOUT_SCOPE_BIT` constant. 327 occurrences across 53 files.

One dependency-edge mechanism, so it moves as one commit: the pool that holds the
spill entries, the builder that fills them, the traversal's return type, and the
bit that marks a scope reference.

The two caps stay prefixed as `CHIP_FANIN_INLINE_CAP` and `CHIP_MAX_FANIN`: both
are object-like macros in `runtime/runtime_types.h`, which the whole tree
includes. A macro captures its identifier textually rather than declaring
anything, so a bare `MAX_FANIN` would silently rewrite any unrelated
`MAX_FANIN` a caller happens to declare, instead of colliding where the compiler
can say so. `FANOUT_SCOPE_BIT` is an `inline constexpr` and needs no such
protection.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2DepListEntry` -> `DepListEntry` and `PTO2DepListPool` -> `DepListPool`. 124
occurrences across 35 files.

The four constants that size and instrument the pool keep a prefix —
`CHIP_DEP_LIST_POOL_SIZE`, `CHIP_DEP_POOL_CLEANUP_INTERVAL`,
`CHIP_DEP_DEGREE_DEBUG_THRESHOLD`, `CHIP_DEP_DEGREE_WARN_THRESHOLD` — because they
are object-like macros in `runtime/runtime_types.h` and a macro rewrites its
identifier in every translation unit that includes the header rather than
declaring something the compiler can diagnose.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The two state machines lose the prefix together: `EarlyDispatchState` with its
`EARLY_DISPATCH_*` values and the `EarlyDispatchLaunchState` sub-state,
`EarlySyncDrainState` with its `EARLY_SYNC_DRAIN_*` values, and
`EARLY_DISPATCH_CORE_MASK_WORDS`. 356 occurrences across 25 files.

An enum and its enumerators cannot be split across commits without leaving the
type and its values on two conventions, and the drain state is the handshake the
dispatch state waits on, so the two read as one mechanism.

`CHIP_EARLY_DISPATCH_QUEUE_SIZE` keeps a prefix: unlike the enumerators, it is an
object-like macro in `runtime/runtime_types.h`, so a bare name would capture the
identifier textually across every including translation unit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2SubtaskSlot` -> `SubtaskSlot` with `SUBTASK_SLOT_COUNT` and the three
`SUBTASK_MASK_AIC` / `SUBTASK_MASK_AIV0` / `SUBTASK_MASK_AIV1` selectors, and
`PTO2DispatchPayload` -> `DispatchPayload` with `DISPATCH_MAX_ARGS`. 442
occurrences across 72 files.

All five constants here are `inline constexpr` in `runtime/submit_types.h` rather
than macros, so they can take the bare name: a clash would be a redeclaration the
compiler reports, not a silent textual rewrite.

The masks name the slots, so they move with the slot type; the payload is what a
dispatch writes into one, so its argument cap moves with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2ScopeMode` -> `ScopeMode` is a plain strip. The two capacities are not:
`CHIP_MAX_SCOPE_DEPTH` and `CHIP_SCOPE_TASKS_CAP` keep a prefix because
`src/common/hierarchical/types.h:117` already declares
`static constexpr int32_t MAX_SCOPE_DEPTH = 64` for the host orchestrator — and
because the chip runtime's version is an object-like macro, the bare name would not
have collided cleanly. It would have textually rewritten the host's declaration
into `static constexpr int32_t 64 = 64;` in any translation unit that saw the chip
header first. Rule 13 gives the bare name to the L3+ side regardless.

The two scope-stats collector bounds do take bare names —
`SCOPE_STATS_MAX_RING_DEPTH`, `SCOPE_STATS_MAX_SCOPE_DEPTH` — since they are
already qualified by what they bound and nothing else spells them.

176 occurrences across 62 files. These are what the `SIMPLER_SCOPE` commit left
behind: it renamed the macro and its guard, not the mode enum the macro sets or the
caps that bound a scope.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2_ALIGN_UP` becomes `CHIP_ALIGN_UP` rather than `ALIGN_UP`, because CANN
already defines `ALIGN_UP` — in `acl/ops/acl_dvpp.h` and
`acl/dvpp/hi_media_common.h`, both reachable from translation units that include
our headers. No grep of this repository can see that, which is why the check has to
run against the external headers we compile against and not only against the tree.

`PTO2_ALIGN_SIZE` takes the same prefix even though `ALIGN_SIZE` is free. The two
are one pair — the granularity and the macro that rounds to it — and splitting
their spelling would read as two unrelated constants.

`PTO2_PACKED_OUTPUT_ALIGN` is a plain strip to `PACKED_OUTPUT_ALIGN`: it belongs to
the packed-output layout rather than to the arena's alignment, and nothing claims
the name.

343 occurrences across 70 files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The last of the identifier work: the waits `TENSOR_DATA_TIMEOUT_CYCLES` /
`TENSOR_DATA_TIMEOUT_MS`, the caps `DEFERRED_RELEASE_CAP` and `EXT_PARAMS_COUNT`,
the three `MODE_*` runtime modes, the types `LaunchSpec` and `OutputLayout`, the
`ORCHESTRATION_CONFIG_DEFINED` include guard, and the file-local
`read_runtime_status` helper. 239 occurrences across 83 files.

Four keep a prefix because they are object-like macros rather than `constexpr`:
`CHIP_TASK_WINDOW_SIZE`, `CHIP_HEAP_SIZE`, `CHIP_BLOCK_NOTIFY_INTERVAL` and
`CHIP_PUBLICATION_REQUEST_TIMEOUT_CYCLES`. `HEAP_SIZE` is the one that proves the
rule rather than merely satisfying it: three cpput fixtures declare
`static constexpr uint64_t HEAP_SIZE = 4096;`, and `#define HEAP_SIZE (256 * 1024 *
1024)` rewrites that declaration into `static constexpr uint64_t (256 * 1024 *
1024) = 4096;`. The runtime build never sees it — the C++ unit tests are a separate
CMake project — so the gate for a rename has to compile both.

`read_runtime_status` is `static` in all four `host/runtime_maker.cpp` copies, so
the prefix bought it nothing that internal linkage did not already provide.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both named a `PTO2_*` variable that nothing reads, and both failed silently
because an unrecognised environment variable is simply ignored.

`tools/benchmark_rounds.sh --serial-orch-sched` set `PTO2_SERIAL_ORCH_SCHED=1`
for its second arm. The runtime reads `SIMPLER_TMR_SERIAL_ORCH_SCHED_ENABLE`
(`tensormap_and_ringbuffer/host/runtime_maker.cpp`), so the serial arm ran with
serial orch->sched still off: the script measured the parallel path twice and
reported the pair as a serial-versus-parallel comparison. Any measurement taken
through that flag is void.

`error_hint(SIMPLER_ERROR_SCHEDULER_TIMEOUT)` told the user to raise
`PTO2_SCHEDULER_TIMEOUT_MS`. The knob is `SIMPLER_SCHEDULER_TIMEOUT_MS`
(`common/platform/include/host/runtime_timeout_config.h`), which CI already sets
by that name, so following the hint on a scheduler-timeout fatal changed nothing
and made a slow kernel look like a real deadlock.

Found while sweeping the `PTO2` prefix out of the runtime: both survived only
because they are strings, so no compiler ever checked them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The last of the prefix, and the only tier of it that was never an identifier: the
brand as a word. `PTO2 shared memory` becomes `shared memory`, `PTO2 integration:`
becomes what that map is for, `Extension to the PTO2 runtime` names
`tensormap_and_ringbuffer`, and the doc titles say what they document.

Log text moves with the docs that quote it, so the documented string keeps matching
the emitted one: `progress: completed=`, `total submitted tasks`,
`completed tasks`, `dispatch starting with`, `scheduler timeout sub_class=`,
`=== Shared Memory Layout ===` and two failure messages, together with every
mention of them in `profiling_levels.md` and `device_log_profiling.md`.

Four file-local identifiers go too: `read_pto2_runtime_status`,
`normalize_pto2_task_id_int`, and the locals `pto2_sm` and `pto2_count` — the last
renamed to `window_tasks`, which is what it counts.

Three references named things that do not exist, which is how a stale comment
becomes a lie rather than just noise:

- `pto2_task_slot(sched, task_id)`, cited by `runtime_types.h` and
  `runtime_init.cpp` as the way to compute a slot. There is no such function; the
  slot is `local_id` masked by the window size, and that is what the comment now
  says — including why the window has to be a power of two.
- `pto2_run_runtime`, which `docs/task-flow.md` names five times as the L2 ABI
  edge. The entry point is `simpler_run`.
- `pto2_init_*` flags, which `docs/dynamic-linking.md` lists among the fields
  `SchedulerContext::deinit()` resets. It resets no such flag, and none exists
  under any spelling, so the clause is gone.

`docs/dfx/profiling-config-naming.md` claimed `PTO2_` was "the device runtime's
internal namespace" and then illustrated it with `CHIP_MAX_RING_DEPTH`,
`SIMPLER_ERROR_*` and `RuntimeContext` — three names that had already left it. It
now states the convention that actually holds, including why an object-like macro
takes `CHIP_` where a `constexpr` does not, and records why
`PTO2_RING_TASK_WINDOW` / `PTO2_RING_HEAP` / `PTO2_RING_DEP_POOL` keep the legacy
spelling: they are read from the environment by name, so a rename is ignored
silently instead of failing to compile, and retiring them needs a cross-repo
migration.

`.claude/rules/codestyle.md` is untouched. Its `PTO2` mentions are the rule that
bans the prefix.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rule 10 still described a ~6.6k-occurrence backlog across 367 files. There are 129
occurrences left and every one is deliberate: the three `PTO2_RING_*` environment
knobs, `PTO2_MANUAL_MAX_SEQ` (pypto-lib's, documented here only), and the rule's own
illustrations of the banned spelling. Left as it was, the rule would send the next
contributor looking for a sweep that no longer exists — and, worse, would let a
genuine regression look like leftover backlog. A `PTO2` match now means a Tier-C
knob or a defect.

Two additions come from doing the work rather than from restating it:

- Why an environment variable is the worst case in Tier C: an unrecognised name is
  ignored, so the rename fails silently in production instead of at compile time.
  Two knobs had already drifted that way and were dead when found.
- What to check a target name against. The bare name may be held by the host
  orchestrator under `src/common/hierarchical/` (rule 13 decides who keeps it), by
  an external header the same translation units include (CANN defines `ALIGN_UP`),
  or — for an object-like macro — by any declaration at all, since a macro rewrites
  its identifier textually instead of colliding where the compiler can report it.
  Checking only the first of the three is how `#define HEAP_SIZE` came to rewrite a
  unit test's `static constexpr uint64_t HEAP_SIZE = 4096`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`PTO2_RING_TASK_WINDOW`, `PTO2_RING_HEAP` and `PTO2_RING_DEP_POOL` are no longer
read. `CallConfig.runtime_env` carries the same three values per task, and is
strictly more expressive: two tasks in one process can hold different ring sizes,
which a process-wide export never allowed. So the env layer was not a fallback
worth keeping — it was a second way to say the same thing, in a weaker form, and
the one spelling of it that could not be renamed.

Removing it deletes the whole parsing path from all four `host/runtime_maker.cpp`
copies — `trim_copy`, `parse_uint_token`, `apply_env_ring_value[s]` and the scalar
/ comma-separated grammar they implemented — leaving per-task entries over the
compile-time default with nothing in between. `<cctype>` and (in host_build_graph)
`<limits>` were there only for that grammar and go with it. Net -283 lines.

What replaces it is one warning. An unrecognised environment variable is *ignored*,
so a caller that still exports one of these would otherwise run on the 256 MB
default with the sizing it asked for nowhere in evidence — and the observable
symptom is a heap-exhaustion deadlock that looks like a runtime regression rather
than a configuration change. `warn_on_retired_ring_env()` reports each retired name
that is set, once per bind, and points at `CallConfig.runtime_env`. It is a
migration aid with no behavioral effect; delete it once no caller sets them.

**Every diagnostic that advertised these variables had to move with them**, or the
removal would have manufactured the same defect this branch already fixed twice
(`PTO2_SERIAL_ORCH_SCHED`, `PTO2_SCHEDULER_TIMEOUT_MS`): a hint naming a variable
nothing reads. So the device-side ring-buffer and orchestrator deadlock reports,
the fanin-spill capacity report, the five `error_hint()` strings, the two capacity
tables in `docs/troubleshooting/`, the `running-onboard` triage table, and the
runnable command in `docs/dfx/scope-stats.md` now name
`runtime_env.ring_task_window` / `ring_heap` / `ring_dep_pool`. Two unit tests
assert on that hint text and move with it.

`MULTI_RING.md` loses the two env tiers from its precedence ladder and its
env-fallback section, which was the only place the comma-separated per-ring
grammar was documented.

The cross-repo edge is real and named where it matters. The deepseek example's own
comment records that pypto-lib's daily CI sizes this network the same way, and
`.claude/skills/multi-repo-qwen-setup` documented exporting
`PTO2_RING_HEAP=4294967296` for batch-16 qwen prefill — 4 GiB, against a 256 MB
default. That skill now gives the values as `CallConfig.runtime_env` fields and
states outright that a runner still exporting the old names deadlocks exactly as
its own gotcha section describes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ChaoWao
ChaoWao force-pushed the refactor/retire-pto2-remaining branch from 4e15283 to 7f16161 Compare August 25, 2026 01:11
`simpler_setup/runtime_compiler.py` sets `SIMPLER_CMAKE_DIR` to
`PROJECT_ROOT / "cmake"`, which is `simpler_setup/_assets/cmake` in an installed
package. The `SKBUILD_MODE` install block never created it, so every runtime cmake
configure from a wheel install failed on the first `include()`:

    CMake Error at CMakeLists.txt:21 (include):
      include could not find requested file:
        .../site-packages/simpler_setup/_assets/cmake/host_log_sources.cmake

which then surfaces as `ValueError: empty compile database` from the clang-tidy
pre-commit hook, and because every gated CI job declares `pre-commit` in `needs:`,
it skips the entire test matrix rather than failing one job.

All four files under `cmake/` are reachable from a platform configure, so the whole
directory ships: `host_log_sources.cmake` and `profiling_config.cmake` are included
unconditionally by the platform `CMakeLists.txt`, `profiling_config.cmake`
configures `profiling_build_config.h.in`, and `sanitizers.cmake` is included for a
sanitizer build. Installing only the file named in the error would have failed at
the next `include()` instead.

Dates from hw-native-sys#1845, which added `include("${SIMPLER_CMAKE_DIR}/host_log_sources.cmake")`
to six platform `CMakeLists.txt` without an install rule to match. It stayed hidden
because the hook only configures on a build-cache miss, and `tools/verify_packaging.sh`
checks the entry points rather than the asset tree.

Verified by building the wheel both ways: `pip wheel --no-build-isolation --no-deps .`
produces zero `simpler_setup/_assets/cmake/*` entries before this change and all four
after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ChaoWao

ChaoWao commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator Author

Acknowledged on the skipped review — 314 files is over the 100-file limit, and the PR body records that consequence up front. Splitting is possible (three stacked PRs of ~7 commits each) but each would then block on the one below it; every one of the 22 commits is independently reviewable and independently builds both the runtime .so files and the cpput targets, which is the mitigation.

Separately, pre-commit was failing here for a reason unrelated to this diff, and because every gated job declares it in needs: it skipped the whole test matrix. #1845 added include("${SIMPLER_CMAKE_DIR}/host_log_sources.cmake") to six platform CMakeLists.txt without an install rule to match, so simpler_setup/_assets/cmake/ never shipped and any runtime cmake configure from a wheel install failed on that include. Only visible on a build-cache miss, which is why this PR was green on its previous push. Fixed here with the missing install(DIRECTORY cmake/ ...), verified by building the wheel both ways: zero _assets/cmake/* entries before, all four after.

@ChaoWao
ChaoWao merged commit 3d006c1 into hw-native-sys:main Aug 25, 2026
20 checks passed
@ChaoWao
ChaoWao deleted the refactor/retire-pto2-remaining branch August 25, 2026 01:57
ChaoWao added a commit to ChaoWao/simpler-fork that referenced this pull request Aug 25, 2026
…nsor

An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things
about it: which task produced it, the version its OverlapMap keys on, whether
dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself,
in `src/common/task_interface/`, so one type served the boundary and both
runtimes' working state. `create_from_chip_args` recorded the mismatch as an
assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are
meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling
`ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while
`ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a
`make()` factory.

The fusion dates to hw-native-sys#1093, which needed the strided view hw-native-sys#808 had just given the
runtime's tensor to reach the argument boundary, and got there by promoting the
runtime-private header into `task_interface/` rather than adding strides to the
40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a
mailbox doubling for a capability that PR noted was not yet used: two months on,
`make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors.
with a cost argument that applies equally here; nobody undid it at L2.

`ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view.

    struct ChipTensor {
        PTOBufferHandle buffer;
        uint64_t start_offset;
        uint32_t shapes[MAX_TENSOR_DIMS];
        uint32_t strides[MAX_TENSOR_DIMS];
        uint32_t ndims;
        DataType dtype;
        AddressSpace address_space;
    };

`simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry
plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the
geometry. One copy each, shared across architectures, placed the way
`src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg`
was an existing namespace.

`Runtime::set_orch_args` is the single place one becomes the other. Both runtimes
call it only from `host/runtime_maker.cpp`, so adoption happens on the host before
any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU
executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of
converting per run. From there inward nothing holds the argument form:
orchestration, the payload, the TensorMap and the kernels all name their runtime's
type.

A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's
include path, so existing `#include "tensor.h"` lines resolve to both types
without an include sweep. That shim names the two headers by their path under
`src/common`, which every platform target but `aicore` already had on its include
path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings
carry.

`is_contiguous` and `extent_elem` become methods that compute from the geometry;
a runtime that reads them per task caches them on its own `Tensor`. The view ops
and the copy helpers that maintained those caches move with them — an argument is
not a thing you take views of, and nothing outside a runtime called them.
`init_external` and both factories lose their `manual_dep` / `version` parameters,
which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a
friend, and the boundary header no longer includes `task_id.h`: it names no TaskId
at all.

`sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor
cap. `MAILBOX_SIZE` is unaffected — since hw-native-sys#1729 the frame is sized by the 144 B
wire `Tensor`.

`ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level
layout so three copy paths could each be a single 64-byte `memcpy`, held by 21
hand-written `offsetof` assertions across four trees. Two of the three were shaped
backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` /
`__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` /
`::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a
`PTO2TensorMapEntry *` field, its comment noting this was "harmless because
`link_entry()` overwrites `next_in_bucket` immediately after".

Each struct now assigns the fields it wants, by name. The optimization the
`memcpy` existed for survives as intent: a canonically contiguous source has the
derived pair recomputed from `shapes` rather than read across.
`PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in
any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an
entry. The entry keeps its own two-cache-line split and the assertions describing
it; what goes is the claim that its bytes agree with a different struct's.

A source that names one runtime's `Tensor` cannot be compiled under the other, and
57 scene-test sources were: a `host_build_graph` case naming the
`tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer`
classes taking an hbg class's `CALLABLE` verbatim. That worked only because
`ChipTensor` happened to be identical in both trees — the coupling this change
removes.

Each borrowing case now carries its own sources, 73 files, and names local paths.
The two class-reuse cases rebase the inherited `CALLABLE` onto their own
`kernels/` copy through a `_rebase_callable` helper, so the Python that drives
them stays in one file while the C++ each runtime compiles is its own.
`task_timing_slots` carries the runtime in a function default rather than a
`@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the
helper builds the path from the runtime it is driving. The cost is real:
`spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`,
`paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist
once per runtime and the copies can drift. A case that asserts something about
`host_build_graph` should not depend on a file the other runtime owns.

`examples/` orchestration and kernel sources lose their `Generated by PyPTO IR
Compiler` marker: they are this repository's sources, and this change edits them.

`tensor_create_info.h`'s doc paragraph said `host_build_graph` has no
initial-value fill "unlike the tensormap_and_ringbuffer copy of this header",
which hw-native-sys#1981 made false by removing that fill; both copies now describe what is
there.

The copies were taken from sources whose spellings `main` has since retired — hw-native-sys#1980
finished that retirement repo-wide — so they carry the current ones.

`test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify
packing Graph boundaries into the payload's tensor slots, and read that pool as
`ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` —
the assertion was true only while one type served both roles.

Verification: full rebuild of both runtimes on both architectures, cpput 119/119,
pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim
sweeps build only the cases they run, so every orchestration source was also
syntax-checked against its runtime's include path — 129 (source, runtime, arch)
compiles, which is what caught a copy under host_build_graph/ still calling
simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a
Python driver mentions rather than its @scene_test decorator; that is what caught
task_timing_slots.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ChaoWao added a commit that referenced this pull request Aug 25, 2026
`ChipHeapRing` and `ChipTaskRing` do not exist. `TaskAllocator` unified the task
window and the heap — its own header says so ("Unified task slot + heap buffer
allocator … checks both resources BEFORE committing to either") and so does the
allocator unit test — but four documents still described the two as live types, and
`ChipRingSet` as an aggregate of them:

    struct ChipRingSet {
        ChipHeapRing   heap_ring;     // neither member exists
        ChipTaskRing   task_ring;
        FaninPool fanin_pool;
    };

The real struct is `TaskAllocator task_allocator; FaninPool fanin_pool;`.

Both names now survive nowhere but in prose, which is what makes this worth fixing
rather than leaving: retiring the `PTO2` prefix in #1980 renamed these mentions along
with everything else, so a description that had been stale since the two types were
folded together started reading as a current one. The rename's own collision check
could not have caught it — it asks whether the target name is taken, not whether the
source name still names anything.

So `MULTI_RING.md` §4.1 gives `ChipRingSet` its real members and says why there is no
separate ring type to hold, §4.2's before/after shows the layout that actually
preceded the per-ring array, and `RUNTIME_LOGIC.md` labels its two structure sections
as the task-window and heap halves of the one allocator instead of two types. The
allocator test's header drops the same two names for what the class guarantees.

`docs/dfx/scope-stats.md` had the ring formula as `min(depth, MAX_RING_DEPTH−1)`;
`scope_stats.h` computes it with `CHIP_MAX_RING_DEPTH`, and the bare spelling is the
host orchestrator's own constant, so the doc pointed at the wrong one.
ChaoWao added a commit to ChaoWao/simpler-fork that referenced this pull request Aug 25, 2026
…nsor

An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things
about it: which task produced it, the version its OverlapMap keys on, whether
dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself,
in `src/common/task_interface/`, so one type served the boundary and both
runtimes' working state. `create_from_chip_args` recorded the mismatch as an
assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are
meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling
`ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while
`ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a
`make()` factory.

The fusion dates to hw-native-sys#1093, which needed the strided view hw-native-sys#808 had just given the
runtime's tensor to reach the argument boundary, and got there by promoting the
runtime-private header into `task_interface/` rather than adding strides to the
40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a
mailbox doubling for a capability that PR noted was not yet used: two months on,
`make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors.
with a cost argument that applies equally here; nobody undid it at L2.

`ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view.

    struct ChipTensor {
        PTOBufferHandle buffer;
        uint64_t start_offset;
        uint32_t shapes[MAX_TENSOR_DIMS];
        uint32_t strides[MAX_TENSOR_DIMS];
        uint32_t ndims;
        DataType dtype;
        AddressSpace address_space;
    };

`simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry
plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the
geometry. One copy each, shared across architectures, placed the way
`src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg`
was an existing namespace.

`Runtime::set_orch_args` is the single place one becomes the other. Both runtimes
call it only from `host/runtime_maker.cpp`, so adoption happens on the host before
any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU
executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of
converting per run. From there inward nothing holds the argument form:
orchestration, the payload, the TensorMap and the kernels all name their runtime's
type.

A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's
include path, so existing `#include "tensor.h"` lines resolve to both types
without an include sweep. That shim names the two headers by their path under
`src/common`, which every platform target but `aicore` already had on its include
path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings
carry.

`is_contiguous` and `extent_elem` become methods that compute from the geometry;
a runtime that reads them per task caches them on its own `Tensor`. The view ops
and the copy helpers that maintained those caches move with them — an argument is
not a thing you take views of, and nothing outside a runtime called them.
`init_external` and both factories lose their `manual_dep` / `version` parameters,
which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a
friend, and the boundary header no longer includes `task_id.h`: it names no TaskId
at all.

`sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor
cap. `MAILBOX_SIZE` is unaffected — since hw-native-sys#1729 the frame is sized by the 144 B
wire `Tensor`.

`ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level
layout so three copy paths could each be a single 64-byte `memcpy`, held by 21
hand-written `offsetof` assertions across four trees. Two of the three were shaped
backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` /
`__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` /
`::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a
`PTO2TensorMapEntry *` field, its comment noting this was "harmless because
`link_entry()` overwrites `next_in_bucket` immediately after".

Each struct now assigns the fields it wants, by name. The optimization the
`memcpy` existed for survives as intent: a canonically contiguous source has the
derived pair recomputed from `shapes` rather than read across.
`PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in
any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an
entry. The entry keeps its own two-cache-line split and the assertions describing
it; what goes is the claim that its bytes agree with a different struct's.

A source that names one runtime's `Tensor` cannot be compiled under the other, and
57 scene-test sources were: a `host_build_graph` case naming the
`tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer`
classes taking an hbg class's `CALLABLE` verbatim. That worked only because
`ChipTensor` happened to be identical in both trees — the coupling this change
removes.

Each borrowing case now carries its own sources, 73 files, and names local paths.
The two class-reuse cases rebase the inherited `CALLABLE` onto their own
`kernels/` copy through a `_rebase_callable` helper, so the Python that drives
them stays in one file while the C++ each runtime compiles is its own.
`task_timing_slots` carries the runtime in a function default rather than a
`@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the
helper builds the path from the runtime it is driving. The cost is real:
`spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`,
`paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist
once per runtime and the copies can drift. A case that asserts something about
`host_build_graph` should not depend on a file the other runtime owns.

`examples/` orchestration and kernel sources lose their `Generated by PyPTO IR
Compiler` marker: they are this repository's sources, and this change edits them.

364 of those kernels declare a ptoas helper as `template <typename ChipTensor>`,
shadowing the type with a parameter name. The parameter is `TensorT` now: a
generated helper that means "any tensor with .data()" should not name one, and the
shadowing is what made the rename ambiguous in the first place.

`tensor_create_info.h`'s doc paragraph said `host_build_graph` has no
initial-value fill "unlike the tensormap_and_ringbuffer copy of this header",
which hw-native-sys#1981 made false by removing that fill; both copies now describe what is
there.

The copies were taken from sources whose spellings `main` has since retired — hw-native-sys#1980
finished that retirement repo-wide — so they carry the current ones.

`test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify
packing Graph boundaries into the payload's tensor slots, and read that pool as
`ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` —
the assertion was true only while one type served both roles.

Verification: full rebuild of both runtimes on both architectures, cpput 119/119,
pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim
sweeps build only the cases they run, so every orchestration source was also
syntax-checked against its runtime's include path — 129 (source, runtime, arch)
compiles, which is what caught a copy under host_build_graph/ still calling
simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a
Python driver mentions rather than its @scene_test decorator; that is what caught
task_timing_slots.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ChaoWao added a commit to ChaoWao/simpler-fork that referenced this pull request Aug 25, 2026
…nsor

An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things
about it: which task produced it, the version its OverlapMap keys on, whether
dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself,
in `src/common/task_interface/`, so one type served the boundary and both
runtimes' working state. `create_from_chip_args` recorded the mismatch as an
assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are
meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling
`ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while
`ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a
`make()` factory.

The fusion dates to hw-native-sys#1093, which needed the strided view hw-native-sys#808 had just given the
runtime's tensor to reach the argument boundary, and got there by promoting the
runtime-private header into `task_interface/` rather than adding strides to the
40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a
mailbox doubling for a capability that PR noted was not yet used: two months on,
`make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors.
with a cost argument that applies equally here; nobody undid it at L2.

`ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view.

    struct ChipTensor {
        PTOBufferHandle buffer;
        uint64_t start_offset;
        uint32_t shapes[MAX_TENSOR_DIMS];
        uint32_t strides[MAX_TENSOR_DIMS];
        uint32_t ndims;
        DataType dtype;
        AddressSpace address_space;
    };

`simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry
plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the
geometry. One copy each, shared across architectures, placed the way
`src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg`
was an existing namespace.

`Runtime::set_orch_args` is the single place one becomes the other. Both runtimes
call it only from `host/runtime_maker.cpp`, so adoption happens on the host before
any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU
executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of
converting per run. From there inward nothing holds the argument form:
orchestration, the payload, the TensorMap and the kernels all name their runtime's
type.

A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's
include path, so existing `#include "tensor.h"` lines resolve to both types
without an include sweep. That shim names the two headers by their path under
`src/common`, which every platform target but `aicore` already had on its include
path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings
carry.

`is_contiguous` and `extent_elem` become methods that compute from the geometry;
a runtime that reads them per task caches them on its own `Tensor`. The view ops
and the copy helpers that maintained those caches move with them — an argument is
not a thing you take views of, and nothing outside a runtime called them.
`init_external` and both factories lose their `manual_dep` / `version` parameters,
which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a
friend, and the boundary header no longer includes `task_id.h`: it names no TaskId
at all.

`sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor
cap. `MAILBOX_SIZE` is unaffected — since hw-native-sys#1729 the frame is sized by the 144 B
wire `Tensor`.

`ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level
layout so three copy paths could each be a single 64-byte `memcpy`, held by 21
hand-written `offsetof` assertions across four trees. Two of the three were shaped
backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` /
`__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` /
`::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a
`PTO2TensorMapEntry *` field, its comment noting this was "harmless because
`link_entry()` overwrites `next_in_bucket` immediately after".

Each struct now assigns the fields it wants, by name. The optimization the
`memcpy` existed for survives as intent: a canonically contiguous source has the
derived pair recomputed from `shapes` rather than read across.
`PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in
any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an
entry. The entry keeps its own two-cache-line split and the assertions describing
it; what goes is the claim that its bytes agree with a different struct's.

A source that names one runtime's `Tensor` cannot be compiled under the other, and
57 scene-test sources were: a `host_build_graph` case naming the
`tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer`
classes taking an hbg class's `CALLABLE` verbatim. That worked only because
`ChipTensor` happened to be identical in both trees — the coupling this change
removes.

Each borrowing case now carries its own sources, 73 files, and names local paths.
The two class-reuse cases rebase the inherited `CALLABLE` onto their own
`kernels/` copy through a `_rebase_callable` helper, so the Python that drives
them stays in one file while the C++ each runtime compiles is its own.
`task_timing_slots` carries the runtime in a function default rather than a
`@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the
helper builds the path from the runtime it is driving. The cost is real:
`spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`,
`paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist
once per runtime and the copies can drift. A case that asserts something about
`host_build_graph` should not depend on a file the other runtime owns.

`examples/` orchestration and kernel sources lose their `Generated by PyPTO IR
Compiler` marker: they are this repository's sources, and this change edits them.

364 of those kernels declare a ptoas helper as `template <typename ChipTensor>`,
shadowing the type with a parameter name. The parameter is `TensorT` now: a
generated helper that means "any tensor with .data()" should not name one, and the
shadowing is what made the rename ambiguous in the first place.

## Kernels name no runtime

A kernel reads a payload element and its code is identical whichever orchestrator
filled it, so naming a runtime there carries no information — and several kernels
are compiled under both. `examples/a2a3/host_build_graph/deepseek_v4_flash_decode`
re-points all 368 of the `tensormap_and_ringbuffer` case's incores at that case's
directory; `test_task_timing_e2e` drives one AIV kernel under both. Each runtime's
`runtime/tensor.h` therefore exports

    using TaskTensor = simpler::{hbg,tmr}::Tensor;

and every kernel names `TaskTensor`. It resolves per translation unit, so it is one
type per build, not a third type. The alternative was duplicating 13 MB of generated
MoE kernels into the hbg tree, where the two copies would drift.

The name is not `Tensor`: `buffer.h`'s L3+ wire `Tensor` is visible in every
orchestration translation unit, and one spelling meaning two types by context is
what this change exists to remove.

Cross-runtime *orchestration* sources need no name — `const auto &a =
orch_args.tensor(0).ref()` is enough, and only kernels must spell the type inside a
`reinterpret_cast`.

`tensor_create_info.h`'s doc paragraph said `host_build_graph` has no
initial-value fill "unlike the tensormap_and_ringbuffer copy of this header",
which hw-native-sys#1981 made false by removing that fill; both copies now describe what is
there.

The copies were taken from sources whose spellings `main` has since retired — hw-native-sys#1980
finished that retirement repo-wide — so they carry the current ones.

`test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify
packing Graph boundaries into the payload's tensor slots, and read that pool as
`ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` —
the assertion was true only while one type served both roles.

Verification: full rebuild of both runtimes on both architectures, cpput 119/119,
pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim
sweeps build only the cases they run, so every orchestration source was also
syntax-checked against its runtime's include path — 129 (source, runtime, arch)
compiles, which is what caught a copy under host_build_graph/ still calling
simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a
Python driver mentions rather than its @scene_test decorator; that is what caught
task_timing_slots.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
poursoul added a commit to poursoul/simpler that referenced this pull request Aug 25, 2026
host_build_graph is whole-graph-resident: the host builds the entire graph
before the device starts, and no task slot or heap byte is reclaimed during
a run. All three premises of a ring were therefore already false — alloc()
caps ids at the table's size so they never wrap, there is no reclaim channel
back to the allocator, and a full table is a one-shot "graph too large"
verdict that no wait can make satisfiable. hw-native-sys#1980 retired the PTO2 prefix on
these names but left the ring semantics untouched.

A task id is now its own table index. task_window_mask,
get_slot_by_task_id, TaskAllocResult::slot and the power-of-two requirement
are gone; every segment is indexed by the id directly. Producer dedup keys
on the TaskId itself, so append_fanin_or_fail loses the ring and slot
parameters that were derivable from it. The task count stays configurable
through runtime_env.ring_task_window — that is orthogonal to the ring, and
a graph larger than the default still only needs the knob, not a rebuild.
Worker.run's shared RuntimeEnv validation still requires a power of two,
which this layer no longer needs but has no reason to reject.

ChipRingFlowControl::current_task_index is deleted outright. It existed so
a device-side orchestrator could publish its ring head incrementally to a
concurrently running scheduler; with host orchestration the count is a
one-shot scalar. The host reads it from its own allocator, and the device
keeps using host_total_tasks, which on_orchestration_done latches into the
scheduler beside the task-table pointer for update_completed_watermark.
This also removes a boot-time read of that counter whose value was
discarded, and the cross-module contract that had the allocator's local id
depend on the counter's per-boot reset. The shared-memory header shrinks
from 256 to 192 bytes.

Renaming is confined to names carrying ring or window:
SharedMemoryRingHeader -> SharedMemoryTaskHeader, RingSchedState ->
TaskHeaderView, ring_buffer.h -> task_allocator.h, CHIP_TASK_WINDOW_SIZE ->
CHIP_DEFAULT_GRAPH_TASKS, and the sm_layout types lose the prefix their
neighbours never had. The ring_task_window knob keeps its name — it is the
cross-runtime RuntimeEnv ABI.
ChaoWao added a commit that referenced this pull request Aug 25, 2026
…nsor (#1974)

An argument arrives at L2 as a `ChipTensor`, and the runtime then decides things
about it: which task produced it, the version its OverlapMap keys on, whether
dependency tracking is creator-only. Those decisions lived on `ChipTensor` itself,
in `src/common/task_interface/`, so one type served the boundary and both
runtimes' working state. `create_from_chip_args` recorded the mismatch as an
assertion — `debug_assert(!t.manual_dep && t.version == 0)`, two fields that are
meaningless on an argument. `docs/buffer-abi.md` recorded it too, calling
`ChipTensor` "L2 leaf, internal" and saying "You never build a `ChipTensor`" while
`ChipWorker.run` took a container of them and `nb::class_<ChipTensor>` exposed a
`make()` factory.

The fusion dates to #1093, which needed the strided view #808 had just given the
runtime's tensor to reach the argument boundary, and got there by promoting the
runtime-private header into `task_interface/` rather than adding strides to the
40 B `ContinuousTensor` it replaced. It cost 40 B → 128 B per wire tensor and a
mailbox doubling for a capability that PR noted was not yet used: two months on,
`make_tensor_arg` and `make_chip_tensor_arg` still reject non-contiguous tensors.
with a cost argument that applies equally here; nobody undid it at L2.

`ChipTensor` (72 B) is a task argument: a resolved buffer and a strided view.

    struct ChipTensor {
        PTOBufferHandle buffer;
        uint64_t start_offset;
        uint32_t shapes[MAX_TENSOR_DIMS];
        uint32_t strides[MAX_TENSOR_DIMS];
        uint32_t ndims;
        DataType dtype;
        AddressSpace address_space;
    };

`simpler::hbg::Tensor` and `simpler::tmr::Tensor` (128 B) are the same geometry
plus `owner_task_id`, `version`, `manual_dep` and the two caches derived from the
geometry. One copy each, shared across architectures, placed the way
`src/common/host_build_graph/graph_cache.h` already established. `simpler::hbg`
was an existing namespace.

`Runtime::set_orch_args` is the single place one becomes the other. Both runtimes
call it only from `host/runtime_maker.cpp`, so adoption happens on the host before
any orchestration runs — including for `tensormap_and_ringbuffer`, whose AICPU
executor now reads an already-adopted `simpler::tmr::EntryArgsStorage` instead of
converting per run. From there inward nothing holds the argument form:
orchestration, the payload, the TensorMap and the kernels all name their runtime's
type.

A `tensor.h` in each runtime's `runtime/` directory sits first on that runtime's
include path, so existing `#include "tensor.h"` lines resolve to both types
without an include sweep. That shim names the two headers by their path under
`src/common`, which every platform target but `aicore` already had on its include
path; the four `aicore` CMakeLists gain the line their `aicpu` and `host` siblings
carry.

`is_contiguous` and `extent_elem` become methods that compute from the geometry;
a runtime that reads them per task caches them on its own `Tensor`. The view ops
and the copy helpers that maintained those caches move with them — an argument is
not a thing you take views of, and nothing outside a runtime called them.
`init_external` and both factories lose their `manual_dep` / `version` parameters,
which every caller passed as `false` / `0`. `PTO2TaskPayload` is no longer a
friend, and the boundary header no longer includes `task_id.h`: it names no TaskId
at all.

`sizeof(ChipStorageTaskArgs)` falls from ~33.8 KB to 19464 B at the 256-tensor
cap. `MAILBOX_SIZE` is unaffected — since #1729 the frame is sized by the 144 B
wire `Tensor`.

`ChipTensor`, `PTO2TensorMapEntry` and `TensorCreateInfo` shared a byte-level
layout so three copy paths could each be a single 64-byte `memcpy`, held by 21
hand-written `offsetof` assertions across four trees. Two of the three were shaped
backwards to satisfy it: `TensorCreateInfo` carried `__pad0__` / `__pad2__` /
`__pad_flags__` purely to occupy `ChipTensor::buffer` / `::owner_task_id` /
`::address_space`, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a
`PTO2TensorMapEntry *` field, its comment noting this was "harmless because
`link_entry()` overwrites `next_in_bucket` immediately after".

Each struct now assigns the fields it wants, by name. The optimization the
`memcpy` existed for survives as intent: a canonically contiguous source has the
derived pair recomputed from `shapes` rather than read across.
`PTO2TensorMapEntry::copy_tensor_create_info` is deleted — it had no callers in
any tree, and was the only reason `TensorCreateInfo` had to be punnable onto an
entry. The entry keeps its own two-cache-line split and the assertions describing
it; what goes is the claim that its bytes agree with a different struct's.

A source that names one runtime's `Tensor` cannot be compiled under the other, and
57 scene-test sources were: a `host_build_graph` case naming the
`tensormap_and_ringbuffer` case's kernels, and two `tensormap_and_ringbuffer`
classes taking an hbg class's `CALLABLE` verbatim. That worked only because
`ChipTensor` happened to be identical in both trees — the coupling this change
removes.

Each borrowing case now carries its own sources, 73 files, and names local paths.
The two class-reuse cases rebase the inherited `CALLABLE` onto their own
`kernels/` copy through a `_rebase_callable` helper, so the Python that drives
them stays in one file while the C++ each runtime compiles is its own.
`task_timing_slots` carries the runtime in a function default rather than a
`@scene_test` decorator, so its sources move under `kernels/<runtime>/` and the
helper builds the path from the runtime it is driving. The cost is real:
`spmd_multiblock_mix`, `alternating_matmul_add`, `batch_paged_attention`,
`paged_attention_unroll`, `benchmark_bgemm` and the task-timing kernels now exist
once per runtime and the copies can drift. A case that asserts something about
`host_build_graph` should not depend on a file the other runtime owns.

`examples/` orchestration and kernel sources lose their `Generated by PyPTO IR
Compiler` marker: they are this repository's sources, and this change edits them.

364 of those kernels declare a ptoas helper as `template <typename ChipTensor>`,
shadowing the type with a parameter name. The parameter is `TensorT` now: a
generated helper that means "any tensor with .data()" should not name one, and the
shadowing is what made the rename ambiguous in the first place.

## Kernels name no runtime

A kernel reads a payload element and its code is identical whichever orchestrator
filled it, so naming a runtime there carries no information — and several kernels
are compiled under both. `examples/a2a3/host_build_graph/deepseek_v4_flash_decode`
re-points all 368 of the `tensormap_and_ringbuffer` case's incores at that case's
directory; `test_task_timing_e2e` drives one AIV kernel under both. Each runtime's
`runtime/tensor.h` therefore exports

    using TaskTensor = simpler::{hbg,tmr}::Tensor;

and every kernel names `TaskTensor`. It resolves per translation unit, so it is one
type per build, not a third type. The alternative was duplicating 13 MB of generated
MoE kernels into the hbg tree, where the two copies would drift.

The name is not `Tensor`: `buffer.h`'s L3+ wire `Tensor` is visible in every
orchestration translation unit, and one spelling meaning two types by context is
what this change exists to remove.

Cross-runtime *orchestration* sources need no name — `const auto &a =
orch_args.tensor(0).ref()` is enough, and only kernels must spell the type inside a
`reinterpret_cast`.

`tensor_create_info.h`'s doc paragraph said `host_build_graph` has no
initial-value fill "unlike the tensormap_and_ringbuffer copy of this header",
which #1981 made false by removing that fill; both copies now describe what is
there.

The copies were taken from sources whose spellings `main` has since retired — #1980
finished that retirement repo-wide — so they carry the current ones.

`test_hbg_sm_compaction` compared `GraphTensor` against `ChipTensor` to justify
packing Graph boundaries into the payload's tensor slots, and read that pool as
`ChipTensor`. The pool is the payload's, so both now name the runtime's `Tensor` —
the assertion was true only while one type served both roles.

Verification: full rebuild of both runtimes on both architectures, cpput 119/119,
pyut 1908 passed / 14 skipped, a2a3sim 21 cases and a5sim 17 cases green. The sim
sweeps build only the cases they run, so every orchestration source was also
syntax-checked against its runtime's include path — 129 (source, runtime, arch)
compiles, which is what caught a copy under host_build_graph/ still calling
simpler::tmr::make_tensor_external. A second check reads which runtime *strings* a
Python driver mentions rather than its @scene_test decorator; that is what caught
task_timing_slots.
poursoul added a commit to poursoul/simpler that referenced this pull request Aug 25, 2026
host_build_graph is whole-graph-resident: the host builds the entire graph
before the device starts, and no task slot or heap byte is reclaimed during
a run. All three premises of a ring were therefore already false — alloc()
caps ids at the table's size so they never wrap, there is no reclaim channel
back to the allocator, and a full table is a one-shot "graph too large"
verdict that no wait can make satisfiable. hw-native-sys#1980 retired the PTO2 prefix on
these names but left the ring semantics untouched.

A task id is now its own table index. task_window_mask,
get_slot_by_task_id, TaskAllocResult::slot and the power-of-two requirement
are gone; every segment is indexed by the id directly. Producer dedup keys
on the TaskId itself, so append_fanin_or_fail loses the ring and slot
parameters that were derivable from it. TaskAllocator::task_head is gone
too: with nothing retiring, the next id is both the occupancy and the run's
total, so active_count answers both questions.

The task count stays configurable through runtime_env.ring_task_window —
that is orthogonal to the ring, and a graph larger than the default still
only needs the knob, not a rebuild. Any positive count is accepted, since
nothing masks with it. The power-of-two, >= 4 requirement belongs to
tensormap_and_ringbuffer, which does mask, and is enforced in that runtime's
own resolve; neither the RuntimeEnv setter nor Worker.run constrains the
value, so host_build_graph's own bound is the only one it passes through.

ChipRingFlowControl::current_task_index is deleted outright. It existed so
a device-side orchestrator could publish its ring head incrementally to a
concurrently running scheduler; with host orchestration the count is a
one-shot scalar, so it becomes a plain int32 in SharedMemoryTaskHeader that
the host writes once after orchestration and the restack ships with the rest
of the header. It packs into existing padding, so the shared-memory header
still shrinks from 256 to 192 bytes, and update_completed_watermark reads
the bound from the table it is walking rather than taking it as an argument.
This also removes a boot-time read of that counter whose value was
discarded, and the cross-module contract that had the allocator's local id
depend on the counter's per-boot reset.

TaskHeaderView::advance_lock goes with the ring it guarded: nothing on the
device advances a reclaim cursor, so the field had no reader. The same for
the `uint8_t ring_id = 0` locals in prepare_task and in the tensor-wait
diagnostics — every TaskId::make in this runtime emits ring 0, so they only
made a constant look configurable, and the wait timeouts no longer print a
ring that is always the same.

Renaming is confined to names carrying ring or window:
SharedMemoryRingHeader -> SharedMemoryTaskHeader, RingSchedState ->
TaskHeaderView, ring_buffer.h -> task_allocator.h, CHIP_TASK_WINDOW_SIZE ->
CHIP_DEFAULT_GRAPH_TASKS, and the sm_layout types lose the prefix their
neighbours never had. The ring_task_window knob keeps its name — it is the
cross-runtime RuntimeEnv ABI.
ChaoWao pushed a commit that referenced this pull request Aug 25, 2026
host_build_graph is whole-graph-resident: the host builds the entire graph
before the device starts, and no task slot or heap byte is reclaimed during
a run. All three premises of a ring were therefore already false — alloc()
caps ids at the table's size so they never wrap, there is no reclaim channel
back to the allocator, and a full table is a one-shot "graph too large"
verdict that no wait can make satisfiable. #1980 retired the PTO2 prefix on
these names but left the ring semantics untouched.

A task id is now its own table index. task_window_mask,
get_slot_by_task_id, TaskAllocResult::slot and the power-of-two requirement
are gone; every segment is indexed by the id directly. Producer dedup keys
on the TaskId itself, so append_fanin_or_fail loses the ring and slot
parameters that were derivable from it. TaskAllocator::task_head is gone
too: with nothing retiring, the next id is both the occupancy and the run's
total, so active_count answers both questions.

The task count stays configurable through runtime_env.ring_task_window —
that is orthogonal to the ring, and a graph larger than the default still
only needs the knob, not a rebuild. Any positive count is accepted, since
nothing masks with it. The power-of-two, >= 4 requirement belongs to
tensormap_and_ringbuffer, which does mask, and is enforced in that runtime's
own resolve; neither the RuntimeEnv setter nor Worker.run constrains the
value, so host_build_graph's own bound is the only one it passes through.

ChipRingFlowControl::current_task_index is deleted outright. It existed so
a device-side orchestrator could publish its ring head incrementally to a
concurrently running scheduler; with host orchestration the count is a
one-shot scalar, so it becomes a plain int32 in SharedMemoryTaskHeader that
the host writes once after orchestration and the restack ships with the rest
of the header. It packs into existing padding, so the shared-memory header
still shrinks from 256 to 192 bytes, and update_completed_watermark reads
the bound from the table it is walking rather than taking it as an argument.
This also removes a boot-time read of that counter whose value was
discarded, and the cross-module contract that had the allocator's local id
depend on the counter's per-boot reset.

TaskHeaderView::advance_lock goes with the ring it guarded: nothing on the
device advances a reclaim cursor, so the field had no reader. The same for
the `uint8_t ring_id = 0` locals in prepare_task and in the tensor-wait
diagnostics — every TaskId::make in this runtime emits ring 0, so they only
made a constant look configurable, and the wait timeouts no longer print a
ring that is always the same.

Renaming is confined to names carrying ring or window:
SharedMemoryRingHeader -> SharedMemoryTaskHeader, RingSchedState ->
TaskHeaderView, ring_buffer.h -> task_allocator.h, CHIP_TASK_WINDOW_SIZE ->
CHIP_DEFAULT_GRAPH_TASKS, and the sm_layout types lose the prefix their
neighbours never had. The ring_task_window knob keeps its name — it is the
cross-runtime RuntimeEnv ABI.
ChaoWao added a commit that referenced this pull request Aug 26, 2026
`.claude/rules/codestyle.md` rule 10 said the retirement was complete and that
"there is no backlog to work through". Two of its three claims held: no `PTO2`
*identifier* is left, and a new one is a defect. The third was false — the rule's
own grep, `PTO Runtime2?|PTO2|pto2_|pto_runtime2`, found 38 brand banners across
36 files in `src/`.

The claim had been measured with `PTO2|pto2_`, which cannot see a brand name with
a space in it. #1980's title was "finish the PTO2 retirement" and it finished
exactly that, verifiably — 62 remaining under its own pattern, reproducible today.
The sentence generalised from "PTO2 identifiers" to "the retirement".

## What changed

**The 38 banners**, following the style already in the tree —
`orchestrator_core/orchestrator.cpp` opens `* host_build_graph orchestrator
implementation`, so the runtime's directory name leads and the subsystem words are
lower case, with type names keeping their case:

    * PTO Runtime2 - TensorMap Interface   ->  * host_build_graph TensorMap interface
    * PTO Runtime2 - Ring Buffer Data …    ->  * tensormap_and_ringbuffer ring buffer data …

The four `PTO Runtime C API` banners are in the platform layer, which serves both
runtimes, so they take the name the canonical header already uses for itself:
`simpler host-runtime C API`.

**Eighteen comments naming a `pto_*` that does not exist.** These are
`doc-consistency.md` §3 defects rather than naming preferences — a reader who
greps the name finds nothing:

  - `pto_submit_task` x16 -> `rt_submit_task`, the actual orchestration entry in
    `orchestration/orchestration_api.h`.
  - `pto_runtime_c_api` x2 -> `runtime_c_api`, the actual file name.

`git grep -w` returning only comments is what established each was absent.

**`tests/lint/check_retired_names.py`**, wired into pre-commit. Rule 10 already
demanded that "the count only goes down"; nothing enforced it, and a count written
into prose cannot stay true. The hook fails on any new `PTO Runtime`,
`PTO Runtime2`, or bare `Runtime2`, so the rule can now point at it and drop the
number it could not keep current.

The hook is deliberately narrow, and the reason is the third population rule 10
lumped into one Tier A row.

## What is deliberately untouched

**Every live `pto_cpu_sim_*` / `pto_sim_*` hook** — 33 occurrences, all left
alone. `cpu_sim_context.cpp` exports them for "pto-isa via
`dlsym(RTLD_DEFAULT)`", and `device_runner_base.cpp` fetches
`pto_sim_register_hooks` by `dlsym`. Renaming one produces **no compile error** —
just a hook that is never found at run time. That is the "handful of Tier-C names
hiding in it" rule 10's no-sweep ban was written to protect, and it is real; it
just hides in the lowercase `pto_*` namespace, not in the banner namespace. So the
hook checks only the brand spellings, and rule 10's Tier A is split into A1
(brand prose, mechanically safe) and A2 (dangling `pto_*` references, grep first),
with the `dlsym` trap named in Tier C.

**Six mentions that named a retired variable only for history** — "the
now-retired `PTO2_RING_*` environment variables", "the process-wide `PTO2_RING_*`
env, since retired" — now state the current mechanism and what it enables
instead. They explained a design by contrast with something the reader cannot
find. (`per_task_runtime_env/README.md` also had "shared the process-wide
process-wide", a duplicated line from #1980's edit.)

`PTO2_*` is deliberately left out of the hook, because what remains of that
spelling is load-bearing in two ways the hook cannot distinguish:

  - Twelve occurrences belong to `warn_on_retired_ring_env()` in each
    `host/runtime_maker.cpp` — a `kRetired[]` array of env names and the comment
    explaining it — plus three doc sites that tell a reader what the warning they
    just saw means. The names cannot leave without the warning leaving, and that
    warning is one day old (#1980, 2026-08-25); rule 10 holds it up as the model
    for retiring a knob rather than silently falling back.
  - Eight are `PTO2_MANUAL_MAX_SEQ`, pypto-lib's own variable, which the qwen
    READMEs tell a user to `export` literally.

So banning the spelling would either delete a live diagnostic or break working
instructions.

## Verification

Comments and one new lint script; no declaration, signature or expression changes.

  - Full product build — both arches, sim and onboard, all four runtimes.
  - cpput 119/119.
  - The hook returns 0 over all 2294 tracked files, 1 on a probe containing
    `PTO Runtime2 - Something`, 1 on a bare `Runtime2`, and 0 on
    `codestyle.md` itself, which is exempt because a rule has to spell what it bans.
  - `clang-format --dry-run --Werror` clean on all 42 changed C++ files; every one
    of them is a matched a2a3/a5 pair.
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