Skip to content
heliaPROFILER
Examples
HELIA

Every counter, every layer

Get the complete counter picture of a model rather than the default four. You will learn how hpx schedules more counters than the hardware holds at once, what the merged CSV looks like, and which derived ratios to compute.

An Apollo510 EVB (Cortex-M55 with the Armv8-M PMU and MVE) on its J-Link USB port. A Cortex-M4 board cannot run this recipe: it exposes the DWT cycle counter only (Boards and targets).

hpx with the aot extra (the config uses heliaAOT), the GNU Arm toolchain, CMake, Ninja and J-Link software.

examples/quickstart/hpx_full_sweep.yml:

model:
path: kws_model.tflite
arena_size: 131072
engine:
type: helia-aot
config:
prefix: hpx
module_name: hpx_model
target:
board: apollo510_evb
toolchain: arm-none-eabi-gcc
profiling:
pmu_counters:
cpu: all
memory: all
mve: all
per_layer: true
iterations: 5
warmup: 2
power:
enabled: false
output:
format: csv
dir: ./results/results_full_sweep
model_explorer: true
detailed: true

all on three groups asks for every counter the SoC’s catalogue lists for that group; the PMU counters page carries the catalogue per SoC.

Terminal window
cd examples/quickstart
hpx profile --config hpx_full_sweep.yml

Not yet captured for this config. The shape of the per-layer file is the same as the default-counter bundle shipped with Profile a model, which has four CPU counters:

id,op,ARM_PMU_CPU_CYCLES,ARM_PMU_INST_RETIRED,ARM_PMU_STALL_FRONTEND,ARM_PMU_STALL_BACKEND,cycles,cycles_pct,overflow,macs,ops,cycles_per_mac
0,CONV_2D,337348.0,262360.0,1907.0,39945.0,337348.0,16.4,False,320000,640000,1.05
1,DEPTHWISE_CONV_2D,216205.0,155556.0,1358.0,48006.0,216205.0,10.5,False,72000,144000,3.0
2,CONV_2D,209934.0,164568.0,7.0,24863.0,209934.0,10.2,False,512000,1024000,0.41

With the three groups on all, the same rows carry one column per counter in the catalogue, and output.detailed: true adds detailed/profile_<preset>.csv per firmware pass and detailed/profile_<group>.csv per group, plus detailed/memory.json.

  • The SoC holds a fixed number of PMU counters at once, so the firmware runs the model once per counter preset (<group>_<index>, for example cpu_0, cpu_1, memory_0) and the host merges the presets by layer id. Every row is therefore the same operator measured in several passes; cycles comes from the pass that carried ARM_PMU_CPU_CYCLES (Data capture).
  • Ratios are more useful than raw counts: ARM_PMU_L1D_CACHE_REFILL / ARM_PMU_L1D_CACHE is the data-cache miss rate, ARM_PMU_MVE_INST_RETIRED / ARM_PMU_INST_RETIRED the vector share, STALL_BACKEND / CPU_CYCLES the fraction of cycles waiting on memory or the pipeline. The PMU counters page lists the derived metrics hpx computes and the ones to compute yourself.
  • overflow is True when a 32-bit counter saturated in any pass; the run is then invalid for that counter and fewer iterations or fewer counters per pass fix it.
  • macs, ops and cycles_per_mac join the host-side model analysis to the measured row by the operator’s original index, so heliaAOT rows line up with the model even where the compiler skipped operators.
  • One group at a time: pmu_counters: {memory: all} keeps the run short and the passes few.
  • Explicit lists: memory: [ARM_PMU_L1D_CACHE, ARM_PMU_L1D_CACHE_MISS_RD] names counters under the group that owns them; an unsupported name or group for the SoC is rejected at preflight.
  • heliaRT instead of heliaAOT: the counters are engine-independent; only the operator rows differ.
  • Overlays: output.model_explorer: true writes one overlay per counter for Model Explorer.

Not yet validated. The nightly suite captures the default cpu group only, so no bundle with the memory and mve groups exists; the CSV excerpt above is from apollo510_evb-kws-rt-ns-arm-none-eabi-gcc-rtt-auto (nightly run 35078330526, 2026-09-16, hpx 0.1.6 at 0714893), which ran the default four counters.