Skip to content

Results#

The typed data returned by profile(). Core measurement records are frozen against field reassignment, while run metadata is enriched as the pipeline executes. Dynamic nested collections such as counters, engine extensions, power samples, and metadata remain mutable for compatibility and efficient capture assembly. Treat collections on returned results as read-only.

ProfileResult dataclass #

ProfileResult(pmu: PmuResult, power: PowerResult | None = None, power_observation: PowerObservation | None = None, power_terminal: PowerTerminalRecord | None = None, on_device_power: OnDevicePowerSummary | None = None, metadata: RunMetadata = RunMetadata(), report_paths: list[Path] = list())

Complete profiling result — the public return type of hpx.profile().

This is the one object a programmatic user needs. It carries everything: PMU data, optional power data, run metadata, and report file paths.

layers property #

layers: list[LayerResult]

Merged per-layer results across all PMU presets.

total_cycles property #

total_cycles: float

Total CPU cycles across all layers.

PmuResult dataclass #

PmuResult(meta: FirmwareMeta, presets: dict[str, PresetResult] = dict(), layers: list[LayerResult] = list(), overflow_detected: bool = False, groups: dict[str, list[LayerResult]] = dict())

Complete PMU profiling result across all presets.

PresetResult dataclass #

PresetResult(name: str, header: list[str] = list(), iterations: list[list[LayerResult]] = list(), layers: list[LayerResult] = list())

Results for a single PMU counter preset (e.g. basic_cpu).

LayerResult dataclass #

LayerResult(id: int | str, op: str, counters: dict[str, float] = dict(), cycles: float | None = None, overflow: bool = False)

Profiling result for a single model layer (averaged across iterations).

FirmwareMeta dataclass #

FirmwareMeta(model_size: int | None = None, arena_size: int | None = None, allocated_arena: int | None = None, input_size: int | None = None, output_size: int | None = None, num_tensors: int | None = None, num_inputs: int | None = None, num_outputs: int | None = None, num_presets: int | None = None, system_clock_hz: int | None = None, profiled_infer_count: int | None = None, profiled_infer_total_us: int | None = None, profiled_infer_avg_us: int | None = None, clean_infer_count: int | None = None, clean_infer_total_cycles: int | None = None, clean_infer_avg_cycles: int | None = None, clean_infer_avg_us: int | None = None, clean_stalled_iters: int | None = None, clean_partial_iters: int | None = None, clean_ref_cycles: int | None = None, clean_dwt_rate_cyc: int | None = None, clean_dwt_rate_us: int | None = None, clean_attach_wait_us: int | None = None, psram: PsramInfo | None = None, presets: tuple[str, ...] = ())

Metadata reported by the profiler firmware at startup.

All fields are optional because older firmware versions may not report every field.

RunMetadata dataclass #

RunMetadata(hpx_version: str = '', run_id: str = '', timestamp: str = '', config_snapshot: dict[str, Any] = dict(), platform: PlatformInfo | None = None, model: ModelInfo | None = None, toolchain: ToolchainInfo | None = None, engine: EngineInfo | None = None, firmware: FirmwareMeta | None = None, memory_plan: 'MemoryPlan | None' = None, timing: TimingInfo | None = None, compatibility: CompatibilityResolution | None = None, dependencies: 'DependencyProvenance | None' = None)

Accumulated run metadata — enriched by stages, consumed by reports.

NsxModuleRef dataclass #

NsxModuleRef(name: str, path: Path, version: str = '', local: bool = True, project: str = '', ref: str = '')

Reference to an NSX module needed by the profiler firmware build.

A module is resolved one of two ways:

  • Registry (local=False) — NSX clones the module from its registered upstream (GitHub). project is the registry project name and ref optionally pins a tag/branch. path is unused.
  • Local (local=True) — hpx vendors the module on disk. path is the source directory to copy into the app, and project (when set) selects the registry-derived install location so NSX's registry-aware lock can find it.

PowerResult dataclass #

PowerResult(summary: PowerSummary, samples: list[PowerSample] = list(), gated_windows: list[GatedPowerWindow] = list(), per_layer: dict[str, Any] | None = None, metadata: PowerMetadata = PowerMetadata())

Complete result of a power capture.

