Skip to content
heliaPROFILER
User guide
HELIA

PMU counters

Choose what the per-layer measurement counts. hpx captures cycles, instructions, cache and bus activity, and on a Cortex-M55 the MVE vector unit and, on Atomiq110, the Ethos-U NPU. The tables on this page are generated from the counter registry of the hpx you are reading about, so the names and groups are the ones the profiler accepts.

A working profile (First profile) and a board whose family you know from Boards and targets.

SoC Profiling domains Counter groups Per-operator record budget
apollo3p cpu cpu 2048
apollo4p cpu cpu 2048
apollo4l cpu cpu 2048
apollo510 cpu, memory, mve cpu, memory, mve 4096
apollo510b cpu, memory, mve cpu, memory, mve 4096
apollo5b cpu, memory, mve cpu, memory, mve 4096
apollo330P cpu, memory, mve cpu, memory, mve 512
apollo510L cpu, memory, mve cpu, memory, mve 512
atomiq110 cpu, memory, mve, ethos_npu cpu, ethos_npu, memory, mve 4096

The rows come from list_socs() and SocDef.profiling_domains through supported_groups_for_domains() in src/helia_profiler/platform/. On a DWT-only SoC the profiler warns and captures cycle counts only; a pmu_counters selection has no effect there, and the mve group is rejected at preflight.

profiling.pmu_counters maps a group to a selection:

Selection Meaning
default the curated subset for that group, sized to fit one pass
all every counter in the group, captured over several passes
[name, ...] an explicit list of counter names
profiling:
pmu_counters:
cpu: default
memory: [ARM_PMU_L1D_CACHE, ARM_PMU_L1D_CACHE_MISS_RD, ARM_PMU_DTCM_ACCESS]
mve: all
Terminal window
hpx profile model.tflite --pmu-counters cpu:default --pmu-counters mve:all
hpx profile model.tflite --pmu-counters mve:ARM_PMU_MVE_INST_RETIRED,ARM_PMU_MVE_STALL

per_layer defaults to true, iterations to 100, warmup to 5 and aggregation to median. Names are case-sensitive and must match the catalogue exactly; an unknown name fails with the full sorted list.

Each group below lists every counter hpx knows, with the curated default selection first.

default selects ARM_PMU_CPU_CYCLES, ARM_PMU_INST_RETIRED, ARM_PMU_STALL_FRONTEND, ARM_PMU_STALL_BACKEND.

Counter Event Description
ARM_PMU_BR_IMMED_RETIRED 13 Immediate branch architecturally executed
ARM_PMU_BR_MIS_PRED_RETIRED 34 Mispredicted branch instruction architecturally executed
ARM_PMU_BR_RETIRED 33 Branch instruction architecturally executed
ARM_PMU_BR_RETURN_RETIRED 14 Function return instruction architecturally executed and the condition code check pass
ARM_PMU_CPU_CYCLES (default) 17 Cycle
ARM_PMU_EXC_RETURN 10 Exception return instruction architecturally executed and the condition code check pass
ARM_PMU_EXC_TAKEN 9 Exception entry
ARM_PMU_INST_RETIRED (default) 8 Instruction architecturally executed
ARM_PMU_L1I_CACHE_REFILL 1 L1 I-Cache refill
ARM_PMU_LD_RETIRED 6 Memory-reading instruction architecturally executed and condition code check pass
ARM_PMU_LE_CANCEL 264 Loop end instruction not taken
ARM_PMU_LE_RETIRED 256 Loop end instruction executed
ARM_PMU_PC_WRITE_RETIRED 12 Software change to the Program Counter (PC). Instruction is architecturally executed and condition code check pass
ARM_PMU_SE_CALL_NS 277 Call to non-secure function, resulting in Security state change
ARM_PMU_SE_CALL_S 276 Call to secure function, resulting in Security state change
ARM_PMU_STALL 60 Stall cycle for instruction or operation not sent for execution
ARM_PMU_STALL_BACKEND (default) 36 No operation issued because of the backend
ARM_PMU_STALL_FRONTEND (default) 35 No operation issued because of the frontend
ARM_PMU_ST_RETIRED 7 Memory-writing instruction architecturally executed and condition code check pass
ARM_PMU_SW_INCR 0 Software update to the PMU_SWINC register, architecturally executed and condition code check pass
ARM_PMU_UNALIGNED_LDST_RETIRED 15 Unaligned memory memory-reading or memory-writing instruction architecturally executed and condition code check pass

