diff --git a/README.md b/README.md index 9c0b22add3..5040b3eb28 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,11 @@ export ASCEND_HOME_PATH=/usr/local/Ascend/ascend-toolkit/latest ## Documentation +**[docs/README.md](docs/README.md) indexes every document**, grouped by task. The entry points: + | Document | Description | | -------- | ----------- | +| [Capability Survey](docs/capability-survey.md) | Status snapshot: what is shipped, gated, or design-only across topology (L2→L4), CANN launch, and comm engines | | [Chip-Level Architecture](docs/chip-level-arch.md) | L2 single-chip: three-program model (host/AICPU/AICore), API layers, handshake protocol | | [Hierarchical Level Runtime](docs/hierarchical_level_runtime.md) | L0–L6 level model, component composition (Orchestrator / Scheduler / Worker) | | [Task Flow](docs/task-flow.md) | End-to-end data flow: Callable / TaskArgs / CallConfig handles, IWorker interface | diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000000..69f98992f6 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,86 @@ +# simpler Documentation + +Index of every document under `docs/`, grouped by what you are trying to do. +The top-level [README](../README.md) links only the handful of entry-point docs; +this page is the complete map. + +New docs belong in one of the groups below, and in a subdirectory when the group +already has one (`dfx/`, `hardware/`, `troubleshooting/`, `investigations/`). +Add the row here in the same commit — an unlisted doc is invisible. + +## Start here + +| Document | What it covers | +| -------- | -------------- | +| [Getting Started](getting-started.md) | Prerequisites, PTO-ISA setup, first example run | +| [Installation and Runtime Environment](install.md) | Install layout and the runtime environment variables | +| [Developer Guide](developer-guide.md) | Directory structure, role ownership, when to rebuild | +| [Capability Survey](capability-survey.md) | **Status snapshot** — what is shipped, gated, or design-only across topology, launch, and communication. Read this before assuming a mechanism works | + +## Architecture + +| Document | What it covers | +| -------- | -------------- | +| [Chip-Level Architecture (L2)](chip-level-arch.md) | Three-program model (host / AICPU / AICore), API layers, handshake | +| [Hierarchical Level Runtime](hierarchical_level_runtime.md) | The L0–L6 level model and component composition | +| [Task Flow](task-flow.md) | Callable / TaskArgs / CallConfig pass-through, `IWorker` | +| [Orchestrator](orchestrator.md) | DAG submission: TensorMap, Scope, Ring, task state machine | +| [Scheduler](scheduler.md) | DAG dispatch: wiring / ready / completion queues, dispatch loop | +| [Worker Manager](worker-manager.md) | Worker pool, THREAD/PROCESS modes, fork + mailbox mechanics | +| [hardware/](hardware/) | Hardware substrate: chip architecture, cache coherency, MMIO performance, CANN source references | + +## Kernels and task authoring + +| Document | What it covers | +| -------- | -------------- | +| [AICore Kernel Programming](aicore-kernel-programming.md) | Writing AICore kernels for this runtime | +| [a5 AICore SIMT Launch](simt-launch.md) | a5 SIMT launch metadata and the `ChipCallable` alignment constraint | +| [Manual Scope V0](manual-scope.md) | Explicit scope control from orchestration code | +| [WAR Anti-Dependencies](war-anti-dependency.md) | Write-after-read hazards and how the runtime orders them | +| [TPUSH/TPOP Guidelines](tpush-tpop.md) | Advisory usage rules for the push/pop instructions | + +## Launch, linking, and callable registration + +| Document | What it covers | +| -------- | -------------- | +| [AICPU Kernel Launch Mechanisms](aicpu-kernel-launch-mechanisms.md) | How the AICPU SO is bootstrapped, registered, and launched via CANN | +| [Dynamic Linking and TLS](dynamic-linking.md) | Binary registration, relocation, thread-local storage on device | +| [Callable Identity Registration](callable-identity-registration.md) | How a callable is identified and registered across tiers | +| [Dynamic Callable Registration over IPC](callable-ipc-dynamic-register.md) | Registering callables into a running child process | +| [Python Callable Serialization](python-callable-serialization.md) | Serializing Python callables for L3+ registration | + +## Multi-chip, multi-host, and communication + +| Document | What it covers | +| -------- | -------------- | +| [Communication Domains](comm-domain.md) | Dynamic `CommDomain` allocation and the symmetric window | +| [a5 SDMA Workspace Overlay](a5-sdma-overlay.md) | a5 SDMA overlay isolation status and the CANN-version gates | +| [L3-L2 Orchestrator Communication](l3-l2-orch-comm.md) | Host-side L3 talking directly to the L2 AICPU orchestrator | +| [L3-L2 Message Queue](l3-l2-message-queue.md) | The queue channel between an L3 host and L2 | +| [Directed NEXT_LEVEL Scheduling](directed-next-level-scheduling.md) | Targeting a specific next-level child instead of any free one | +| [Remote L3 Worker Design](remote-l3-worker-design.md) | L4 host-to-host workers — protocol, transports, status | +| [remote-l3-worker-design/](remote-l3-worker-design/) | Full design set: protocol, buffers and transports, implementation plan and record | + +## Profiling, logging, and DFX + +| Document | What it covers | +| -------- | -------------- | +| **[dfx/](dfx/README.md)** | **Every profiling and diagnostics reference**, indexed: framework and naming rules, L2/L0 swimlanes, PMU, host trace, device phases, scheduler-overhead model, args dump, dep_gen, scope stats, backpressure, buffer-capacity audit | +| [Log System](logging.md) | Log levels, sinks, and the host/device logging split | + +## Building, testing, and packaging + +| Document | What it covers | +| -------- | -------------- | +| [Testing](testing.md) | Test types (st / pyut / cpput), how to run them, writing new tests | +| [CI Pipeline](ci.md) | Jobs, gating, and what each pipeline stage covers | +| [Python Packaging](python-packaging.md) | Wheel layout, `simpler` vs `simpler_setup`, asset packaging | +| [Compiler Sanitizers](sanitizers.md) | ASAN / UBSan / TSAN builds | +| [Sim Multi-Device Isolation](sim_multi_device_isolation.md) | How the simulator isolates concurrent virtual devices | + +## When something is broken + +| Document | What it covers | +| -------- | -------------- | +| [troubleshooting/](troubleshooting/) | Device error codes, local timeout defaults, AICPU shared-SO faults, sim oversubscription hangs, macOS build issues, cpput ABI issues | +| [investigations/](investigations/README.md) | Considered-and-dropped proposals and measured dead ends. **Check here before proposing an optimization or refactor** | diff --git a/docs/capability-survey.md b/docs/capability-survey.md new file mode 100644 index 0000000000..dd655195ce --- /dev/null +++ b/docs/capability-survey.md @@ -0,0 +1,307 @@ +# Runtime Capability Survey — Topology, Launch, Communication + +**Snapshot: verified against `main` @ `e6a61f15`, 2026-07-27.** + +This is a **status** document: for each mechanism it answers *is this shipped, +exercised, gated, or only designed?* It deliberately does not re-explain +architecture — the reference docs below own that, and this page links to them +rather than restating them: + +- Hardware substrate → [hardware/chip-architecture.md](hardware/chip-architecture.md), + [hardware/mmio-performance.md](hardware/mmio-performance.md), + [hardware/cache-coherency.md](hardware/cache-coherency.md) +- Level model → [hierarchical_level_runtime.md](hierarchical_level_runtime.md) +- Three-program model → [chip-level-arch.md](chip-level-arch.md) +- AICPU launch mechanics → [aicpu-kernel-launch-mechanisms.md](aicpu-kernel-launch-mechanisms.md) +- Comm domains / overlays → [comm-domain.md](comm-domain.md), [a5-sdma-overlay.md](a5-sdma-overlay.md) +- Remote L3 / L4 → [remote-l3-worker-design.md](remote-l3-worker-design.md) + +Status claims rot faster than architecture. Re-derive rather than trust this +page when the snapshot SHA is old; every claim carries a `file:line` so it can +be re-checked directly. + +## Status vocabulary + +| Status | Meaning | +| ------ | ------- | +| **Shipped** | Implemented, reachable in a default build, covered by CI | +| **Shipped, not CI-run** | Implemented and reachable, but no CI job exercises it | +| **Gated** | Implemented but unreachable in any configuration available here | +| **Design only** | Documented contract or plan; no working data path | +| **Name only** | An identifier exists (enum, macro, string) with no implementation behind it | + +## Topology: L2 (host / AICPU / AICore) → L4 (host → remote host) + +The 7-level model (L6 Cluster … L0 Core) is declared in +[hierarchical_level_runtime.md](hierarchical_level_runtime.md). Its own status +table is accurate: L3 implemented; L4 local implemented, remote simulation only; +L5/L6 untested. + +**The level is a label in C++ and a real branch in Python.** `Worker` stores +`level_` (`src/common/hierarchical/worker.cpp:56`) and nothing else reads it, so +L3–L6 execute byte-identical Orchestrator / Scheduler / WorkerManager code. The +Python facade *does* branch: `level == 2` → single `ChipWorker`, `level >= 3` → +hierarchical, anything else `ValueError` +(`python/simpler/worker.py:4117-4123`); `add_remote_worker` and the +remote-memory APIs require `level >= 4` (`:2367`, `:2603`). A worker level is a +position in the orchestration tree and carries no physical meaning by itself. + +### L2 — one chip (shipped) + +The host cannot dispatch to AICore at all; all on-chip work is submitted to +AICPU, which runs the graph (`hardware/chip-architecture.md:132-136`). GM is +shared across a device's AICPU/AICore tiers but exclusive per `device_id`. + +| Aspect | a2a3 | a5 | +| ------ | ---- | -- | +| Die ↔ `device_id` | a2: 1 die → 1 id. a3: 2 dies → **2 ids**, and both dies **share one AICPU OS** (`src/a2a3/docs/hardware.md:20-24`) | 2 dies → **1 id**, one orchestrator per id (`src/a5/docs/hardware.md:12-14`) | +| AICore per die | 24 clusters → 24 AIC / 48 AIV | 18 clusters → 18 AIC / 36 AIV | +| `PLATFORM_MAX_BLOCKDIM` | 24 → 72 cores | 36 → 108 cores | +| AICPU cores per die | 2 clusters × 4 = 8 (`src/a2a3/docs/hardware.md:30-32`) | 2 clusters × 2 = 4 (`src/a5/docs/hardware.md:17-19`) | +| AICPU threads | max 4, launch bound 6 | max 7, launch bound 14 (7 physical × SMT) | +| Host-map (SVM) | `halHostRegister(DEV_SVM_MAP_HOST)`, dlsym'd (`src/a2a3/platform/onboard/host/device_runner.cpp:78-102`) | not overridden | +| Comm window | Fabric V2 handles, VMM-IPC fallback | VMM shareable handles only | + +Two numbers surprise readers who skip the arch docs: the default +`aicpu_thread_num` is **3** (`src/common/task_interface/call_config.h:112`) — +neither the per-arch max nor the launch bound — and AICore geometry is not +selectable at all, because `resolve_block_dim()` unconditionally takes the +device maximum (`src/common/platform/onboard/host/device_runner_base.cpp:1201-1212`). +Each arch doc's "three views of how many cores" section explains why the spec +count, the silicon count, and the runtime-visible count differ +(`src/a2a3/docs/hardware.md:42-51`). + +The AICPU↔AICore control path is the AIC_CTRL MMIO window: one LDR costs +95–105 ns and serializes within a thread, so polling N cores from one thread +costs ~95 ns × N and only more AICPU threads shrink the round +([hardware/mmio-performance.md](hardware/mmio-performance.md)). + +The **AICPU role split is per-runtime, not per-arch**: `tensormap_and_ringbuffer` +decouples an orchestrator thread at `tidx == nthreads-1` when `nthreads > 1` +and `SIMPLER_TMR_SERIAL_ORCH_SCHED_ENABLE` is off +(`src/a2a3/runtime/tensormap_and_ringbuffer/aicpu/aicpu_executor.cpp:260-273`); +`host_build_graph` runs no device-side orchestrator. + +### L3 — one host, many device ids (shipped) + +One forked process per `device_ids` entry, each binding its own `ChipWorker` in +the child (`python/simpler/worker.py:4366-4409`). Every parent↔child edge is a +POSIX-shm mailbox, and the HeapRing is mmap'd **before** any fork so children +inherit it (`src/common/hierarchical/worker.cpp:55-66`) — that shared region, +not just the mailbox, is what makes parent-allocated tensors visible to chip +children. Collectives are explicitly single-host: both backends state "Scope: +L3 single-host multi-card only" (`src/a2a3/platform/onboard/host/comm_hccl.cpp:19`). + +Two additional shipped L3↔L2 channels bypass the level abstraction and talk to +AICPU directly: [l3-l2-orch-comm.md](l3-l2-orch-comm.md) and +[l3-l2-message-queue.md](l3-l2-message-queue.md), with examples under +`examples/workers/l3/`. Parent-directed targeting of a specific child is +[directed-next-level-scheduling.md](directed-next-level-scheduling.md). + +### L4 — host → remote host (control plane shipped, data plane simulation only) + +Shipped: `add_remote_worker(RemoteWorkerSpec)` → JSON manifest over TCP → +`simpler-remote-worker` daemon → session runner → C++ `RemoteL3Endpoint` +registered as a NEXT_LEVEL endpoint and dispatched by the same Scheduler +(`python/simpler/worker.py:2362-2375`; `src/common/hierarchical/worker.cpp:82-93`). +The remote session builds a real `Worker(level=3, device_ids=…)` and initialises +its chip subtree before answering READY. + +**Design only:** `transport` defaults to `"sim"` and the daemon raises on any +other value (`python/simpler/remote_l3_worker.py:66`). Remote buffers are +`multiprocessing.shared_memory`, so `REMOTE_WINDOW` / `UB_LDST` are protocol +placeholders. The A2 RoCE / A3 HCCS / A5 UB HCOMM profiles are documented +contracts marked hardware-gated +([remote-l3-worker-design.md](remote-l3-worker-design.md):71-77). There is no +L4 example and no CI job starts the daemon. + +## Launching AICore and AICPU work (the CANN surface) + +The runtime binds the low-level **`rt*` / `rts*`** layer, not the public +`aclrt*` launch API. Seven entry points, one of which is a2a3-only: + +| Purpose | CANN call | Site | Status | +| ------- | --------- | ---- | ------ | +| Register AICore ELF | `rtRegisterAllKernel` | `src/common/platform/onboard/host/device_runner_base.cpp:1118` | Shipped | +| Launch AICore | `rtKernelLaunchWithHandleV2` | `device_runner_base.cpp:1139` | Shipped | +| Bootstrap AICPU SO | `rtAicpuKernelLaunchExWithArgs` (`KERNEL_TYPE_AICPU_KFC`) | `src/common/aicpu_loader/host/load_aicpu_op.cpp:201` | Shipped | +| Register AICPU op | `rtsBinaryLoadFromFile` | `load_aicpu_op.cpp:341` | Shipped | +| Resolve AICPU entries | `rtsFuncGetByName` (loops all declared symbols) | `load_aicpu_op.cpp:362` | Shipped | +| Launch AICPU | `rtsLaunchCpuKernel` | `load_aicpu_op.cpp:401` | Shipped | +| Unload AICPU binary | `rtsBinaryUnload` | `load_aicpu_op.cpp:226`, `:334` | Shipped | +| FFTS base address | `rtGetC2cCtrlAddr` → `KernelArgs::ffts_base_addr` | `src/a2a3/platform/onboard/host/device_runner.cpp:121` | Shipped, **a2a3 only** | + +The unload asymmetry explains a design that otherwise looks arbitrary: the +AICPU binary *can* be unloaded, the AICore ELF *cannot* (CANN exposes no public +`rtUnregisterAllKernel`), so the ELF handle is registered lazily and cached. +Per-run registration pinned an extra device copy and surfaced as `207001` at +launch with a `507899` cascade at `rtStreamCreate` +(`device_runner_base.cpp:1101-1124`). + +Per-*task* AICore kernels are not CANN-registered at all: they are `rtMemcpy`'d +into device GM as a `ChipCallable` image and entered through a raw device +function pointer +(`src/a2a3/runtime/tensormap_and_ringbuffer/aicore/aicore_executor.cpp:37-41`). + +### AICPU bootstrap + +Three stages, all shipped. A KFC launch targets CANN's preinstalled +`libaicpu_extend_kernels.so` (`DynTileFwkKernelServerInit`) carrying a private +byte-offset ABI; the device-side dispatcher writes the inner SO to +`/usr/lib64/aicpu_kernels/...` keyed by a truncated ELF Build-ID; then JSON +registration with `opKernelLib=AICPUKernel`. Two symbols are launched, not one: +`simpler_aicpu_init` (per-device one-shot `InitArgs`) and `simpler_aicpu_exec` +(`src/common/aicpu_loader/host/load_aicpu_op.h:155-158`). + +`numBlocks` is the AICPU thread count, but placement belongs to CANN, so the +host over-launches and a device-side gate reads `sched_getcpu()` and drops every +thread outside a host-chosen allowed-CPU table +(`src/common/platform/onboard/aicpu/platform_aicpu_affinity.cpp:31-40`). + +### Launch order and timeouts + +AICore is launched **before** the AICPU Run task, because the first +`rtKernelLaunchWithHandleV2` lazily loads the binary on-device: ~1.4 s against a +busy device versus ~0.4 ms idle (`src/a5/platform/onboard/host/device_runner.cpp:360-410`). +The a2a3 mirror of this ordering is self-documented as unverified on a2a3 +silicon. + +Three timeouts exist, and the constants are **defaults, not the operative +values**: op-execute 45 s, stream-sync 50 s, scheduler 10 s +(`src/a2a3/platform/include/common/platform_config.h:69,85,75`). All three are +env-overridable with ordering validation +(`resolve_onboard_timeout_config`, `device_runner_base.cpp:66-110`; +[troubleshooting/local-timeout-defaults.md](troubleshooting/local-timeout-defaults.md)), +and **CI runs at 2 s / 3 s / 4 s** (`.github/workflows/ci.yml:480-482`). Triage +a CI timeout against the CI values, not the header constants. + +Every failed launch runs a recovery path that is easy to miss: +`recover_device_or_mark_unusable` does a bounded +`aclrtSynchronizeDeviceWithTimeout`, and `force_reset_device()` calls +`aclrtResetDeviceForce` followed by a post-reset stream poison probe +(`src/a5/platform/onboard/host/device_runner.cpp:465-497`, `:567-620`). + +### Not used here + +- **`KERNEL_TYPE_AICPU_CUSTOM` ("Path B")** — absent from `src/`. Tried during + PR #537 and abandoned per issue #822: the cust subprocess is bound to + `cpuId=0`, whose L1 sits outside AICore's HBM snoop domain. Note that + [aicpu-kernel-launch-mechanisms.md](aicpu-kernel-launch-mechanisms.md) + **inverts** the Path A/B labels relative to issue #822's own usage. Treat + Path B as unvalidated on this stack rather than as a live option. +- **ACL launch family** (`aclrtLaunchKernel*`, `aclrtBinaryLoad*`) and + **`rtStarsTaskLaunch`** — no call sites. STARS appears only as the subsystem + that reaps the op-execute timeout. +- **a2a3 pipeline slot 1** — plumbed end to end but dead; `run()` hard-codes + slot 0 (`src/a2a3/platform/onboard/host/device_runner.cpp:218`). +- **Sim platform** uses no CANN at all: `dlopen` + `std::thread`, with + `SIM_AUTO_BLOCKDIM = 8` and one OS thread per AICore + (`src/common/platform/sim/host/device_runner_base.h:56-65`). + +## Communication engines: SDMA, URMA, CCU, HCCL, Fabric + +Four async engines are declared — +`ASYNC_ENGINE_{SDMA,ROCE,URMA,CCU}` +(`src/a2a3/runtime/tensormap_and_ringbuffer/runtime/pto_types.h:53-59`) — and +**two are name only**. ROCE and CCU appear as enum constants, +`COMPLETION_ENGINE_*` macros, and `return "CCU"` strings in +`async_engine_name()`; there is no backend directory, submit path, poll op, or +test for either, and no doc states what they are intended to be. CANN itself +does treat CCU as a first-class engine (`COMM_ENGINE_CCU = 5` in +`hccl/hcomm_res_defs.h`), but nothing in `src/` references `COMM_ENGINE_*`. + +The single wiring point is the completion-ops table: a2a3 registers COUNTER and +SDMA_EVENT_RECORD (`.../runtime/pto_async_wait.h:85-89`); a5 registers those +plus URMA_EVENT_HANDLE (`src/a5/.../pto_async_wait.h:90-98`). Out-of-range +values yield `PTO2_ERROR_ASYNC_COMPLETION_INVALID`. + +| Engine | a2a3 | a5 | Status | +| ------ | ---- | -- | ------ | +| COUNTER (default) | registered | registered | **Shipped** — CI-run on both arches (`ci.yml:883`, `async_notify_demo` / `deferred_notify_demo`, no `skipif`) | +| SDMA | build macro forced ON; runtime opt-in | `option(... OFF)` | a2a3 **Shipped** (dedicated CI step, `ci.yml:628-643`); a5 not built | +| URMA | absent | full implementation | **Gated** — see below | +| ROCE, CCU | enum only | enum only | **Name only** | + +**a2a3 SDMA is opt-in at runtime**, not "always on": the provider is always +compiled, but provisioning the 48 STARS streams requires +`Worker(..., enable_sdma=True)`, default `False` +(`python/simpler/worker.py:4178`, `:4396`; +`python/bindings/task_interface.cpp:1367`). It is quarantined from the general +CI sweep via `SDMA_IGNORE` (`ci.yml:600`) for a measured hazard: with 48 +device-only SDMA streams an AICore fault takes ~306 s to tear down versus ~0.3 s +without, traced to a single 300,000 ms remote TRS event timeout +([investigations/2026-07-a2a3-sdma-fault-teardown.md](investigations/2026-07-a2a3-sdma-fault-teardown.md), +issue #1425). + +**a5 URMA is real code that cannot execute.** The scheduler walks `UrmaCqCtx` +CQEs checking the owner bit, advances the tail and rings the doorbell +(`src/a5/.../backend/urma/urma_completion_scheduler.h:133-215`); the kernel +submits `TGET_ASYNC`/`TPUT_ASYNC` with 256 MB chunking. Both +sit behind `PTO_URMA_SUPPORTED`, which is **defined nowhere in this repo and +nowhere in the installed CANN pto headers**, so the `#else` branch returns +`PTO2_ERROR_ASYNC_COMPLETION_INVALID` immediately. The host overlay macro is +fully wired, so turning it on does not help — the device path stays unreachable. +a5's SDMA and URMA overlays are mutually exclusive by CMake `FATAL_ERROR` +because `CommContext` exposes a single `workSpace` pair +(`src/a5/platform/onboard/host/CMakeLists.txt:49-53`). + +**HCCL is bootstrap, not data movement.** The complete set of functions called +is `HcclGetRootInfo`, `HcclCommInitRootInfo`, `HcclBarrier`, `HcclCommDestroy`. +There is no `HcclAllReduce` / `AllGather` / `Send` / `Recv` anywhere; every +shipped collective is a hand-written AIV kernel that computes a peer pointer +from the symmetric window +(`tests/st/worker/collectives/allreduce/kernels/aiv/allreduce_ring_kernel.cpp:59-61`). + +**Fabric is undocumented.** a2a3 prefers `alloc_windows_via_fabric()` with +`ACL_MEM_SHARE_HANDLE_TYPE_FABRIC` and falls back to `alloc_windows_via_ipc()` +only when Fabric is unsupported +(`src/a2a3/platform/onboard/host/comm_hccl.cpp:676`, `:762`). a5 has zero +occurrences of "fabric". No `.md` in the repo describes Fabric as a +memory-sharing mechanism. + +One ABI fact constrains portability: the AICore→AICPU completion struct +diverged — `DeferredCompletionEntry` is 24 bytes on a2a3 and 32 on a5, the extra +8 being the `backend_cookie` URMA's poll needs. A URMA-on-a2a3 port must widen a +struct that is currently frozen by `static_assert`. + +## Open questions + +Unresolved after this survey, in rough order of how much they block: + +1. **What are `ASYNC_ENGINE_ROCE` and `ASYNC_ENGINE_CCU` for?** No design doc, + investigation entry, or code comment says whether they are reserved slots or + leftovers from a dropped design. +2. **Has a5 URMA ever run on silicon?** No CI run, test artifact, or + investigation attests to it, and `a5-sdma-overlay.md` has no URMA re-enable + checklist analogous to its SDMA one. +3. **Which CANN mitigation closed issue #822, and is Path B usable on CANN + 9.0.0?** The doc says "CANN-side mitigation landed" without naming it, and + nobody re-ran the repro. +4. **Does CANN's one-inner-SO-per-process latch still exist?** The whole + one-process-per-`(arch, runtime)` ChipWorker model rests on it, but it is + asserted only from CANN source paths that are not vendored here and no + in-repo probe detects it. +5. **Where would `PTO_URMA_SUPPORTED` ever be defined?** Not in this repo, not + in the installed CANN pto headers. +6. **Which platforms lack Fabric support?** Stated only as a code comment, never + enumerated, and a5's divergence to the V1 handle route is undocumented. + +## Documentation drift found while compiling this survey + +Each entry below was re-verified directly at the cited line. Line numbers drift; +re-check before editing. + +| Location | Claims | Reality | +| -------- | ------ | ------- | +| `hardware/chip-architecture.md:232` | AIC_CTRL MMIO is `Device-nGnRnE` | `Device-nGnRE`, proven from driver source (`hardware/mmio-performance.md:12`) | +| `worker-manager.md:174`, `:190` | dispatch poll uses `sleep_for(50us)`, "not busy-wait" | every mailbox wait spins; liveness is a wall-clock sample (`src/common/hierarchical/worker_manager.cpp:58`). A dispatch-path sleep is now banned by [codestyle](../.claude/rules/codestyle.md) rule 5 | +| `dynamic-linking.md:259` | AICore ELF is "registered each `launch_aicore_kernel()` call" | registration is lazy and cached (`device_runner_base.cpp:1101-1124`) | +| `dynamic-linking.md:355-361` | AICPU launches before AICore; call is `rtKernelLaunch` | AICore launches first; the call is `rtKernelLaunchWithHandleV2` | +| `comm-domain.md:111` | window is VMM + shareable-handle import with `aclrtDeviceEnablePeerAccess` | a2a3 prefers Fabric V2 (`comm_hccl.cpp:762`); the doc never mentions Fabric | +| `comm-domain.md:262-264` | a producer `CoreCallable` declares the SDMA workspace requirement | that API was removed by PR #1406 | +| `a5-sdma-overlay.md:24` | the a2a3 SDMA path "is always on" | build macro is ON; runtime provisioning defaults to `False` | +| `investigations/2026-07-a2a3-sdma-fault-teardown.md:153` | `sdma_async_completion_demo` is "unaffected by this change" | that demo sets `enable_sdma=True` (test:134), as CI's own comment states | +| `src/common/worker/pto_runtime_c_api.h:259` | "`config` carries block_dim (0 = auto)" | `CallConfig` has no such field — "There is no block_dim knob" (`src/common/task_interface/call_config.h:22`) | +| `src/common/platform/sim/host/device_runner_base.h:62-64` | "an explicit block_dim is still honoured" | same as above | +| `src/common/aicpu_loader/README.md:18-28`, `:47-51` | one `rtsFuncGetByName`; `device_id` in per-task `KernelArgs`; dispatcher under `build/lib//onboard//` | loops all symbols; `device_id` lives on `InitArgs`; dispatcher is at `build/lib//dispatcher/` | +| `tests/ut/cpp/a5/test_aicore_completion_mailbox.cpp:139` | "a5 is counter-only (no SDMA event-record backend)" | a5 registers SDMA and URMA ops (`src/a5/.../pto_async_wait.h:90-98`) | diff --git a/docs/dfx/README.md b/docs/dfx/README.md new file mode 100644 index 0000000000..e2bb0761f9 --- /dev/null +++ b/docs/dfx/README.md @@ -0,0 +1,50 @@ +# DFX and Profiling + +Every profiling / diagnostics reference lives in this directory. Start with the +framework doc if you are adding a collector, or jump straight to the per-feature +doc for the data you want. + +Analysis CLIs that consume these outputs are documented in +[simpler_setup/tools/README.md](../../simpler_setup/tools/README.md). + +## Framework and conventions + +| Document | What it covers | +| -------- | -------------- | +| [Profiling Framework](profiling-framework.md) | Collector architecture, host/device split, how perf levels gate collection | +| [Profiling / DFX Configuration Naming Rules](profiling-config-naming.md) | Naming conventions every new DFX knob must follow | +| [Profiling Name Map](profiling-name-map.md) | `func_id` → human-readable name mapping consumed by the trace tools | +| [Global DFX Backpressure](global-backpressure-design.md) | Block-on-contention and dual-signal freeze across collectors | +| [DFX Buffer Capacity Audit (a2a3)](dfx-buffer-capacity-audit.md) | Per-buffer capacity accounting and overflow behavior | + +## Timing and scheduling + +| Document | What it covers | +| -------- | -------------- | +| [L2 Timing](l2-timing.md) | `host_wall` / `device_wall` / Effective / Orch / Sched breakdown from `[STRACE]` | +| [Host runtime trace markers](host-trace.md) | The `[STRACE]` marker set emitted by the host runtime | +| [Device-side phase timing](device-phases.md) | Fixed AICPU phases and the variable-phase plan | +| [Scheduler-Overhead Model](sched-overhead-model.md) | Is the scheduler the bottleneck, or starved — the model behind `--overhead` | + +## Per-task traces + +| Document | What it covers | +| -------- | -------------- | +| [L2 Swimlane Profiling](l2-swimlane-profiling.md) | Per-task timing and scheduler phases across cores | +| [L0 Swimlane Profiling](l0-swimlane-profiling.md) | Intra-core AICore pipeline trace for a single task | +| [PMU Profiling](pmu-profiling.md) | Per-task AICore hardware counters | + +## Data and dependencies + +| Document | What it covers | +| -------- | -------------- | +| [Args Dump](args-dump.md) | Per-task argument capture, and replaying a task from it | +| [dep_gen](dep_gen.md) | Complete per-submit dependency graph, tensor-annotated | +| [Scope Stats](scope-stats.md) | Per-scope resource-usage peaks (ring fill, dep pool) | + +## Related, outside this directory + +| Document | What it covers | +| -------- | -------------- | +| [Log System](../logging.md) | Log levels and sinks — the host/device logging path, distinct from profiling collectors | +| [troubleshooting/](../troubleshooting/) | Device error codes and timeout defaults, for when a run fails rather than runs slowly | diff --git a/docs/dfx/args-dump.md b/docs/dfx/args-dump.md index 2a72104eda..c39cb0ea60 100644 --- a/docs/dfx/args-dump.md +++ b/docs/dfx/args-dump.md @@ -568,7 +568,7 @@ callback that gathers payload bytes and appends metadata to a shard-local record list, plus `reconcile_counters` / `export_dump_files` / `finalize`. The mgmt/collector threading, buffer pooling, and `Module` trait pattern are shared with PMU and L2Swimlane — see -[profiling-framework.md](../profiling-framework.md) for the +[profiling-framework.md](profiling-framework.md) for the framework reference. ### 5.5 a5 — same framework, host-shadow transport @@ -990,7 +990,7 @@ their unset fallback and keep the `#897` distributed-skew trade-off. ## 9. Related docs -- [profiling-framework.md](../profiling-framework.md) — shared +- [profiling-framework.md](profiling-framework.md) — shared host-side collector framework (a2a3 only). - [chip-level-arch.md](../chip-level-arch.md) — host / AICPU / AICore program boundaries this feature spans. diff --git a/docs/dfx/l2-swimlane-profiling.md b/docs/dfx/l2-swimlane-profiling.md index 7c774f2d28..8d399357a9 100644 --- a/docs/dfx/l2-swimlane-profiling.md +++ b/docs/dfx/l2-swimlane-profiling.md @@ -410,7 +410,7 @@ class TestPagedAttention(SceneTestCase): SceneTest extracts this into `/name_map_.json` and passes it to `swimlane_converter` automatically. See -[profiling-name-map.md](../profiling-name-map.md) for the full +[profiling-name-map.md](profiling-name-map.md) for the full schema and L3 example. ### 3.5 Dependency arrows from dep_gen @@ -810,7 +810,7 @@ to copy into the right per-core or per-thread vector, plus `reconcile_counters` / `export_swimlane_json` / `finalize`. The mgmt/collector threading and `Module` trait pattern are shared with PMU and ArgsDump — see -[profiling-framework.md](../profiling-framework.md) for the +[profiling-framework.md](profiling-framework.md) for the framework reference. ### 5.3 a5 — same framework, host-shadow transport @@ -1056,7 +1056,7 @@ and re-run the converter — see **Tasks show as `func_` instead of human names.** `deps.json` resolved the `func_id`, but the CALLABLE spec lacks `"name"` fields -or `name_map_.json` was not produced. See [profiling-name-map.md](../profiling-name-map.md). +or `name_map_.json` was not produced. See [profiling-name-map.md](profiling-name-map.md). **Some tasks missing from the swimlane.** Likely dropped on device because the buffer pool ran out. On a2a3 check @@ -1100,9 +1100,9 @@ rules. `SIMPLER_DFX` device-log markers (no swimlane capture, works with `--rounds > 1`); the lighter alternative when you don't need the per-task / phase deep dive. -- [profiling-framework.md](../profiling-framework.md) — shared +- [profiling-framework.md](profiling-framework.md) — shared host-side collector framework (a2a3 only). -- [profiling-name-map.md](../profiling-name-map.md) — `func_id` → +- [profiling-name-map.md](profiling-name-map.md) — `func_id` → human name mapping for swimlane labels. - [chip-level-arch.md](../chip-level-arch.md) — host / AICPU / AICore program boundaries this feature spans. diff --git a/docs/dfx/pmu-profiling.md b/docs/dfx/pmu-profiling.md index 086ec20b49..5d68c0e088 100644 --- a/docs/dfx/pmu-profiling.md +++ b/docs/dfx/pmu-profiling.md @@ -300,9 +300,9 @@ reconcile_counters() ← merge shard files into pmu.csv, then assert finalize(unregister, free) ``` -[`PmuCollector`](../src/a2a3/platform/include/host/pmu_collector.h) +[`PmuCollector`](../../src/a2a3/platform/include/host/pmu_collector.h) inherits from -[`profiling_common::ProfilerBase`](../src/common/platform/include/host/profiler_base.h): +[`profiling_common::ProfilerBase`](../../src/common/platform/include/host/profiler_base.h): the base class owns split mgmt threads, collector shards, and the `BufferPoolManager` they share. `PmuCollector` only supplies the PMU-specific pieces — the `PmuModule` trait that describes the @@ -316,7 +316,7 @@ them in the CSV directory; the next `start()` for the same output path removes those stale run-scoped files before collector threads launch. The mgmt/collector threading, buffer pooling, and `Module` trait pattern are shared with ArgsDump and L2Swimlane — see -[profiling-framework.md](../profiling-framework.md) for the framework reference. +[profiling-framework.md](profiling-framework.md) for the framework reference. ### 5.3 a5 — same framework, host-shadow transport (DAV_3510, 10 counters) @@ -427,7 +427,7 @@ PmuBuffer pool (rotated) (BUFFERS_PER_CORE per core) maintains a paired host-shadow `malloc()` per device buffer and synchronizes via `rtMemcpy` (onboard) / `memcpy` (sim). The framework copy hooks `profiling_copy_to_device` / `profiling_copy_from_device` -(in [`profiling_copy.h`](../../src/a5/platform/include/host/profiling_copy.h)) +(in [`profiling_copy.h`](../../src/common/platform/include/host/profiling_copy.h)) abstract this difference. Each AICore worker resolves its PMU MMIO base at kernel entry from @@ -436,7 +436,7 @@ register-base table the host already fills for AICPU) and reads its `PmuAicoreRing` from `KernelArgs::aicore_pmu_ring_addrs[block_idx]` (filled by the host in `PmuCollector::init`). Both addresses are forwarded by `KERNEL_ENTRY` into platform-owned per-core slots -([`aicore_profiling_state.h`](../src/a5/platform/include/aicore/aicore_profiling_state.h)); +([`aicore_profiling_state.h`](../../src/a5/platform/include/aicore/aicore_profiling_state.h)); the runtime `Handshake` carries no profiling fields. Because the resolved reg base is valid from Phase 1 onward (no AICPU-side init dependency), `aicore_execute` caches it once after Phase 3 alongside @@ -478,11 +478,11 @@ tasks in flight on a single AICore. Parity on `reg_task_id & 1` keeps adjacent dispatches from colliding (the runtime's `dispatch_seq++` guarantees neighboring register tokens differ by 1 → different slots). -[`PmuCollector`](../src/a5/platform/include/host/pmu_collector.h) on +[`PmuCollector`](../../src/a5/platform/include/host/pmu_collector.h) on a5 inherits the same CRTP base -([`profiling_common::ProfilerBase`](../src/common/platform/include/host/profiler_base.h)) +([`profiling_common::ProfilerBase`](../../src/common/platform/include/host/profiler_base.h)) as a2a3 and parameterizes -[`BufferPoolManager`](../src/common/platform/include/host/buffer_pool_manager.h) +[`BufferPoolManager`](../../src/common/platform/include/host/buffer_pool_manager.h) with `PmuModule`. The only a5-specific glue is the 5-callback `MemoryOps` and the per-tick shm mirror. @@ -561,7 +561,7 @@ Notes on this constraint: switches to a new buffer via the free queue. If no free buffer is available, records are dropped. Increase `PLATFORM_PMU_BUFFERS_PER_CORE` (default 4) in - [platform_config.h](../src/a5/platform/include/common/platform_config.h) + [platform_config.h](../../src/a5/platform/include/common/platform_config.h) if your workload produces bursts that exhaust the buffer pool. - A non-zero `diff` in the host's `record count mismatch` warning means AICPU attempted to commit `diff` records whose dual-issue @@ -627,7 +627,7 @@ host drain/replenish path has more buffer headroom. ## 9. Related docs -- [profiling-framework.md](../profiling-framework.md) — shared host-side +- [profiling-framework.md](profiling-framework.md) — shared host-side collector framework. - [chip-level-arch.md](../chip-level-arch.md) — host / AICPU / AICore program boundaries the PMU path spans. diff --git a/docs/profiling-config-naming.md b/docs/dfx/profiling-config-naming.md similarity index 98% rename from docs/profiling-config-naming.md rename to docs/dfx/profiling-config-naming.md index 2aa49b2ce4..22aa5c262e 100644 --- a/docs/profiling-config-naming.md +++ b/docs/dfx/profiling-config-naming.md @@ -7,7 +7,7 @@ onboard scripts, and external consumers (e.g. pypto-serving), so they must be consistent and self-describing. See [profiling-framework.md](profiling-framework.md) for the collector -architecture, and [dfx/host-trace.md](dfx/host-trace.md) for the `[STRACE]` +architecture, and [dfx/host-trace.md](host-trace.md) for the `[STRACE]` host-trace facility. ## The four rules diff --git a/docs/profiling-framework.md b/docs/dfx/profiling-framework.md similarity index 92% rename from docs/profiling-framework.md rename to docs/dfx/profiling-framework.md index c6725fdfbd..e3b955246a 100644 --- a/docs/profiling-framework.md +++ b/docs/dfx/profiling-framework.md @@ -3,27 +3,27 @@ Shared profiling infrastructure that the PMU, L2Swimlane, DepGen, ArgsDump, and ScopeStats collectors are built on. The host-side framework headers live in -[`src/common/platform/include/host/`](../src/common/platform/include/host/) +[`src/common/platform/include/host/`](../../src/common/platform/include/host/) and are consumed verbatim by both a2a3 and a5 collectors (PR #944 unified the previously-divergent per-arch copies into one set). The AICPU device-side producer algorithms live in -[`src/common/platform/include/aicpu/profiler_device_engine.h`](../src/common/platform/include/aicpu/profiler_device_engine.h) +[`src/common/platform/include/aicpu/profiler_device_engine.h`](../../src/common/platform/include/aicpu/profiler_device_engine.h) and are shared by the device writers that publish buffers into those host collectors. This page describes both halves; §8 covers the a5-specific transport deviations that the collectors themselves still carry. The per-collector pages -([pmu-profiling.md](dfx/pmu-profiling.md), -[l2-swimlane-profiling.md](dfx/l2-swimlane-profiling.md), -[dep_gen.md](dfx/dep_gen.md), -[args-dump.md](dfx/args-dump.md), -[scope-stats.md](dfx/scope-stats.md)) +([pmu-profiling.md](pmu-profiling.md), +[l2-swimlane-profiling.md](l2-swimlane-profiling.md), +[dep_gen.md](dep_gen.md), +[args-dump.md](args-dump.md), +[scope-stats.md](scope-stats.md)) describe the data each subsystem collects and how it enables it on-device. For everyday per-run timing (no collector, always on under `SIMPLER_HOST_STRACE`): -[l2-timing.md](dfx/l2-timing.md) covers host_wall / device_wall (`[STRACE]` markers) + -device-log Orch/Sched/Total, and [host-trace.md](dfx/host-trace.md) + -[device-phases.md](dfx/device-phases.md) cover the `[STRACE]` per-stage +[l2-timing.md](l2-timing.md) covers host_wall / device_wall (`[STRACE]` markers) + +device-log Orch/Sched/Total, and [host-trace.md](host-trace.md) + +[device-phases.md](device-phases.md) cover the `[STRACE]` per-stage breakdown of `simpler_run` (host stages + AICPU phase subdivision). ## 1. Why a shared framework @@ -53,7 +53,7 @@ space, publish a full buffer, wait for a free replacement, and install it as the current buffer. Both waits are resident block-on-contention gates — the writer parks until the host clears the freeze — not bounded drops; records are only lost if the 30-second host-crash backstop trips. See -[dfx/global-backpressure-design.md](dfx/global-backpressure-design.md). +[dfx/global-backpressure-design.md](global-backpressure-design.md). Before unification this was near-identical control flow repeated across collectors. The framework collapses the host side to one implementation @@ -117,7 +117,7 @@ subsystem's shared-memory layout is shaped. ### 3.1 `BufferPoolManager` — data layer -Defined in [`buffer_pool_manager.h`](../src/common/platform/include/host/buffer_pool_manager.h). +Defined in [`buffer_pool_manager.h`](../../src/common/platform/include/host/buffer_pool_manager.h). Owns: - `ready_shards_` — mgmt drain → collector hand-off shards, each backed by a @@ -148,7 +148,7 @@ Owns no threads. Every entry point is documented as one of: ### 3.2 `ProfilerBase` — control layer -Defined in [`profiler_base.h`](../src/common/platform/include/host/profiler_base.h). +Defined in [`profiler_base.h`](../../src/common/platform/include/host/profiler_base.h). Provides: - The mgmt thread(s), collector thread(s), and their lifecycle (`start` / @@ -179,7 +179,7 @@ Provides: before stashing, `start(tf)` becomes a no-op. `ProfilerAlgorithms` (in the same -[profiler_base.h](../src/common/platform/include/host/profiler_base.h)) +[profiler_base.h](../../src/common/platform/include/host/profiler_base.h)) is where the unified algorithms live: - `try_pop_aicpu_entry` — barrier-correct head/tail advance over the @@ -210,7 +210,7 @@ A stateless `struct` per subsystem (`PmuModule`, `L2SwimlaneModule`, `DepGenModule`, `DumpModule`, `ScopeStatsModule`) that tells the generic algorithms what the shared-memory layout looks like. The contract lives in the docblock at the top of -[`profiler_base.h`](../src/common/platform/include/host/profiler_base.h); +[`profiler_base.h`](../../src/common/platform/include/host/profiler_base.h); the required members are: | Member | Purpose | @@ -231,12 +231,12 @@ the required members are: | `kind_of(info) → int` | **Multi-kind only.** Tells the framework which recycled bin a finished buffer belongs to. Single-kind modules omit this; the framework passes 0 | The Module structs are defined alongside their collectors in -[pmu_collector.h](../src/a2a3/platform/include/host/pmu_collector.h), -[l2_swimlane_collector.h](../src/common/platform/include/host/l2_swimlane_collector.h), -[dep_gen_collector.h](../src/common/platform/include/host/dep_gen_collector.h), -[args_dump_collector.h](../src/common/platform/include/host/args_dump_collector.h), +[pmu_collector.h](../../src/a2a3/platform/include/host/pmu_collector.h), +[l2_swimlane_collector.h](../../src/common/platform/include/host/l2_swimlane_collector.h), +[dep_gen_collector.h](../../src/common/platform/include/host/dep_gen_collector.h), +[args_dump_collector.h](../../src/common/platform/include/host/args_dump_collector.h), and -[scope_stats_collector.h](../src/common/platform/include/host/scope_stats_collector.h) +[scope_stats_collector.h](../../src/common/platform/include/host/scope_stats_collector.h) — each is a few dozen lines of static methods over the subsystem's own `DataHeader` / ringbuffer types. @@ -268,7 +268,7 @@ and only has to provide: ### 3.5 `DeviceProfilerEngine` — AICPU producer algorithm layer Defined in -[`profiler_device_engine.h`](../src/common/platform/include/aicpu/profiler_device_engine.h). +[`profiler_device_engine.h`](../../src/common/platform/include/aicpu/profiler_device_engine.h). This is the device-side counterpart to `ProfilerAlgorithms`: it owns the AICPU producer control flow, while each subsystem keeps its record schema, flush/finalize behavior, and small layout hooks locally. @@ -422,7 +422,7 @@ Two things follow: the only bound is the 30-second host-crash backstop (`PLATFORM_DFX_BACKPRESSURE_TIMEOUT_CYCLES`), and a record is dropped only if that trips — i.e. the host is gone. Full state machine and its correctness - arguments: [dfx/global-backpressure-design.md](dfx/global-backpressure-design.md). + arguments: [dfx/global-backpressure-design.md](global-backpressure-design.md). - The AICPU writer publishes a full buffer to the ready queue before acquiring its replacement buffer. If no replacement is visible yet, the current pointer is cleared and later records first try to recover from @@ -460,23 +460,23 @@ Two things follow: Existing collectors are the canonical examples: -- [`PmuCollector`](../src/a2a3/platform/include/host/pmu_collector.h) - — single kind, per-core instances. See [pmu-profiling.md](dfx/pmu-profiling.md). -- [`DepGenCollector`](../src/common/platform/include/host/dep_gen_collector.h) - — single kind, one instance. See [dep_gen.md](dfx/dep_gen.md). -- [`ArgsDumpCollector`](../src/common/platform/include/host/args_dump_collector.h) - — single kind, per-AICPU-thread instances. See [args-dump.md](dfx/args-dump.md). -- [`ScopeStatsCollector`](../src/common/platform/include/host/scope_stats_collector.h) - — single kind, one instance. See [scope-stats.md](dfx/scope-stats.md). -- [`L2SwimlaneCollector`](../src/common/platform/include/host/l2_swimlane_collector.h) +- [`PmuCollector`](../../src/a2a3/platform/include/host/pmu_collector.h) + — single kind, per-core instances. See [pmu-profiling.md](pmu-profiling.md). +- [`DepGenCollector`](../../src/common/platform/include/host/dep_gen_collector.h) + — single kind, one instance. See [dep_gen.md](dep_gen.md). +- [`ArgsDumpCollector`](../../src/common/platform/include/host/args_dump_collector.h) + — single kind, per-AICPU-thread instances. See [args-dump.md](args-dump.md). +- [`ScopeStatsCollector`](../../src/common/platform/include/host/scope_stats_collector.h) + — single kind, one instance. See [scope-stats.md](scope-stats.md). +- [`L2SwimlaneCollector`](../../src/common/platform/include/host/l2_swimlane_collector.h) — four kinds (AICPU task, scheduler phase, orchestrator phase, AICore task), per-core / per-thread instances; the canonical multi-kind example. See - [l2-swimlane-profiling.md](dfx/l2-swimlane-profiling.md). + [l2-swimlane-profiling.md](l2-swimlane-profiling.md). ## 8. a5 specifics — host-shadow transport a5's framework headers (under -[`src/common/platform/include/host/`](../src/common/platform/include/host/)) +[`src/common/platform/include/host/`](../../src/common/platform/include/host/)) mirror a2a3's class shapes — same `ProfilerBase` / `BufferPoolManager` / `ProfilerAlgorithms` decomposition, same Module concept contract, same start/stop lifecycle. The only @@ -541,7 +541,7 @@ per-core ring/reg addresses travel through `KernelArgs`: | `regs` (per-physical-core register-base table) | host (already required for AICPU MMIO) | AICore `KERNEL_ENTRY` resolves `regs[get_physical_core_id()]` → `set_aicore_pmu_reg_base`; AICore `aicore_execute` caches the value at Phase-3 | AICore's per-core profiling slots live in -[`aicore/aicore_profiling_state.h`](../src/a5/platform/include/aicore/aicore_profiling_state.h) +[`aicore/aicore_profiling_state.h`](../../src/a5/platform/include/aicore/aicore_profiling_state.h) — `[[block_local]]` static on onboard, `pthread_key_t` TLS in sim. The runtime `aicore_execute(runtime, block_idx, core_type)` signature is unchanged; adding a new profiling field touches `KernelArgs` and this @@ -551,8 +551,8 @@ state surface, never the runtime protocol. L2Swimlane and PMU on a5 both use the "AICore writes, AICPU commits" model. The AICore-side write target is a per-core -[`L2SwimlaneAicoreRing`](../src/common/platform/include/common/l2_swimlane_profiling.h) / -[`PmuAicoreRing`](../src/a5/platform/include/common/pmu_profiling.h) of +[`L2SwimlaneAicoreRing`](../../src/common/platform/include/common/l2_swimlane_profiling.h) / +[`PmuAicoreRing`](../../src/a5/platform/include/common/pmu_profiling.h) of `PLATFORM_{L2,PMU}_AICORE_RING_SIZE` (= 2, dual-issue) slots, allocated once by the host and addressed by `BufferState::aicore_ring_ptr` (AICPU-visible) and the per-core diff --git a/docs/profiling-name-map.md b/docs/dfx/profiling-name-map.md similarity index 98% rename from docs/profiling-name-map.md rename to docs/dfx/profiling-name-map.md index 1a1324ec77..c0af471de3 100644 --- a/docs/profiling-name-map.md +++ b/docs/dfx/profiling-name-map.md @@ -140,7 +140,7 @@ mapping file is written and the tools fall back to default labels: `func_(rXtY)` when a `deps.json` resolved the `func_id`, or `task(rXtY)` when none is available (the host emits `func_id = -1`, so without `deps.json` tasks cannot be told apart by function — see -[dfx/l2-swimlane-profiling.md §3.5](dfx/l2-swimlane-profiling.md#35-dependency-arrows-from-dep_gen)). +[dfx/l2-swimlane-profiling.md §3.5](l2-swimlane-profiling.md#35-dependency-arrows-from-dep_gen)). ## Tool Usage