Skip to content

Latest commit

 

History

895 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

heliaPROFILER

hpx profiles LiteRT (.tflite) and ExecuTorch (.pte) models on real Ambiq Apollo silicon. One command resolves an inference engine, builds temporary NSX firmware, flashes the target, captures measurements, and writes a portable result bundle.

Alpha. heliaPROFILER is pre-1.0. Breaking changes may land on minor versions until v1.0. Pin an exact version in production pipelines.

📖 Full docs: https://ambiqai.github.io/helia-profiler/

Why hpx

  • Per-layer PMU breakdowns — cycles, instructions, cache, and (on Cortex-M55 boards) MVE and memory counter groups, one row per layer.
  • Power & energy per inference — GPIO-gated Joulescope capture (JS110/JS220/JS320) uses a dedicated transport-free firmware image to isolate the inference window from setup/teardown and capture traffic.
  • Four engines, one per run — tflm (vanilla TFLM baseline), helia-rt (Ambiq's optimized TFLM interpreter), helia-aot (Ambiq's ahead-of-time model compiler), and executorch (Cortex-M ExecuTorch programs, on the arm or ns CMSIS-NN provider). Selected explicitly — never auto-detected.
  • Multiple toolchains — arm-none-eabi-gcc, armclang, and ATfE, so you can compare build/runtime trade-offs without changing your model.
  • Memory placement control — place the heliaRT tensor arena in TCM, SRAM, or PSRAM and weights in TCM, SRAM, MRAM, or PSRAM; heliaAOT exposes per-tensor placement through its engine configuration, and ExecuTorch places each of its five runtime buffers independently.
  • Four capture transports — lossless RTT by default, plus USB CDC, UART, and diagnostic SWO, with probe, port, and target-reset helpers for bring-up.
  • Host-only model analysis — inspect MACs, parameters, tensor sizes, and heliaAOT graph transforms without connecting hardware.
  • Run comparison and regression policy — compare two result bundles, inspect the largest layer deltas, and apply versioned metric thresholds.
  • Model Explorer overlays — export per-layer metrics as JSON overlays for Model Explorer.
  • Config-file driven — a frozen, immutable hpx.yml schema merges with CLI flags, with strict validation and did-you-mean suggestions for typos.
  • Multi-board — Apollo3, Apollo4, and Apollo5-family EVBs. Run hpx boards for the exact list your install supports.
  • Verifiable result bundles — summaries, per-layer data, provenance, validity/comparability issues, and a SHA-256 manifest designed for scripts as well as people.
  • Hardware-in-the-loop validation — hpx validate runs canonical MLPerf Tiny models end-to-end across engines, toolchains, transports, and memory placements, and emits a portable bundle two runs can be compared from.
  • Typed Python API — call profile() directly or use immutable, branchable Session workflows in notebooks and automation.

Install

See the Quick install for Nix, uv, and pip setup.

Quick taste

hpx doctor                                   # check toolchain + dependencies
hpx profile model.tflite                     # profile with defaults
hpx profile model.tflite --power             # add Joulescope power capture
hpx profile --config hpx.yml                 # reproducible, config-driven run
hpx analyze model.tflite                     # inspect the model without hardware
hpx compare results/baseline results/change  # compare two completed runs
hpx validate --suite smoke                   # prove the whole bench works

hpx profile defaults to heliaRT, GNU Arm, RTT, apollo510_evb, per-layer CPU counters, 100 measured iterations, and 5 warmups. Select a different engine, board, toolchain, transport, memory plan, PMU selection, or output directory explicitly on the command line or in YAML.

  Layer  Op                  ARM_PMU_CPU_CYCLES  ARM_PMU_INST_RETIRED
  0      CONV_2D                        123,456                98,765
  1      DEPTHWISE_CONV_2D               45,678                34,567
  ...
  Power:  1.234 mA avg   12.345 mW avg   x.xxx µJ / inference

(Illustrative sample only — see Getting Started for a real walkthrough.)

Development

uv sync --locked --all-groups --extra aot --extra analysis
uv run ruff check .
uv run ty check src/helia_profiler tests
uv run pytest -q

pytest deselects the hardware marker by default, so the whole unit suite runs with no board attached. Hardware cases run through hpx validate (or pytest -m hardware).

For software-only capture tests or standalone review probes, install the device guard before importing HPX:

uv run python tools/software_only.py pytest tests/test_power_drivers.py -q
uv run python tools/software_only.py python /path/to/probe.py

Standalone probes can import sibling helpers; the checkout src directory retains precedence over the probe directory.

