From fdc4d690db1293e0d7df20f6bc82886f4e524fa9 Mon Sep 17 00:00:00 2001 From: Chao Wang <26245345+ChaoWao@users.noreply.github.com> Date: Tue, 25 Aug 2026 18:04:10 -0700 Subject: [PATCH] Remove documentation that describes things that no longer exist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three kinds of stale documentation, all of it naming something the tree does not contain. `doc-consistency.md` §3: when a referent is gone, the reference goes too. **`problems.md`, deleted.** A personal working audit of `host_build_graph` — findings, their status, and notes on what to look at next. It was never meant to be here. It arrived in #1974 through a `git add -A` that swept it up with that change's 958 files, and #2012 then updated it rather than noticing it. Nothing references it (`git grep problems.md` is empty), it is absent from `mkdocs.yml`, and `wheel.packages` is `["simpler_setup", "python/simpler"]` so it never shipped. Its closed items name the PRs that closed them, each of which carries the reasoning in its own commit message. **`last_task_alive`, in hbg's `RUNTIME_LOGIC.md`.** The paragraph gives four reasons `SchedulerState` holds no per-run content, and the third was "hbg never advances `last_task_alive`". That was accurate when written — hbg inherited the field from `tensormap_and_ringbuffer` and did not advance it — but #1837 deleted the field with the rest of the reclamation paths, for exactly the reason the sentence gives, and #2004 then removed the ring that held it. The clause now names the one thing in that list that does not exist. It is replaced by the live fact from the same runtime: polling reserves no wiring or dependency pool, because readiness comes from the task table's `completion_flags`. **`ring 0`, in hbg's `SCALAR_DATA_ACCESS.md`.** Ownership validation was described as checking that "the task ID ... carries ring 0, the only ring HBG places tasks on". hbg has had no ring since #2004 (`git grep 'rings\['` over its tree is empty), and since #2012 the check is on the id *space*, not a ring index. The bullet now says what the code does and why a `GRAPH_NODE` id fails it. **`pto_runtime2_init`, in three `scheduler.h` files.** A comment credited it with reserving and wiring the early-dispatch queues. `git grep pto_runtime2_init` returned only those three comments — the symbol exists nowhere. The work is done by `SchedulerState::init_data_from_layout`, which the comment now names. Only three of the four runtime trees carried the line; `src/a5/runtime/tensormap_and_ringbuffer` words that member differently. **`run_from_blob`, in `docs/buffer-abi.md`.** A present-tense table row told the chip leaf to "hand the POD blob to `run_from_blob`", a name that has never existed (introduced with the row in #1599). The row now names the three functions that do the work — `read_args_from_blob`, `ImportRegistry.materialize_args`, `_submit_chip_run_materialized` — matching `worker.py`'s `submit_frame`. Deliberately untouched: `tensormap_and_ringbuffer`'s ring documentation. `current_task_index`, `task_window_mask`, `advance_lock` and `last_task_alive` are all live there (162 uses across 20 non-doc files); #2004 dropped the ring from `host_build_graph` only, and said so. Co-Authored-By: Claude Opus 5 (1M context) --- docs/buffer-abi.md | 2 +- problems.md | 123 ------------------ .../host_build_graph/docs/RUNTIME_LOGIC.md | 5 +- .../docs/SCALAR_DATA_ACCESS.md | 4 +- .../runtime/scheduler/scheduler.h | 10 +- .../runtime/scheduler/scheduler.h | 10 +- .../host_build_graph/docs/RUNTIME_LOGIC.md | 5 +- .../docs/SCALAR_DATA_ACCESS.md | 4 +- .../runtime/scheduler/scheduler.h | 10 +- 9 files changed, 28 insertions(+), 145 deletions(-) delete mode 100644 problems.md diff --git a/docs/buffer-abi.md b/docs/buffer-abi.md index 52c6b43752..9eb7268092 100644 --- a/docs/buffer-abi.md +++ b/docs/buffer-abi.md @@ -250,7 +250,7 @@ A `Tensor` on the wire is materialized differently by each consumer: | Consumer | What it does | | -------- | ------------ | -| **Chip leaf (L2 runtime)** | Materialize each one to a `ChipTensor` (map-once, keyed by identity), including **strided** views; hand the POD blob to `run_from_blob`. | +| **Chip leaf (L2 runtime)** | Decode the POD blob with `read_args_from_blob`, then materialize each one to a `ChipTensor` (map-once, keyed by canonical identity) via `ImportRegistry.materialize_args`, including **strided** views, and submit with `_submit_chip_run_materialized`. | | **Python sub-worker** (compute) | Map each one into a `MappedArg`; the callable computes with `torch.frombuffer(arg.buffer, ...)`. No `ChipTensor`. | | **Nested L4→L3 orch** (forwarding) | **Re-export** each backing to a descriptor `H'` that keeps the source's canonical identity — no pass-through, no map on the forwarding hop. | diff --git a/problems.md b/problems.md deleted file mode 100644 index 451b26357a..0000000000 --- a/problems.md +++ /dev/null @@ -1,123 +0,0 @@ -# Problems - -Audit of `host_build_graph` for data structures inherited from -`tensormap_and_ringbuffer` whose actual hbg usage diverges from the tmr design -they were shaped for. - -Original audit was against `upstream/main@761fdf8d`. **Updated 2026-08-25 against -`upstream/main@fc42cd1dd`**, after the L2-tensor split (#1974) and the ring removal -(#2004). #1980 retired the `PTO2` *identifiers* this audit named, so the spellings -below are the current ones; the brand prose survives in ~100 places, see -`KNOWN_ISSUES.md`. - ---- - -## CLOSED - -### 1. Single-ring shape carried as a multi-ring one — FIXED (#1965, #2004) - -`PTO2_MAX_RING_DEPTH` was `1` against tmr's `4`, yet the tree carried 38 -array declarations dimensioned by it and 21 loops that ran exactly once. #1965 -collapsed each operation to one scalar form; #2004 went further and dropped the -ring itself — a task id is now its own table index, and `task_window_mask` / -`get_slot_by_task_id` / `TaskAllocResult::slot` are gone. - -### 2. `PTO2RingSet` was a one-member wrapper named "Set" — FIXED (#1965) - -### 3. `DEP_POOL_OVERFLOW` reported for fanin exhaustion — FIXED UPSTREAM (#1963) - -Renamed to `SIMPLER_ERROR_FANIN_CAPACITY_EXCEEDED`, value 4 held. - -### 4. `PTO2_DEP_POOL_SPIN_LIMIT` was a dead define — FIXED (#1965) - -### 7. One byte layout shared by three unrelated structs — FIXED (#1974) - -`ChipTensor`, `TensorMapEntry` 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, and the entry's `memcpy` wrote `ChipTensor::buffer.size` into a -`TensorMapEntry *`. Each struct now assigns its own fields; -`TensorMapEntry::copy_tensor_create_info` is deleted (it had no callers). - -### 8. One tensor type served the boundary and both runtimes — FIXED (#1974) - -`ChipTensor` carried `owner_task_id` / `version` / `manual_dep` and two derived -caches — what the *runtime* decides about an argument, on the type a *caller* hands -in. `create_from_chip_args` recorded the mismatch as -`debug_assert(!t.manual_dep && t.version == 0)`, and `docs/buffer-abi.md` called the -type "internal" while `ChipWorker.run` took a container of them. - -Now: `ChipTensor` is 72 B of geometry plus a resolved address; -`simpler::{hbg,tmr}::Tensor` is 128 B and adds the runtime's own state; -`Runtime::set_orch_args` is the single adoption point and runs on the host in both -runtimes. `sizeof(ChipStorageTaskArgs)` fell from ~33.8 KB to 19464 B. - -### 4b. A nonzero producer ring id becomes a ring-0 dependency — FIXED - -`task_id.h` declared the encoding as `(ring_id << 32) | local_id` and named the -accessor `ring()`. **That was false for hbg**, which uses the high bits as an -id-space tag: `graph_execution.cpp` minted `TaskId::make(1, synthetic_local)` for a -Graph node. So every hbg guard reading `ring() != 0` looked like a bounds check on -a dimension that no longer exists, when it was really asking "is this a graph-node -id" — and `FaninBuilder::mark_seen` folded that question's answer into its dedup -return value, so `append_fanin_or_fail` read "not a ring task" as "not deduped -yet" and appended an edge to whatever `prod_slot` the foreign local id happened to -mask onto. - -The bug survived #2004 unchanged: it moved `mark_seen` to key on the `TaskId` and -dropped the redundant ring/slot parameters, but left the space check folded into -the dedup return value. - -`TaskId` is now an opaque 64-bit handle (`raw`, `invalid()`, `is_valid()`, `==`, -`sizeof == 8`); each runtime owns and names its own layout in -`src/common/{host_build_graph,tensormap_and_ringbuffer}/task_id_encoding.h` — -`TaskIdSpace{RING, GRAPH_NODE}` + `make_ring_task` / `make_graph_node` / -`is_ring_task` for hbg, a real `make_task_id(ring, local)` / `task_ring` for tmr. -`mark_seen` deduplicates and nothing else; `append_fanin_or_fail` rejects a -non-RING producer up front via `report_fatal(SIMPLER_ERROR_INVALID_ARGS, …)`. - -Repro: `graph_node_dependency` in -`tests/st/host_build_graph_validation/`, verified to fail (`DID NOT RAISE` — -the bogus edge was built silently) with the new guard removed. - ---- - -## STILL OPEN - -### 5. `on_scope_end` is an empty stub — low value - -`runtime/scheduler/scheduler.h`: -`void on_scope_end(TaskSlotState ** /*task_slot_states*/, int32_t /*count*/) {}`, -still called from `end_scope`, kept as a no-op so the orchestrator call site -matches tmr's. Inline empty function, so readability only — fold into the next -change that touches either file. - -### 6. Docs name a field hbg does not have - -`docs/RUNTIME_LOGIC.md` states hbg "never advances `last_task_alive`". That -identifier does not exist anywhere in the hbg tree except that sentence. - ---- - -## Deliberate, do not "fix" - -- `AsyncWaitList` — live in hbg (`scheduler_dispatch.cpp` reads `.count`). -- `SchedulerState` and its thirteen queue slot arrays — the scheduler runs on the - AICPU, so the arena/offset form is required. -- `TensorMapEntry`'s two-cache-line mirror of the runtime `Tensor`'s hot fields — a - shared performance design. Since #1974 it mirrors `simpler::{hbg,tmr}::Tensor`, - not the boundary type. -- `ring_dep_pool` in the bind ABI — `[[maybe_unused]]` with "kept for ABI - stability"; a deliberate cross-repo contract decision. -- `TaskTensor` — not a third type. A per-translation-unit alias for the runtime - being built, so kernels (identical either way, and several compiled under both) - name no runtime. The alternative was duplicating 13 MB of generated MoE kernels - into the hbg tree, where the copies would drift. - -## Open sizing question (not a vestige) - -`TENSORMAP_POOL_SIZE` is `65536` in both runtimes, but tmr spends it per-ring -across 4 rings while hbg uses one ring's worth. Since #1962 that is an explicit -~8 MB allocation per bind. With `GRAPH_MAX_NODES = 1024` and a default task window -of 16384 it is not a hard bound on either side (a capacity check backs it), so -whether hbg wants its own number is a measurable question, not a guess. diff --git a/src/a2a3/runtime/host_build_graph/docs/RUNTIME_LOGIC.md b/src/a2a3/runtime/host_build_graph/docs/RUNTIME_LOGIC.md index 5864fcad44..bbd4528811 100644 --- a/src/a2a3/runtime/host_build_graph/docs/RUNTIME_LOGIC.md +++ b/src/a2a3/runtime/host_build_graph/docs/RUNTIME_LOGIC.md @@ -124,8 +124,9 @@ scalar `rt_orchestration_done` publishes into the runtime header. **Why the scheduler state is device-written.** `SchedulerState` holds no per-run content: `sm_header` and the task-header pointer derive from a pooled SM base, -queue capacities are compile-time constants, hbg never advances -`last_task_alive`, and it has no host-side entry point at all. So the host would +queue capacities are compile-time constants, polling reserves no wiring or +dependency pool (readiness comes from the task table's `completion_flags`, which +the task header owns), and it has no host-side entry point at all. So the host would only be writing an initialization pattern — 203,392 bytes of it, dominated by `AsyncWaitList::entries` — for the device to receive and never read. `RuntimeContext` therefore holds a *pointer* to it, wired from diff --git a/src/a2a3/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md b/src/a2a3/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md index 39daa3d8d4..1f8b8f3b5e 100644 --- a/src/a2a3/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md +++ b/src/a2a3/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md @@ -70,7 +70,9 @@ it derives for itself, from a heap block whose prior contents it never reads. Before a wait slot is used, the runtime verifies: -- the task ID is valid and carries ring 0, the only ring HBG places tasks on; +- the task ID is valid and lies in the `RING` id space — a `GRAPH_NODE` id packs + its outer task and node index into the low bits, so it indexes no task table + slot (see `src/common/host_build_graph/task_id_encoding.h`); - the task table slot that ID indexes has a bound task descriptor; and - the descriptor's full task ID matches the tensor's owner/producer ID. diff --git a/src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler.h b/src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler.h index d52d331a89..8b8bafec66 100644 --- a/src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler.h +++ b/src/a2a3/runtime/host_build_graph/runtime/scheduler/scheduler.h @@ -689,11 +689,11 @@ struct SchedulerState { EarlyDispatchDoorbell early_dispatch_doorbell_table[EARLY_DISPATCH_CORE_MASK_WORDS * 64]{}; // Cross-thread early-dispatch work queues, one ChipReadyQueue MPMC instance per - // resource shape (AIC/AIV/MIX) — arena-backed, reserved/wired in pto_runtime2_init - // alongside the per-shape ready queues, and indexed the same way. A candidate is - // pushed to the queue for its own shape (active_mask.to_shape()) so the drain can - // pop per shape and size the pop to that shape's free cores, exactly as normal - // dispatch pops ready_queues[shape]. + // resource shape (AIC/AIV/MIX) — arena-backed, reserved and wired by + // SchedulerState::init_data_from_layout alongside the per-shape ready queues, and + // indexed the same way. A candidate is pushed to the queue for its own shape + // (active_mask.to_shape()) so the drain can pop per shape and size the pop to that + // shape's free cores, exactly as normal dispatch pops ready_queues[shape]. // // A consumer's SPMD blocks span cores owned by several AICPU threads, but only a // thread RUNNING the consumer's producer discovers it (via the producer's diff --git a/src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.h b/src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.h index 42fae719fa..3c5096066c 100644 --- a/src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.h +++ b/src/a2a3/runtime/tensormap_and_ringbuffer/runtime/scheduler/scheduler.h @@ -735,11 +735,11 @@ struct SchedulerState { EarlyDispatchDoorbell early_dispatch_doorbell_table[EARLY_DISPATCH_CORE_MASK_WORDS * 64]{}; // Cross-thread early-dispatch work queues, one ChipReadyQueue MPMC instance per - // resource shape (AIC/AIV/MIX) — arena-backed, reserved/wired in pto_runtime2_init - // alongside the per-shape ready queues, and indexed the same way. A candidate is - // pushed to the queue for its own shape (active_mask.to_shape()) so the drain can - // pop per shape and size the pop to that shape's free cores, exactly as normal - // dispatch pops ready_queues[shape]. + // resource shape (AIC/AIV/MIX) — arena-backed, reserved and wired by + // SchedulerState::init_data_from_layout alongside the per-shape ready queues, and + // indexed the same way. A candidate is pushed to the queue for its own shape + // (active_mask.to_shape()) so the drain can pop per shape and size the pop to that + // shape's free cores, exactly as normal dispatch pops ready_queues[shape]. // // A consumer's SPMD blocks span cores owned by several AICPU threads, but only a // thread RUNNING the consumer's producer discovers it (via the producer's diff --git a/src/a5/runtime/host_build_graph/docs/RUNTIME_LOGIC.md b/src/a5/runtime/host_build_graph/docs/RUNTIME_LOGIC.md index 5864fcad44..bbd4528811 100644 --- a/src/a5/runtime/host_build_graph/docs/RUNTIME_LOGIC.md +++ b/src/a5/runtime/host_build_graph/docs/RUNTIME_LOGIC.md @@ -124,8 +124,9 @@ scalar `rt_orchestration_done` publishes into the runtime header. **Why the scheduler state is device-written.** `SchedulerState` holds no per-run content: `sm_header` and the task-header pointer derive from a pooled SM base, -queue capacities are compile-time constants, hbg never advances -`last_task_alive`, and it has no host-side entry point at all. So the host would +queue capacities are compile-time constants, polling reserves no wiring or +dependency pool (readiness comes from the task table's `completion_flags`, which +the task header owns), and it has no host-side entry point at all. So the host would only be writing an initialization pattern — 203,392 bytes of it, dominated by `AsyncWaitList::entries` — for the device to receive and never read. `RuntimeContext` therefore holds a *pointer* to it, wired from diff --git a/src/a5/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md b/src/a5/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md index 39daa3d8d4..1f8b8f3b5e 100644 --- a/src/a5/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md +++ b/src/a5/runtime/host_build_graph/docs/SCALAR_DATA_ACCESS.md @@ -70,7 +70,9 @@ it derives for itself, from a heap block whose prior contents it never reads. Before a wait slot is used, the runtime verifies: -- the task ID is valid and carries ring 0, the only ring HBG places tasks on; +- the task ID is valid and lies in the `RING` id space — a `GRAPH_NODE` id packs + its outer task and node index into the low bits, so it indexes no task table + slot (see `src/common/host_build_graph/task_id_encoding.h`); - the task table slot that ID indexes has a bound task descriptor; and - the descriptor's full task ID matches the tensor's owner/producer ID. diff --git a/src/a5/runtime/host_build_graph/runtime/scheduler/scheduler.h b/src/a5/runtime/host_build_graph/runtime/scheduler/scheduler.h index d52d331a89..8b8bafec66 100644 --- a/src/a5/runtime/host_build_graph/runtime/scheduler/scheduler.h +++ b/src/a5/runtime/host_build_graph/runtime/scheduler/scheduler.h @@ -689,11 +689,11 @@ struct SchedulerState { EarlyDispatchDoorbell early_dispatch_doorbell_table[EARLY_DISPATCH_CORE_MASK_WORDS * 64]{}; // Cross-thread early-dispatch work queues, one ChipReadyQueue MPMC instance per - // resource shape (AIC/AIV/MIX) — arena-backed, reserved/wired in pto_runtime2_init - // alongside the per-shape ready queues, and indexed the same way. A candidate is - // pushed to the queue for its own shape (active_mask.to_shape()) so the drain can - // pop per shape and size the pop to that shape's free cores, exactly as normal - // dispatch pops ready_queues[shape]. + // resource shape (AIC/AIV/MIX) — arena-backed, reserved and wired by + // SchedulerState::init_data_from_layout alongside the per-shape ready queues, and + // indexed the same way. A candidate is pushed to the queue for its own shape + // (active_mask.to_shape()) so the drain can pop per shape and size the pop to that + // shape's free cores, exactly as normal dispatch pops ready_queues[shape]. // // A consumer's SPMD blocks span cores owned by several AICPU threads, but only a // thread RUNNING the consumer's producer discovers it (via the producer's