default selects ETHOSU_PMU_CYCLE, ETHOSU_PMU_NPU_ACTIVE, ETHOSU_PMU_MAC_ACTIVE, ETHOSU_PMU_SRAM_RD_DATA_BEAT_RECEIVED.

Counter Event Description
ETHOSU_PMU_CYCLE (default) 0 Total NPU cycles while the command stream runs
ETHOSU_PMU_EXT_RD_DATA_BEAT_RECEIVED 0 External (flash/MRAM) read data beats
ETHOSU_PMU_EXT_WR_DATA_BEAT_WRITTEN 0 External (flash/MRAM) write data beats
ETHOSU_PMU_MAC_ACTIVE (default) 0 Cycles the MAC engine is active
ETHOSU_PMU_NPU_ACTIVE (default) 0 Cycles the NPU is active (not idle/stalled)
ETHOSU_PMU_NPU_IDLE 0 Cycles the NPU is idle
ETHOSU_PMU_SRAM_RD_DATA_BEAT_RECEIVED (default) 0 SRAM interface read data beats
ETHOSU_PMU_SRAM_WR_DATA_BEAT_WRITTEN 0 SRAM interface write data beats
ETHOSU_PMU_WD_ACTIVE 0 Cycles the weight decoder is active

default selects ARM_PMU_MEM_ACCESS, ARM_PMU_L1D_CACHE_REFILL, ARM_PMU_BUS_ACCESS, ARM_PMU_BUS_CYCLES.

Counter Event Description
ARM_PMU_BUS_ACCESS (default) 25 Bus access
ARM_PMU_BUS_CYCLES (default) 29 Bus cycles
ARM_PMU_DTCM_ACCESS 16392 Data TCM access
ARM_PMU_ITCM_ACCESS 16391 Instruction TCM access
ARM_PMU_L1D_CACHE 4 L1 D-Cache access
ARM_PMU_L1D_CACHE_ALLOCATE 31 Level 1 data cache allocation without refill
ARM_PMU_L1D_CACHE_MISS_RD 57 Level 1 data cache read miss
ARM_PMU_L1D_CACHE_RD 64 Level 1 data cache read
ARM_PMU_L1D_CACHE_REFILL (default) 3 L1 D-Cache refill
ARM_PMU_L1D_CACHE_WB 21 Level 1 data cache write-back
ARM_PMU_L1I_CACHE 20 Level 1 instruction cache access
ARM_PMU_LL_CACHE_MISS_RD 55 Last level data cache read miss
ARM_PMU_LL_CACHE_RD 54 Last level data cache read
ARM_PMU_MEMORY_ERROR 26 Local memory error
ARM_PMU_MEM_ACCESS (default) 19 Data memory access

default selects ARM_PMU_MVE_INST_RETIRED, ARM_PMU_MVE_INT_MAC_RETIRED, ARM_PMU_MVE_LDST_RETIRED, ARM_PMU_MVE_STALL.

