# Model Explorer overlays

Look at where the cycles go on the graph rather than in a table. hpx
writes one overlay JSON per captured counter that
[Model Explorer](https://github.com/google-ai-edge/model-explorer) renders
as a colour over each operator node.

## Prerequisites

A result bundle with `model_explorer/` in it (the default; `output.model_explorer`
is `true`), the `.tflite` model that produced it, and Model Explorer in a
browser.

## Which overlay

| File | Value on each node |
|---|---|
| `model_explorer/me_overlay_<COUNTER>.json` | that counter's per-layer aggregate, one file per counter captured, for example `me_overlay_ARM_PMU_CPU_CYCLES.json`, `me_overlay_ARM_PMU_INST_RETIRED.json`, `me_overlay_ARM_PMU_MVE_INST_RETIRED.json` |

Each overlay maps graph node ids to that counter's raw per-layer value and
carries a three-stop gradient (`GRADIENT_COST` in
`report/model_explorer.py`): Model Explorer interpolates it across the
range of values in the file, green at the minimum, yellow at the midpoint
and red at the maximum. The colour is relative to the range in that one
overlay, so a node's colour says nothing about absolute cost and cannot be
compared between two overlays or two runs.

The file is Model Explorer's node-data format: a top-level key per graph id
(`main` for a single-subgraph model) holding a `name` shown in the overlay
selector (the counter name), a `results` map from node key to
`{"value": <number>}`, and the `gradient` list. It is plain JSON, so
`jq '.main.results'` reads the per-node values when the graph view is not
needed; [Parsing outputs](https://ambiqai.github.io/helia-profiler/guide/parsing-outputs/)
covers the CSV and summary that carry the same numbers with more context.

## Steps

1. Open [Model Explorer](https://google-ai-edge.github.io/model-explorer/).
2. Load the `.tflite` model the run profiled (the same file; the overlay
   matches nodes by operator index).
3. Choose **Add Overlay** and pick one of the `me_overlay_*.json` files.
4. Read the colours: red is the highest value of that counter, green the
   lowest. Switch overlays to compare, for instance cycles against
   `ARM_PMU_L1D_CACHE_MISS_RD` to see whether a hot layer is memory-bound.
5. Check the picture against the table: the reddest node of the cycles
   overlay is the first row of `summary.top_layers`, and its `pct` says how
   much of the instrumented total it holds. High cycle cost with many cache misses is a reason to investigate
   [memory placement](https://ambiqai.github.io/helia-profiler/guide/memory/). Low cache misses alone do not prove a
   layer is compute-bound; compare stalls, instruction counts and the
   other available counters before attributing the cost.

A layer that ran in several PMU passes has one value per counter, taken
from the pass that captured that counter; a counter the SoC could not
capture has no overlay file rather than a file of zeros.

Nodes are matched by the original TFLite operator index, the same
`source_index` that joins MACs on
[Output files](https://ambiqai.github.io/helia-profiler/guide/output/#2-profile_resultscsv). heliaRT and TFLM run
operators in graph order, so their overlays use the sequential operator
index (0, 1, 2, ...). heliaAOT skips operators such as `VAR_HANDLE`
without renumbering, so its overlays use the original index from the AOT
operator manifest, or from the label suffix (the `3` in `CONV_2D:3`) when
the run has no manifest. A layer whose original index cannot be resolved
(a position the AOT manifest does not name, or any run whose manifest
extraction failed) is left out of the overlay rather than painted onto an
unrelated node. ExecuTorch layers name plan instructions, not graph nodes,
so an ExecuTorch run writes no overlay files. Each run replaces the
`me_overlay_*.json` files in `model_explorer/`.

## Disabling

```bash
hpx profile model.tflite --no-model-explorer
```

```yaml
output:
  model_explorer: false
```

The `model_explorer/` directory is then absent and the manifest lists no
overlay export; nothing else in the bundle changes.

## Expected output

A graph whose hottest operators match `top_layers` in `summary.json` for
the cycles overlay, and whose colour pattern shifts by counter.

## What next

[PMU counters](https://ambiqai.github.io/helia-profiler/guide/pmu-counters/) for what each counter measures;
[Memory placement](https://ambiqai.github.io/helia-profiler/guide/memory/) when the cache-miss overlay points at
weights or activations in a slow tier.