The launcher blocks Joulescope, J-Link and USB driver imports and provides inert serial constructors and port discovery that raise until replaced with fakes. Callbacks copied after startup retain those inert operations even if a later monkeypatch changes the original module. Installation rejects already imported HPX/device modules. Selecting a pytest marker alone does not provide this guard.

Python children must use sys.executable and retain the launcher's bootstrap and checkout src prefix in PYTHONPATH, plus PYTHONSAFEPATH=1; a sitecustomize hook guards children and grandchildren before their scripts run. Stripped environments, startup flags that suppress the hook, shells, preexec_fn callbacks and external commands are rejected. Mock external tool calls in these tests. Tests importing vendor helpers such as pyjoulescope_driver.time64 also fail explicitly; this launcher is not a drop-in replacement for the whole suite.

This is an accidental-access guard for trusted Python tests, not an OS sandbox: trusted interpreter startup/site files are assumed, and direct native device I/O or deliberate removal of the guard is outside its boundary. Run hardware tests separately through the existing explicit hardware workflow with board ownership. The guard does not alter production capture behavior or claim hardware validation.

The launcher's own tests run fresh interpreters against inert vendor sentinels, including unguarded negative controls; run them outside the launcher:

uv run pytest --confcutdir=tools/tests tools/tests/test_software_only.py -q

Pre-commit hooks

One-time setup after cloning:

uv tool install pre-commit==4.6.0
pre-commit install

Nix contributors can run nix develop .#contrib to get pre-commit 4.6.0 alongside the HPX tools, then run pre-commit install once. The default nix develop environment is unchanged; entering either shell does not install hooks.

This installs both hook stages the repo uses: pre-commit (formatting, whitespace/YAML/JSON/TOML checks, ruff, and a gate requiring every TODO(...)/FIXME(...)/HACK(...) marker to carry a reference) and prepare-commit-msg (strips AI-tool attribution trailers from the commit message). pre-push is left untouched, so git-lfs's own pre-push hook keeps working. Secret scanning is server-side: GitHub secret scanning and push protection are enabled on the repository, so a pushed secret is rejected regardless of local hooks.

Run every hook against the whole tree with pre-commit run --all-files. CI runs the identical .pre-commit-config.yaml, so a clean local run means a clean CI run. Hook revisions are bumped deliberately via pre-commit autoupdate in its own reviewed PR, not ad hoc.

The docs site lives in astro-site/ (Astro and Starlight on @ambiqai/helia-ui); npm ci && npm run build there builds it, npm run dev serves it, and the check chain in .github/workflows/docs.yml is what CI runs. It deploys to GitHub Pages on a release and on docs-only pushes to main. See Documentation release checks for browser validation, manual publishing and post-deployment verification.

Repository workflows use the committed uv.lock for reproducibility. PyPI installations continue to resolve the compatible dependency ranges published in pyproject.toml.

Architectural rules, module responsibilities, and the repo workflows that should stay stable are documented in AGENTS.md — worth reading before a first change, whether you are a person or an agent.

License

Apache-2.0

Fixed-fixture PSRAM weights

The fixture API supports SRAM or DTCM working memory with PSRAM weights for heliaAOT and upstream LiteRT Micro on Apollo510 EVB. AOT uses externally bound arenas; Micro constructs its interpreter from the PSRAM flatbuffer. Both load complete weights once from MRAM staging before model initialization and timing. MRAM staging remains part of the firmware image. Internal state policy and input restoration are unchanged.

Pass the compiled build's psram_weights descriptor to FixtureCaptureRequest.psram_weights. The descriptor binds expected payloads and PSRAM clock to the exact image. Capture requires the bounded placement terminal and verifies ready/XIP status, active ranges and payload checksums. A linker map alone cannot establish runtime PSRAM placement. A build rendered without compilation has an unbound descriptor and cannot authorize capture. This additive interface is fixture API 3.5; it does not include a streaming or numerical qualification claim. Placement validation uses the canonical target bank extents and implemented backing paths rather than benchmark recipe pairs. Static working arenas currently use SRAM or DTCM; dynamic PSRAM working arenas, other fixture reset targets, and NOR/RRAM loader declarations are separate adapter gaps. External AOT fixture binding currently requires PSRAM weights. Operator timing binding compares the effective working and weight banks recorded in the build receipt; legacy receipts without those banks are refused. Ordinary profile operator timings cannot be bound to PSRAM fixture builds: their active payload, external arena layout and loader configuration are not recorded by that profile binding.

Releases

Packages

Used by

Contributors

Languages