Counter Event Description
ARM_PMU_MVE_FP_HP_RETIRED 520 MVE half-precision floating-point instruction architecturally executed
ARM_PMU_MVE_FP_MAC_RETIRED 532 MVE floating-point multiply or multiply-accumulate instruction architecturally executed
ARM_PMU_MVE_FP_RETIRED 516 MVE floating-point instruction architecturally executed
ARM_PMU_MVE_FP_SP_RETIRED 524 MVE single-precision floating-point instruction architecturally executed
ARM_PMU_MVE_INST_RETIRED (default) 512 MVE instruction architecturally executed
ARM_PMU_MVE_INT_MAC_RETIRED (default) 552 MVE multiply or multiply-accumulate instruction architecturally executed
ARM_PMU_MVE_INT_RETIRED 548 MVE integer instruction architecturally executed
ARM_PMU_MVE_LDST_CONTIG_RETIRED 580 MVE contiguous load or store instruction architecturally executed
ARM_PMU_MVE_LDST_MULTI_RETIRED 604 MVE memory instruction targeting multiple registers architecturally executed
ARM_PMU_MVE_LDST_NONCONTIG_RETIRED 592 MVE non-contiguous load or store instruction architecturally executed
ARM_PMU_MVE_LDST_RETIRED (default) 568 MVE load or store instruction architecturally executed
ARM_PMU_MVE_LDST_UNALIGNED_NONCONTIG_RETIRED 664 MVE unaligned noncontiguous load or store instruction architecturally executed
ARM_PMU_MVE_LDST_UNALIGNED_RETIRED 652 MVE unaligned memory load or store instruction architecturally executed
ARM_PMU_MVE_LD_CONTIG_RETIRED 584 MVE contiguous load instruction architecturally executed
ARM_PMU_MVE_LD_MULTI_RETIRED 608 MVE memory load instruction targeting multiple registers architecturally executed
ARM_PMU_MVE_LD_NONCONTIG_RETIRED 596 MVE non-contiguous load instruction architecturally executed
ARM_PMU_MVE_LD_RETIRED 572 MVE load instruction architecturally executed
ARM_PMU_MVE_LD_UNALIGNED_RETIRED 656 MVE unaligned load instruction architecturally executed
ARM_PMU_MVE_PRED 696 Cycles where one or more predicated beats architecturally executed
ARM_PMU_MVE_STALL (default) 716 Stall cycles caused by an MVE instruction
ARM_PMU_MVE_STALL_BREAK 723 Stall cycles caused by an MVE chain break
ARM_PMU_MVE_STALL_DEPENDENCY 724 Stall cycles caused by MVE register dependency
ARM_PMU_MVE_STALL_RESOURCE 717 Stall cycles caused by an MVE instruction because of resource conflicts
ARM_PMU_MVE_STALL_RESOURCE_FP 719 Stall cycles caused by an MVE instruction because of floating-point resource conflicts
ARM_PMU_MVE_STALL_RESOURCE_INT 720 Stall cycles caused by an MVE instruction because of integer resource conflicts
ARM_PMU_MVE_STALL_RESOURCE_MEM 718 Stall cycles caused by an MVE instruction because of memory resource conflicts
ARM_PMU_MVE_ST_CONTIG_RETIRED 588 MVE contiguous store instruction architecturally executed
ARM_PMU_MVE_ST_MULTI_RETIRED 612 MVE memory store instruction targeting multiple registers architecturally executed
ARM_PMU_MVE_ST_NONCONTIG_RETIRED 600 MVE non-contiguous store instruction architecturally executed
ARM_PMU_MVE_ST_RETIRED 576 MVE store instruction architecturally executed
ARM_PMU_MVE_ST_UNALIGNED_RETIRED 660 MVE unaligned store instruction architecturally executed
ARM_PMU_MVE_VREDUCE_FP_RETIRED 676 MVE floating-point vector reduction instruction architecturally executed
ARM_PMU_MVE_VREDUCE_INT_RETIRED 680 MVE integer vector reduction instruction architecturally executed
ARM_PMU_MVE_VREDUCE_RETIRED 672 MVE vector reduction instruction architecturally executed

Generated from the counter registry at source tree fe269596788d6ab1604cf433559e96b5f48c1d13: 79 counters in 4 groups across 9 SoCs.

The Ethos-U counters are sampled from the NPU’s own PMU through the core driver, per command stream, and only mean something for Vela-compiled models on the ethos_u engine backend; layers the NPU never dispatched are reported through the NPU_DISPATCHED column rather than as zeros.

