Skip to content
heliaPROFILER
User guide
HELIA

Concepts

This section is for contributors and for agents that change hpx rather than run it. It names the packages, says what each one owns and hands on, and points at the module behind every block, so a change can be placed before it is written. Users who only run hpx profile need the User guide, not this.

hpx is a profiler, not a build system, an SDK exporter or an application framework. It generates a disposable firmware app for one model and one engine, builds it with NSX, flashes it, captures what the firmware prints, and writes a result bundle. Four rules shape every package:

Rule What it means in code Where it is enforced
Immutable configuration ProfileConfig is resolved once from the CLI and YAML, then frozen; every stage reads the same object and none mutates it config/__init__.py (frozen pydantic models with extra="forbid")
One engine per run the engine is explicit; comparing engines means two runs and hpx compare engines/__init__.py (get_adapter takes one EngineType)
Typed stage boundaries domain handoffs use typed, frozen dataclasses owned by their subsystem, not bare dicts; fields can contain mappings such as LayerResult.counters. PipelineContext separately owns mutable orchestration state results/, engines/base.py (EngineArtifacts), fixtures/types.py (FixtureRenderSpec), pipeline.py
Subprocess isolation GCC, CMake, J-Link and the heliaAOT compiler run through subprocess.run() with argument lists, never a shell deps/nsx.py, target/probe/jlink.py, engines/helia_aot/compile.py

ProfileConfig is the read-only input. PipelineContext is the mutable state bag the stages fill: each stage sets the fields it owns and reads the fields earlier stages set, through narrowing accessors that raise PipelineError naming the producing stage when it has not run. The Pipeline page lists both.

The public profile API and CLI share one internal execution helper that maps this completed context into ProfileResult. Its optional evaluation is the same verdict stored by report generation; None means no evaluation was supplied. The CLI applies output.fail_on_invalid to that typed outcome after reports and presentation finish. Library callers receive invalid outcomes normally and choose their own policy.

hpx.profile and Session.profile run the whole pipeline once: build, flash, capture and write a result bundle. The run API splits that for fixed input bytes. Session.freeze resolves a plan into a FrozenRun; hpx.build compiles it for a TypedFixture into a CompiledBuild, saved as hpx.compiled-build and read back with load_build; run_build captures from it without rebuilding and returns a RunResult, saved as hpx.run-result and read with load_run or api.load_result. The hpx freeze, hpx build and hpx run commands drive the same flow. Its types are exported from the package root, which is the whole public Python contract; the runs/, fixtures/ and runtime/ packages behind it are internal.

The retained build reuses the profile path’s platform resolution, engine preparation, memory planning, firmware generation and build stages. It adds fixture binding and identity checks around them. Freeze, save/load and api.observations are host-only operations; build invokes host tools; run_build is the device boundary. Loading a saved result verifies retained evidence before observations map it into the portable result view.

For implementation owners, verification responsibilities and focused tests, see the contributor architecture map. The fixed-fixture maintainer guide has station setup, runtime preparation and evidence details.

HPX uses subclasses of HpxError with an optional hint that the CLI prints under the message. The subclass says which package failed:

Error Raised by Meaning
PipelineError pipeline.py a stage product was read before its stage ran
ConfigError config/ bad YAML, unknown key, missing field
PlatformError platform/ unknown board or SoC
EngineError engines/ adapter failure
FirmwareError firmware/ template rendering failure
BuildError deps/, firmware/build.py NSX configure or build failure; NetworkError and DependencyError (VersionError, LockError) narrow it
CaptureError capture/, transport/, target/probe/ transport, protocol or firmware-reported failure; DeterministicCaptureError narrows it for refusals a retry cannot change, such as a missing image or an unknown load address on the flash path
PowerError power/ driver failure
ReportError report/ output failure; ValidationBundleError narrows it for hpx validate bundles

The list is src/helia_profiler/errors.py; the CLI maps every HpxError to a non-zero exit and the codes in the run’s issues are a separate vocabulary, documented on the issue codes page.

Block Path under src/helia_profiler/
Entry points cli/, api.py, session.py
Run API runs/, fixtures/, and offline readers in readers/
Configuration config/, vocab.py, placement.py
Pipeline pipeline.py, profiler.py, stages/
Engines engines/
Firmware firmware/
Dependencies deps/
Platform platform/
Target target/
Transport transport/
Capture capture/
Power power/
Results results/, report/, evaluation/, modelcost/
Host and wire hostenv/, diagnostics/, validation/, wire/
  • Pipeline: the eighteen stages in order, what each sets and when it is skipped.
  • Engine adapters: how one EngineType becomes an adapter, its artifacts and a firmware template.
  • Firmware generation: the template skeleton, the NSX project files and the build.
  • Data capture: target lifecycle, transports, the wire stream and the parser.
  • Field diagnostics: what hpx doctor --bundle collects, redacts and archives.
  • Adding an engine: the touch points a fifth engine has to cover.