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.
Choose the subsystem you need
Section titled “Choose the subsystem you need”Stage order, immutable configuration and the results each stage produces.
How one selected engine turns a model into firmware artifacts.
Templates, NSX modules and the build that runs on the target.
Target readiness, transports and parsing the measurement stream.
Collect and inspect a redacted support bundle for a failing environment.
The adapter, configuration, firmware and validation touch points.
The blocks
Section titled “The blocks”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 |
Two objects flow through everything
Section titled “Two objects flow through everything”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.
Two programmatic flows
Section titled “Two programmatic flows”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.
Errors are typed
Section titled “Errors are typed”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.
Where the code lives
Section titled “Where the code lives”| 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/ |
What next
Section titled “What next”- Pipeline: the eighteen stages in order, what each sets and when it is skipped.
- Engine adapters: how one
EngineTypebecomes 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 --bundlecollects, redacts and archives. - Adding an engine: the touch points a fifth engine has to cover.