metadata is the typed :class:~helia_profiler.power.metadata.PowerMetadata (#154 Phase 2 breaking change — previously dict[str, Any]; the flat dict view is metadata.to_metadata_dict()). The result is frozen but its metadata is deliberately mutable: pipeline stages enrich it after capture, like RunMetadata.

Result bundles#

The result manifest is a small stable envelope around open provenance, comparability, and extension data. Loading preserves unknown fields so newer producers can evolve additively without older tools silently deleting data.

load_result_manifest #

load_result_manifest(path: str | Path, *, verify: bool = False) -> ResultManifest

Load a result manifest and optionally verify its sibling artifacts.

ResultManifest dataclass #

ResultManifest(schema: str, schema_version: int, run_id: str, timestamp: str, hpx_version: str, status: RunStatus, validity: ResultValidity, issues: tuple[ResultIssue, ...], provenance: dict[str, Any], comparability: dict[str, Any], artifacts: tuple[ResultArtifact, ...], bundle_type: str | None = None, extensions: dict[str, Any] = dict(), extra: dict[str, Any] = dict())

Stable result envelope with open provenance and extension payloads.

load classmethod #

load(path: str | Path) -> Self

Load a manifest while preserving unknown fields.

write #

write(path: str | Path) -> Path

Write the manifest without discarding unknown fields.

verify #

verify(bundle_dir: str | Path) -> None

Verify all declared artifact paths, sizes, and SHA-256 digests.

ResultArtifact dataclass #

ResultArtifact(path: str, media_type: str, size_bytes: int, sha256: str, role: str | None = None, name: str | None = None, schema: str | None = None, schema_version: int | None = None, producer: str | None = None, optional: bool | None = None, extra: dict[str, Any] = dict())

One content-addressed file in a result bundle.

ResultIssue dataclass #

ResultIssue(code: str, severity: str, message: str, context: dict[str, Any] = dict(), extra: dict[str, Any] = dict())

One stable machine-readable issue with optional open context.

RunStatus #

Bases: StrEnum

Publication status of a result bundle.

ResultValidity #

Bases: StrEnum

Whether measurements in a completed bundle are authoritative.

Dependency lock provenance#

read_dependency_lock_provenance() is a read-only provider for later diagnostics collectors. Pass a prepared profiler_app, its nsx.lock or hpx-dependencies.json, or the parent fingerprint workspace. It verifies the exact lock SHA-256 and returns a frozen typed surface; it does not resolve, synchronize, sanitize, or write files.

The stable join keys are baseline_fingerprint (CompatibilityBaseline.fingerprint) and lock_sha256.

read_dependency_lock_provenance #

read_dependency_lock_provenance(app_or_workspace_path: str | Path) -> DependencyLockProvenance

Read typed lock provenance without mutating an app or workspace.

app_or_workspace_path may name profiler_app, its nsx.lock or hpx-dependencies.json, or the parent fingerprint workspace containing profiler_app. The exact on-disk lock digest is verified against the recorded run state before a surface is returned.

DependencyLockProvenance dataclass #

DependencyLockProvenance(lock_path: Path, lock_sha256: str, registry_hash: str, requested_refs: tuple[DependencyRequest, ...], resolved: tuple[DependencyModule, ...], overrides: tuple[DependencyOverride, ...], qualification: QualificationState, baseline_fingerprint: str, workspace_fingerprint: str, lock_mode: DependencyLockMode, update_requested: bool)

Read-only lock provenance surface for later diagnostics collectors.

Field-diagnostics support bundle#

collect_support_bundle() is the diagnostics collector read_dependency_lock_provenance() was reserved for: it gathers doctor checks/versions, the compatibility baseline, the exact Stage 5 lock provenance (when workspace is given), a module inventory, an optional sanitized resolved config, and optional probe/port summaries — redacting absolute paths, credentialed URLs, tokens, and device serials by default (see helia_profiler.redact) — into one in-memory SupportBundleCollection. write_support_bundle() archives it deterministically (stable member order and byte content for identical inputs); verify_support_bundle() re-checks an archive's structure and per-member digests, rejecting unsafe or disallowed member paths. Every section is collected best-effort: a missing workspace, config, or optional tool marks just that section unavailable with a reason instead of failing the whole bundle.

SupportBundleOptions dataclass #

SupportBundleOptions(workspace: Path | None = None, config_path: Path | None = None, toolchain: Toolchain = ARM_NONE_EABI_GCC, transport: Transport = RTT, engine: EngineType = HELIA_RT, include_probes: bool = True, include_ports: bool = True, raw_probe_ids: bool = False)

What hpx doctor --bundle should collect.

Every section beyond the always-available doctor checks and compatibility baseline is optional and independently toggleable so a bundle can be built entirely offline with no attached hardware.

collect_support_bundle #

collect_support_bundle(options: SupportBundleOptions = SupportBundleOptions()) -> SupportBundleCollection

Gather every diagnostic section, redact it, and build the manifest.

Never raises for a missing optional dependency, tool, or workspace — every section catches its own typed failures and records a skip reason instead. Only truly unexpected internal errors propagate.

write_support_bundle #

write_support_bundle(collection: SupportBundleCollection, output: Path) -> Path

Write collection as a deterministic ZIP archive and return its path.

output names the exact archive file when it ends in .zip; otherwise it is treated as a directory (created if needed) and the filename is derived from :func:content_fingerprint plus the HPX version, so identical inputs always produce the same file name and the same member bytes for every entry except manifest.json (only its generated_at timestamp differs run to run).

Raises :class:~helia_profiler.errors.ReportError (not a raw :class:OSError) if the destination cannot be created or written to (permission denied, no space left, a path component that is itself a file, ...), so CLI callers only ever need to catch HpxError.

verify_support_bundle #

verify_support_bundle(path: Path) -> SupportBundleManifest

Verify a support-bundle archive's structure, contents, and digests.

Rejects absolute member paths (POSIX, and Windows drive-letter paths in either C:\... or C:/... form), ../empty path segments, backslashes, NUL bytes, duplicate entries, and any file extension other than .json/exactly nsx.lock — defense in depth against a malformed or hostile archive (zip-slip, disguised binary payloads) even though this module only ever writes archives matching that shape itself.

SupportBundleManifest dataclass #

SupportBundleManifest(schema: str, schema_version: int, hpx_version: str, generated_at: str, host: dict[str, Any], sections: tuple[SupportBundleSection, ...], redaction: dict[str, Any], artifacts: tuple[ResultArtifact, ...], extra: dict[str, Any] = dict())

Stable envelope describing one support-bundle archive's contents.

verify #

verify(bundle_dir: str | Path) -> None

Verify every declared artifact path, size, and SHA-256 digest.

Rejects absolute paths and any path that escapes bundle_dir so a hostile/corrupted manifest cannot be used to read or overwrite files outside the extracted bundle (zip-slip style attacks).

SupportBundleSection dataclass #

SupportBundleSection(name: str, available: bool, reason: str | None = None)

One diagnostic section the collector attempted.

available=False records why a section was skipped (missing workspace, offline, optional tool absent, ...) rather than failing the whole bundle — see docs/architecture/field-diagnostics.md.

Validity and comparability#

The same pure policy functions drive manifests, summary output, comparisons, and programmatic consumers. Invalid runs and model mismatches block run-level deltas. Topology differences suppress only per-layer deltas. Power scope, mode, firmware, or integrity differences suppress only power metrics, while intentional engine, toolchain, clock, board, transport, and placement changes remain informative comparison dimensions.

evaluate_run #

evaluate_run(ctx: PipelineContext) -> RunEvaluation

Evaluate captured results without mutating pipeline state.

RunEvaluation dataclass #

RunEvaluation(validity: ResultValidity, issues: tuple[ResultIssue, ...] = ())

Authoritative validity and structured issues for one completed run.

assess_comparability #

assess_comparability(baseline: RunArtifacts, candidate: RunArtifacts) -> ComparabilityAssessment

Compare identity, validity, topology, and intentional run dimensions.

ComparabilityAssessment dataclass #

ComparabilityAssessment(issues: tuple[ComparabilityIssue, ...] = ())

Whether run-level and per-layer deltas may be computed.

ComparabilityIssue dataclass #

ComparabilityIssue(code: str, severity: ComparabilitySeverity, message: str, context: dict[str, Any] = dict())

One machine-readable compatibility decision.

ComparabilitySeverity #

Bases: StrEnum

Effect of one comparability issue on comparison output.

Defined here so the comparability registry can bind severity to code without importing from evaluation; evaluation.comparability re-exports it, which remains the canonical public import path.

Regression profiles#

Versioned comparison profiles apply deterministic direction, unit, tolerance, missing-metric, and required-dimension policy to an existing CompareResult. They remain separate from the loose result-bundle schema.

ComparisonProfile dataclass #

ComparisonProfile(schema: str, schema_version: int, metrics: dict[str, MetricPolicy], missing: MissingMetricPolicy | None = None, required_dimensions: tuple[str, ...] = (), name: str | None = None, extra: dict[str, Any] = dict())

Open v1 profile selecting deterministic metric regression policies.

MetricPolicy dataclass #

MetricPolicy(direction: MetricDirection, unit: str, max_regression_pct: float | None = None, max_regression_abs: float | None = None, missing: MissingMetricPolicy | None = None, extra: dict[str, Any] = dict())

Tolerance and availability policy for one named comparison metric.

MetricDirection #

Bases: StrEnum

Preferred candidate direction for one metric.

MissingMetricPolicy #

Bases: StrEnum

Verdict when a selected metric is unavailable.

evaluate_comparison_profile #

evaluate_comparison_profile(result: CompareResult, profile: ComparisonProfile) -> ComparisonVerdict

Evaluate existing metric deltas against one versioned profile.

ComparisonVerdict dataclass #

ComparisonVerdict(status: VerdictStatus, metrics: tuple[MetricVerdict, ...], dimension_mismatches: tuple[str, ...] = (), profile_name: str | None = None, profile_schema: str = COMPARISON_PROFILE_SCHEMA, profile_schema_version: int = COMPARISON_PROFILE_SCHEMA_VERSION, profile_sha256: str = '')

Deterministic verdict for one result pair and profile.

MetricVerdict dataclass #

MetricVerdict(metric: str, status: VerdictStatus, message: str, baseline: float | None = None, candidate: float | None = None, regression: float | None = None, allowed_regression: float | None = None, unit: str = '')

Verdict and evidence for one selected metric.

VerdictStatus #

Bases: StrEnum

Regression policy outcome.