Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/dfx/profiling-config-naming.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ by **independent layers**:
| Compile-time (does the code exist?) | macros (`SIMPLER_DFX`, `SIMPLER_HOST_STRACE`, `SIMPLER_*_PROFILING`) | umbrella on, sub-tiers off |
| Per-run (does this run collect X?) | `SIMPLER_DFX_FLAG_*` bitmask via `CallConfig` | none selected |
| Runtime emission (does it actually emit?) | env (`SIMPLER_DEVICE_STRACE_ENABLE`, log level) | on |
| Runtime detail tier | `get_chip_swimlane_level()` | AICPU_TIMING |
| Runtime detail tier | `get_chip_swimlane_level()` | SCHEDULE_TIMING |

`SIMPLER_HOST_STRACE` (compile) gates whether `[STRACE]` markers exist at all;
`SIMPLER_DEVICE_STRACE_ENABLE` (runtime env) independently gates device-domain
Expand Down
14 changes: 7 additions & 7 deletions simpler_setup/tools/swimlane_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def _decode_perf_data(data, *, timeline_origin_ns=None): # noqa: PLR0912, PLR09
the freq MUST come from the host, never be hardcoded here)
- join `aicpu_tasks` by `(core_id, reg_task_id)`; unmatched rows are
dropped and counted
- AICORE_TIMING (level=1): aicpu_tasks is empty by construction, so
- TASK_TIMING (level=1): aicpu_tasks is empty by construction, so
synthesize one task per aicore record (dispatch/finish = 0)
- sort joined `tasks` by `task_id` (= task_token_raw)
- convert phase records from `*_cycles` → `*_time_us`
Expand Down Expand Up @@ -511,7 +511,7 @@ def _core_type(core_id):
}
)
elif level == 1:
# AICORE_TIMING fallback: AICPU records are absent (complete_task
# TASK_TIMING fallback: AICPU records are absent (complete_task
# bypassed). The AICore stream alone is the source of truth.
for row in aicore_rows:
core_id, task_token_raw, _reg_task_id, start_cycles, end_cycles, *rest = row
Expand Down Expand Up @@ -734,7 +734,7 @@ def load_deps_kernel_map(deps_path):
"""Build a ``task_id → kernel_ids[3]`` map from deps.json's ``tasks[]``.

a2a3 dep_gen captures per-task ``kernel_ids = [aic, aiv0, aiv1]`` so the
swimlane post-processor can resolve ``func_id`` at AICORE_TIMING (level=1)
swimlane post-processor can resolve ``func_id`` at TASK_TIMING (level=1)
where the AICore record alone is on disk and carries ``func_id == -1``.
The trace generator uses the per-record ``core_type`` to pick the right
subslot: ``aic → kernel_ids[0]``, ``aiv → kernel_ids[1]`` (falling back
Expand Down Expand Up @@ -943,7 +943,7 @@ def _append_dependency_flow_pair( # noqa: PLR0913


def resolve_func_id_from_kernel_map(task_id, core_type, kernel_map):
"""Look up the active ``func_id`` for an AICORE_TIMING record via dep_gen.
"""Look up the active ``func_id`` for a TASK_TIMING record via dep_gen.

Picks the kernel_ids[3] subslot by record ``core_type``. Returns the
resolved func_id (>= 0) on a hit, or -1 if no usable subslot was found
Expand Down Expand Up @@ -1438,7 +1438,7 @@ def generate_chrome_trace_json( # noqa: PLR0912, PLR0913, PLR0915
if verbose:
print(f" Unique cores: {len(unique_cores)}")

# Recover func_id for AICORE_TIMING (level=1) records, which the host
# Recover func_id for TASK_TIMING (level=1) records, which the host
# emits as func_id=-1. Resolve once here against dep_gen's per-task
# kernel_ids[3] (picking the subslot by core_type) and write it back onto
# the task, so every downstream consumer — Worker View, Scheduler View, and
Expand Down Expand Up @@ -3498,9 +3498,9 @@ def main():
deps_path = Path(args.deps_json) if args.deps_json else Path(input_path).parent / "deps.json"
deps_edges = load_deps_json(deps_path)
# Load the per-task kernel_ids map separately so the trace generator
# can resolve func_id=-1 records (AICORE_TIMING / level=1) back to
# can resolve func_id=-1 records (TASK_TIMING / level=1) back to
# the real kernel name. Optional — pre-schema deps.json without
# kernel_ids and AICPU_TIMING+ runs both leave this at None.
# kernel_ids and SCHEDULE_TIMING+ runs both leave this at None.
deps_kernel_map = load_deps_kernel_map(deps_path)
deps_block_map = load_deps_block_map(deps_path)
if deps_edges is not None:
Expand Down
12 changes: 6 additions & 6 deletions src/a2a3/runtime/host_build_graph/docs/profiling_levels.md
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ mirrors the PMU pattern — two independent channels (one binary, one int):
(shared memory). Host writes it in `ChipSwimlaneCollector::initialize`; AICPU
promotes it from the header in `chip_swimlane_aicpu_init` and exposes it via
`get_chip_swimlane_level()` (typed `ChipSwimlaneLevel`) for
`>= AICPU_TIMING / SCHED_PHASES / ORCH_PHASES` gates.
`>= SCHEDULE_TIMING / SCHED_PHASES / ORCH_PHASES` gates.

On sim, the binary on/off travels via the dlsym'd `set_chip_swimlane_enabled`
entry point; the granular level still goes through the shared-memory
Expand All @@ -412,7 +412,7 @@ header just like on onboard.
| ----- | -------- |
| 0 | Nothing (disabled) |
| 1 | AICore timing only (start/end/task_token_raw) — AICPU `complete_task` is bypassed |
| 2 | + AICPU dispatch_time, finish_time |
| 2 | + Scheduler per-task dispatch_time, finish_time |
| 3 | + Scheduler phases (`SCHED_*`) |
| 4 | + Orchestrator phases (full) |

Expand Down Expand Up @@ -458,10 +458,10 @@ content it depends on instead of relying on magic numbers:
// Cheap binary check, available immediately after kernel entry.
if (is_chip_swimlane_enabled()) { ... }

// AICPU dispatch/finish timestamps.
// Scheduler per-task dispatch/finish timestamps (AICPU-produced in this runtime).
// Granular checks below require chip_swimlane_aicpu_init to have already run
// (so the level has been promoted from the shared-memory header).
if (get_chip_swimlane_level() >= ChipSwimlaneLevel::AICPU_TIMING) { ... }
if (get_chip_swimlane_level() >= ChipSwimlaneLevel::SCHEDULE_TIMING) { ... }

// Scheduler main-loop phase records (SCHED_*)
if (get_chip_swimlane_level() >= ChipSwimlaneLevel::SCHED_PHASES) { ... }
Expand All @@ -477,8 +477,8 @@ shared-memory field and mirrors `PmuEventType : uint32_t`):
| Enumerator | Underlying value |
| ---------- | ---------------- |
| `DISABLED` | 0 |
| `AICORE_TIMING` | 1 |
| `AICPU_TIMING` | 2 |
| `TASK_TIMING` | 1 |
| `SCHEDULE_TIMING` | 2 |
| `SCHED_PHASES` | 3 |
| `ORCH_PHASES` | 4 |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,14 @@ void SchedulerContext::complete_slot_task(
}

#if SIMPLER_DFX
// Level gate: at AICORE_TIMING (level=1) the AICore record alone carries
// Level gate: at TASK_TIMING (level=1) the AICore record alone carries
// {start, end, task_token_raw}, host resolves func_id/core_type from
// dep_gen / per-core mapping, and AICPU has nothing to write. Only at
// AICPU_TIMING (level=2) and above does AICPU contribute dispatch/finish
// SCHEDULE_TIMING (level=2) and above does AICPU contribute dispatch/finish
// timestamps via complete_task. Bypassing here saves the per-completion
// hot-path cost (counter inc + ring lookup + record store + wmb + buffer
// rotation bookkeeping) for runs that only want AICore timing.
if (chip_swimlane.chip_swimlane_enabled && chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane.chip_swimlane_enabled && chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
#if SIMPLER_SCHED_PROFILING
uint64_t t_perf_start = get_sys_cnt_aicpu();
#endif
Expand Down Expand Up @@ -340,7 +340,7 @@ void SchedulerContext::check_running_cores_for_completion(
// charge AICPU completion-processing cost to the (end → finish)
// span, masking the actual FIN-delivery latency.
uint64_t finish_ts = 0;
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING && (t.pending_done || t.running_done)) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING && (t.pending_done || t.running_done)) {
finish_ts = get_sys_cnt_aicpu();
}
#endif
Expand Down Expand Up @@ -542,7 +542,7 @@ SchedulerContext::SyncStartStageResult SchedulerContext::stage_sync_start_cores(
sched_chip_swimlane_[thread_idx].sched_loop_count, static_cast<uint32_t>(handle_count)
);
}
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
dispatch_ts = pub_t0 != 0 ? pub_t0 : get_sys_cnt_aicpu();
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ class SchedulerContext {
//
// dispatch_timestamp_slot points to the CoreExecState slot
// (pending_dispatch_timestamp / running_dispatch_timestamp) selected at
// prepare time, or nullptr when chip swimlane is below AICPU_TIMING and no
// prepare time, or nullptr when chip swimlane is below SCHEDULE_TIMING and no
// dispatch timestamp is being recorded.
struct PublishHandle {
uint64_t reg_addr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ SchedulerContext::PublishHandle SchedulerContext::prepare_subtask_to_core(
// boundary. The completion-before-dispatch invariant makes this race-free
// (all prior tasks on this core have FIN'd, so AICore has dcci'd their
// records out of the old buffer). Gated on the same enable bit as flush
// so level=1 (AICORE_TIMING-only) participates without needing complete_task.
// so level=1 (TASK_TIMING-only) participates without needing complete_task.
#if SIMPLER_DFX
if (chip_swimlane_level_ != ChipSwimlaneLevel::DISABLED) {
chip_swimlane_aicpu_on_aicore_dispatch(core_id, thread_idx, reg_task_id);
Expand All @@ -246,7 +246,7 @@ SchedulerContext::PublishHandle SchedulerContext::prepare_subtask_to_core(

uint64_t *dispatch_timestamp_slot = nullptr;
#if SIMPLER_DFX
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
dispatch_timestamp_slot =
to_pending ? &core_exec_state.pending_dispatch_timestamp : &core_exec_state.running_dispatch_timestamp;
}
Expand Down Expand Up @@ -401,7 +401,7 @@ void SchedulerContext::dispatch_shape(
wmb();
uint64_t dispatch_ts = 0;
#if SIMPLER_DFX
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
dispatch_ts = get_sys_cnt_aicpu();
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ mirrors the PMU pattern — two independent channels (one binary, one int):
(shared memory). Host writes it in `ChipSwimlaneCollector::initialize`; AICPU
promotes it from the header in `chip_swimlane_aicpu_init` and exposes it via
`get_chip_swimlane_level()` (typed `ChipSwimlaneLevel`) for
`>= AICPU_TIMING / SCHED_PHASES / ORCH_PHASES` gates.
`>= SCHEDULE_TIMING / SCHED_PHASES / ORCH_PHASES` gates.

On sim, the binary on/off travels via the dlsym'd `set_chip_swimlane_enabled`
entry point; the granular level still goes through the shared-memory
Expand All @@ -236,7 +236,7 @@ header just like on onboard.
| ----- | -------- |
| 0 | Nothing (disabled) |
| 1 | AICore timing only (start/end/task_token_raw) — AICPU `complete_task` is bypassed |
| 2 | + dispatch_time, finish_time |
| 2 | + Scheduler per-task dispatch_time, finish_time |
| 3 | + Scheduler phases (`SCHED_*`) |
| 4 | + Orchestrator phases (full) |

Expand Down Expand Up @@ -286,10 +286,10 @@ content it depends on instead of relying on magic numbers:
// Cheap binary check, available immediately after kernel entry.
if (is_chip_swimlane_enabled()) { ... }

// AICPU dispatch/finish timestamps.
// Scheduler per-task dispatch/finish timestamps (AICPU-produced in this runtime).
// Granular checks below require chip_swimlane_aicpu_init to have already run
// (so the level has been promoted from the shared-memory header).
if (get_chip_swimlane_level() >= ChipSwimlaneLevel::AICPU_TIMING) { ... }
if (get_chip_swimlane_level() >= ChipSwimlaneLevel::SCHEDULE_TIMING) { ... }

// Scheduler main-loop phase records (SCHED_*)
if (get_chip_swimlane_level() >= ChipSwimlaneLevel::SCHED_PHASES) { ... }
Expand All @@ -305,8 +305,8 @@ shared-memory field and mirrors `PmuEventType : uint32_t`):
| Enumerator | Underlying value |
| ---------- | ---------------- |
| `DISABLED` | 0 |
| `AICORE_TIMING` | 1 |
| `AICPU_TIMING` | 2 |
| `TASK_TIMING` | 1 |
| `SCHEDULE_TIMING` | 2 |
| `SCHED_PHASES` | 3 |
| `ORCH_PHASES` | 4 |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,14 +247,14 @@ void SchedulerContext::complete_slot_task(
}

#if SIMPLER_DFX
// Level gate: at AICORE_TIMING (level=1) the AICore record alone carries
// Level gate: at TASK_TIMING (level=1) the AICore record alone carries
// {start, end, task_token_raw}, host resolves func_id/core_type from
// dep_gen / per-core mapping, and AICPU has nothing to write. Only at
// AICPU_TIMING (level=2) and above does AICPU contribute dispatch/finish
// SCHEDULE_TIMING (level=2) and above does AICPU contribute dispatch/finish
// timestamps via complete_task. Bypassing here saves the per-completion
// hot-path cost (counter inc + ring lookup + record store + wmb + buffer
// rotation bookkeeping) for runs that only want AICore timing.
if (chip_swimlane.chip_swimlane_enabled && chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane.chip_swimlane_enabled && chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
#if SIMPLER_SCHED_PROFILING
uint64_t t_perf_start = get_sys_cnt_aicpu();
#endif
Expand Down Expand Up @@ -391,7 +391,7 @@ void SchedulerContext::check_running_cores_for_completion(
// charge AICPU completion-processing cost to the (end → finish)
// span, masking the actual FIN-delivery latency.
uint64_t finish_ts = 0;
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING && (t.pending_done || t.running_done)) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING && (t.pending_done || t.running_done)) {
finish_ts = get_sys_cnt_aicpu();
}
#endif
Expand Down Expand Up @@ -604,7 +604,7 @@ SchedulerContext::SyncStartStageResult SchedulerContext::stage_sync_start_cores(
sched_chip_swimlane_[thread_idx].sched_loop_count, static_cast<uint32_t>(handle_count)
);
}
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
dispatch_ts = pub_t0 != 0 ? pub_t0 : get_sys_cnt_aicpu();
}
#endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ class SchedulerContext {
//
// dispatch_timestamp_slot points to the CoreExecState slot
// (pending_dispatch_timestamp / running_dispatch_timestamp) selected at
// prepare time, or nullptr when chip swimlane is below AICPU_TIMING and no
// prepare time, or nullptr when chip swimlane is below SCHEDULE_TIMING and no
// dispatch timestamp is being recorded.
struct PublishHandle {
uint64_t reg_addr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ SchedulerContext::PublishHandle SchedulerContext::prepare_subtask_to_core(
// released once AICore ACKs this boundary dispatch (see the ACK hook in
// check_running_cores_for_completion), because FIN precedes the swimlane
// record on this runtime. `reg_task_id` is passed as that ACK gate. Gated on
// the same enable bit as flush so level=1 (AICORE_TIMING-only) participates.
// the same enable bit as flush so level=1 (TASK_TIMING-only) participates.
#if SIMPLER_DFX
if (chip_swimlane_level_ != ChipSwimlaneLevel::DISABLED) {
chip_swimlane_aicpu_on_aicore_dispatch(core_id, thread_idx, reg_task_id);
Expand All @@ -225,7 +225,7 @@ SchedulerContext::PublishHandle SchedulerContext::prepare_subtask_to_core(

uint64_t *dispatch_timestamp_slot = nullptr;
#if SIMPLER_DFX
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
dispatch_timestamp_slot =
to_pending ? &core_exec_state.pending_dispatch_timestamp : &core_exec_state.running_dispatch_timestamp;
}
Expand Down Expand Up @@ -378,7 +378,7 @@ void SchedulerContext::dispatch_shape(
wmb();
uint64_t dispatch_ts = 0;
#if SIMPLER_DFX
if (chip_swimlane_level_ >= ChipSwimlaneLevel::AICPU_TIMING) {
if (chip_swimlane_level_ >= ChipSwimlaneLevel::SCHEDULE_TIMING) {
dispatch_ts = get_sys_cnt_aicpu();
}
#endif
Expand Down
Loading
Loading