The Cortex-M55 PMU has 8 hardware counter slots; hpx chains pairs into 32-bit logical counters to avoid overflow, so each firmware pass captures 4 counters per group. A larger selection is planned into passes, each pass builds, flashes and captures warmup + iterations inferences, and the results merge into one per-layer table. profile_results.csv is always the merged result; output.detailed: true adds detailed/profile_<group>.csv and profile_<group>_<pass>.csv. Selecting all on every group spans the whole catalogue and runs many independent passes; use default or an explicit list while iterating.

profiling.iterations inferences per pass, after profiling.warmup discarded runs, combined per layer by profiling.aggregation:

Method Behaviour
median (default) robust to corrupted or outlier iterations
mean arithmetic average
trimmed drops the high and low extremes, then averages

All three first reject structurally invalid samples (a uint32 wrap, a frozen-zero row) and log how many; a counter with no surviving samples is omitted rather than replaced. profiling.per_layer: false captures whole-model counters only. Every run also performs a clean end-to-end pass with no per-layer instrumentation and reports its cycle count next to the per-layer sum; a small delta between the two is the instrumentation overhead and is shown in the terminal.

  • The terminal’s top-layers table: layers by cycles with their share of the total, and on a Cortex-M55 the MVE instruction share and MACs per MVE instruction.
  • profile_results.csv: one row per layer, one column per captured counter, merged across passes; overflow is True for a layer whose counter saturated, whose values are then a lower bound.
  • detailed/profile_<group>.csv and per-pass files with output.detailed.
  • model_explorer/me_overlay_<COUNTER>.json, one per counter, for Model Explorer.
Derived metric Formula Where
L1D hit rate (1 - L1D_CACHE_MISS_RD / L1D_CACHE_RD) x 100%, falling back to L1D_CACHE and L1D_CACHE_REFILL as a complete pair summary.json, detailed/memory.json
MVE instruction share MVE_INST_RETIRED / INST_RETIRED x 100% terminal
MVE MAC density MVE_INT_MAC_RETIRED / MVE_INST_RETIRED terminal
MVE load/store density MVE_LDST_RETIRED / MVE_INST_RETIRED terminal
MVE stall share MVE_STALL / CPU_CYCLES x 100% terminal

A derived rate is omitted, not guessed, when no consistent counter pair covers every layer.

6. Apollo3 and Apollo4: the debugger stays attached

Section titled “6. Apollo3 and Apollo4: the debugger stays attached”

On the Cortex-M4F families the DWT->CYCCNT cycle counter lives in the core debug power domain, powered only while a debugger asserts the Debug Access Port’s CDBGPWRUPREQ, which firmware cannot set. If the host released the probe after reset the domain would power down mid-run and every per-layer cycle count would read 0. The rtt and swo transports hold a debugger attached anyway; for uart and usb_cdc hpx detects these families and keeps a pylink session attached for the whole capture. Apollo5 boards keep releasing the probe after reset: their Armv8-M PMU does not need it and the secure bootloader prefers it. The dedicated power binary never has a debugger, which is why it times its window with STIMER on those families (SocCapabilities.power_window_timer).

Each SoC also reserves a fixed number of per-operator PMU records (SocDef.pmu_max_ops). A model that runs more operators than that fails the capture with HPX_ERROR=operator_count_exceeds_capacity on every engine; the limit is per SoC rather than a configuration key.

profile_results.csv with one column per requested counter, overflow_detected: false in summary.json, and a clean-pass cycle count close to the per-layer sum.

Symptom Cause Fix
overflow_detected: true a counter wrapped its 32-bit accumulator on a very long or hot layer, or that layer’s PMU read failed fewer iterations, or fewer or narrower counters for that layer
selections silently ignored a DWT-only SoC expected; hpx profile --verbose shows the warning
per-layer cycles read 0 on Apollo4 the probe was released early over uart or usb_cdc check for a custom reset or lifecycle override
all takes a long time many independent build, flash and capture passes narrow the selection
unknown counter name case or spelling copy it from the catalogue above
group not supported for this target mve needs a Cortex-M55; ethos_npu needs Atomiq110 pick a group the family table lists

Power measurement to add energy to the same window, or Output files for every column the CSV carries.