Engine adapters
Show the seam that keeps the pipeline engine-agnostic. Everything an
engine contributes to a run passes through one prepare() call and one
typed artifact object; the rest of hpx reads those and never imports an
engine package.
Diagram
Section titled “Diagram”- Registryengines/__init__.py
- EngineType
- adapter factories
- get_adapter
- Adapters
- tflm
- helia_rt
- helia_aot
- executorch
- Shared helpers
- cmsis_nn
- ethos_u
- Artifactsengines/base.py
- EngineArtifacts
- TflmArtifacts
- HeliaRtArtifacts
- HeliaAotArtifacts
- ExecutorchArtifacts
- Consumers
- firmware render
- memory planning
- workspace fingerprint
- model analysis
Text description of the diagram
- Registry (
engines/__init__.py):EngineType, adapter factories,get_adapter - Adapters:
tflm,helia_rt,helia_aot,executorch - Shared helpers:
cmsis_nn,ethos_u - Artifacts (
engines/base.py):EngineArtifacts,TflmArtifacts,HeliaRtArtifacts,HeliaAotArtifacts,ExecutorchArtifacts - Consumers: firmware render, memory planning, workspace fingerprint, model analysis
The blocks
Section titled “The blocks”Registry
Section titled “Registry”EngineType is a StrEnum with four members, tflm, helia-rt,
helia-aot and executorch, so YAML and Jinja compare against the hyphen
form without unwrapping. _ADAPTER_FACTORIES maps each member to a
deferred import, so registering an engine does not import its package
until get_adapter(engine_type) asks for it.
The adapter protocol
Section titled “The adapter protocol”EngineAdapter in engines/base.py has a name, an engine_type, and
prepare(config, work_dir) returning that engine’s artifact subtype. Two
hooks let an engine shape memory placement:
apply_arena_placement_override() for engines that emit typed arena
regions, and check_psram_placement() together with
psram_weights_source, which is how the PSRAM preflight on
Memory placement is enforced per engine.
What each adapter’s prepare() does
Section titled “What each adapter’s prepare() does”| Engine | Module | Steps | Modules it adds |
|---|---|---|---|
| tflm | engines/tflm.py |
resolves the nsx-tflite-micro module and the reference or CMSIS-NN backend |
nsx-tflite-micro (plus the CMSIS-NN provider for that backend) |
| helia-rt | engines/helia_rt/ |
validates the variant and toolchain; with no override returns the pinned registry module; source_path installs a local tree as a module; dist_path or a release source verifies the matching core and toolchain archive and generates a wrapper (nsx_module.py, artifacts.py, download.py) |
nsx-helia-rt |
| helia-aot | engines/helia_aot/ |
maps the board to a compiler platform and runs the helia-aot compiler (compile.py); extracts the operator manifest and memory plan from the compiler’s context (manifest.py); vendors the generated model as a local module named by engine.config.module_name (default hpx_model); resolves the CMSIS-NN provider |
nsx-cmsis-nn, the model module |
| executorch | engines/executorch.py |
resolves the nsx-executorch checkout at the commit the compatibility baseline pins (auto-cloned into the hpx cache, or engine.config.source_path); reads the optional <model>.pte.json sidecar for the provider, op lists, planned arena and I/O sizes; resolves the region of each static RAM buffer; generates a wrapper module and emits the provider module before it |
the CMSIS-NN provider, the nsx-executorch wrapper |
The shared helpers sit beside the adapters: engines/cmsis_nn.py resolves
the nsx-cmsis-nn module reference and its CMake variables for every
engine that links it, and engines/ethos_u.py holds the NSX module
identity of the Ethos-U backend. Support for each engine and backend per
SoC is a registry question, answered on Engines and
Boards and targets, not here.
Artifacts
Section titled “Artifacts”EngineArtifacts carries only what every engine produces: engine_type,
engine_header (no default; each adapter states its own), extra_modules,
cmake_vars and memory_plan. Engine-specific fields live on the subclass, so reading
another engine’s field is an AttributeError at the access site rather
than a silent None; each subclass pins its engine_type and raises
ValueError if constructed with another. Four resolved_* properties
(backend, version, variant, toolchain_tag) are how the dependency
workspace fingerprint records engine identity without knowing which engine
it holds. tests/contracts/test_engine_artifact_types.py asserts the
adapter-to-artifact map is complete over EngineType.
Consumers
Section titled “Consumers”| Consumer | Reads | Module |
|---|---|---|
| firmware render | engine_header, cmake_vars, extra_modules, the subtype’s fields (AOT operator manifest and arena regions, ExecuTorch buffer sizes) |
firmware/context.py, firmware/project.py |
| memory planning | memory_plan, the adapter’s placement hooks |
stages/plan_memory.py, placement.py |
| workspace fingerprint | the resolved_* properties |
deps/dependencies.py |
| model analysis | the engine’s view of the graph for hpx analyze --engine |
evaluation/engine_analysis.py |
How the engine shapes the firmware
Section titled “How the engine shapes the firmware”| Engine | Main template | Module graph on top of the board’s starter profile |
|---|---|---|
| tflm | main.cc.j2 |
nsx-tflite-micro, with the CMSIS-NN provider first for that backend |
| helia-rt | main.cc.j2 |
nsx-helia-rt |
| helia-aot | main_aot.cc.j2 |
nsx-cmsis-nn, then the generated model module |
| executorch | main_executorch.cc.j2 |
the CMSIS-NN provider, then nsx-executorch |
The provider is ordered before nsx-executorch on purpose: NSX must
configure exactly one CMSIS-NN provider before the runtime creates its
bridge target. The binary section sizes in summary.json record what the
engine choice cost in flash and RAM for the run at hand.
Where the code lives
Section titled “Where the code lives”| Block | Path under src/helia_profiler/ |
|---|---|
| registry | engines/__init__.py |
| protocol and artifacts | engines/base.py |
| adapters | engines/tflm.py, engines/helia_rt/, engines/helia_aot/, engines/executorch.py |
| shared helpers | engines/cmsis_nn.py, engines/ethos_u.py |
| stage | stages/prepare_engine.py |
| contract test | tests/contracts/test_engine_artifact_types.py |
What next
Section titled “What next”Firmware generation for what the render context does with the artifacts; Adding an engine for the touch points a fifth adapter has to cover.