Skip to content

[Feature] Introduce reusable PreparedCall with production TMR program-path integration #2270

Description

@ChaoWao

Summary

Introduce an immutable, reusable PreparedCall containing the resolved host-side result of a TMR invocation, and make the existing program execution path actually consume it.

This is the next bounded milestone after merged #2176, derived from the shared program/kernel execution design. Work from current main and selectively reuse existing implementations; existing PR numbering or dependency stacks do not dictate the design or merge order.

The deliverable is a production-used preparation result with demonstrable isolation and reuse. A types-only implementation or standalone codec with fake consumers does not complete this issue.

Motivation / Use Case

The target composition is:

program: device ownership + tensor bindings/transfers ─┐
                                                     ├→ prepare → PreparedCall → submit → Submission
kernel: caller-owned device arguments ────────────────┘

Kernel execution may own resident runtime metadata and internal workspaces while borrowing the device and tensor storage. Program mode adds device ownership and tensor parameter management around that common execution capability.

At the inspected main baseline fd5f2d93fc55c784a002049577b0015ebfa4194e:

  • Add: persistent kernel-context execution resources #2176 establishes cold-path resources. prepare_kernel_callable() registers the callable and establishes persistent arguments; it does not produce a per-invocation prepared result. Public kernel launch remains unsupported.
  • PreparedExecution combines a borrowed Runtime*, configuration, launch fields, native run identity, pipeline slot, and retirement state. ActiveExecution takes ownership of that object rather than allowing the preparation result to be reused.
  • launch_run() still performs DFX arming and other host work; Runtime publication is synchronous and includes handshake state.

We need the explicit preparation result before introducing a common stream-ordered publication/reset/launch closure. Removing admission guards or enabling the launch stub first would preserve the coupling that the design is intended to remove.

Proposed API / Behavior

1. Three distinct lifetimes

Object Responsibility
PreparedCall Immutable resolved invocation description and references to everything needed to consume it; reusable across executions
Submission (or the existing per-run state adapted to this role) Identity, ordering/completion state, status, pipeline lease during migration, and references for one execution
WorkingSet Mutable device execution storage; remains under existing serial execution ownership in this milestone

One PreparedCall may be used by multiple submissions. Submission does not consume or mutate the PreparedCall. This milestone validates sequential reuse and does not promise simultaneous device execution or multiple queued launches.

PreparedCall is not an ACLGraph: TMR may still build its internal task graph on the device. Do not represent the preparation result as a log of host function calls.

2. Extract a real, owned preparation result

Start with the TMR path:

  • Snapshot normalized device tensor descriptors and scalar values, resolved launch shape/thread/affinity settings, callable/function-table identity, and the effective per-call execution configuration.
  • Give image/argument storage and callable/code/resource references explicit lifetimes. No borrowing from a temporary Runtime, input descriptor array, mutable caller configuration, or temporary host orchestration object.
  • Retain stable resource bindings under their existing owner and identity rules. Keep references alive while PreparedCall or an execution still uses them; an unsupported invalidation must be rejected explicitly rather than yielding a dangling reference.
  • Move native run identity, pipeline slot and completion/retirement flags out of the immutable result. Existing per-run machinery can carry them during migration; a new general-purpose framework is not required.
  • A new or failed preparation must not overwrite a prior PreparedCall. A bank/slot being selected for execution is not the identity of the prepared result.
  • Keep host-only diagnostics/export metadata separate from device execution data.

Descriptor/scalar snapshots do not snapshot device tensor contents. Preserve existing tensor data semantics and document borrowed-storage requirements where ownership cannot be retained automatically. Program tensor allocations/slices and copy-back leases must not be recycled while a prepared result or execution still references them.

For DFX, distinguish resolved host configuration/resource requirements from per-execution reset/arming effects. Carry the preparation data explicitly; the serial execution adapter may still apply effects at the existing safe point in this milestone. Do not claim all launch-time host work or capture requirements have been eliminated. Do not regress existing program DFX support to make the new path pass.

3. Connect the existing program path

Adapt the current TMR program preparation/execution path to create and consume PreparedCall, while preserving the current execution claim, serial dispatch and tensor transfer behavior.

A small internal seam is sufficient. No new public Python API, duplicate kernel-suffixed C API family, or generic runner hierarchy is required here. Compatibility adapters may keep existing entry points working during migration.

The result must be reusable through the production execution path, not just encode/decode unit tests. Submission-specific data and mutable execution storage must be rebuilt/reset independently of the retained prepared description.

4. Keep the interface compatible with the eventual HBG adapter

Review the representation against HBG's known needs: pristine image sections, relocation/bank-dependent bindings, definition/code references and tensor backing ownership. Keep runtime-specific payloads explicit; do not make a TMR packet layout the universal representation.

Implementing HBG pristine restoration or enabling HBG kernel execution is not required to close this issue.

Acceptance criteria

  • Prepare A, then B with different invocation values; A's stored descriptors, scalars and effective configuration remain unchanged.
  • Mutate/release the original host argument/configuration containers after preparation; the owned preparation result remains valid. Device tensor contents retain their documented external semantics.
  • Execute A → B → A through the production TMR program path with independent expected outputs. The second A uses the same PreparedCall without rebuilding its resolved host preparation result. Per-submission reset, IO and bookkeeping are allowed.
  • Reject an invalid or over-capacity B without damaging a previously valid A or its owned resources.
  • Each execution gets independent run/completion/retirement state; prepared-result reuse does not reuse an old status or consume the object.
  • Owner/lifetime tests cover temporary input containers, prepared-result lifetime, and program tensor backing through execution/copy-back; no dangling Runtime or function-table pointer is hidden behind the new type.
  • Preserve existing program outputs, IN/OUT/INOUT transfer semantics and supported DFX behavior. Run relevant program regression checks and report architecture/runtime coverage honestly.
  • Document the remaining launch-time host effects and the migration seam for the next submission-closure milestone. Keep kernel capability reporting honest while launch remains unsupported.

Scope boundary / stopping rule

Close this issue when the production-used immutable preparation result and the acceptance criteria above are demonstrated under current serial scheduling.

The following belong to later milestones and must not grow this PR:

  • Publication/handshake device ABI split, asynchronous publication banks, and the full shared reset/launch/completion closure.
  • Removing Orchestrator/lane admission restrictions or enabling arbitrary host run-ahead.
  • Full kernel launch enablement, ACLGraph capture/replay, multi-graph lifetime handling or graph parameter updates.
  • Complete resident DFX redesign, HBG replay restoration, or a general runner/resource-management refactor.
  • The unload/reset double-failure follow-up in [Bug] Program loader loses explicit cleanup path when unload and device reset both fail #2269.

Alternatives Considered

Candidate Reusable contribution Required adaptation / reason not to adopt wholesale
#2180 Invocation validation, normalization, independently owned snapshots and bounded decoding Its packet-to-AICPU transport is narrower than PreparedCall. It does not provide the complete resolved host result, publication or owner contract.
#2189 Shared ExecutionInputs and executor/scheduler consumption Reconcile context-fixed configuration and unsupported kernel DFX with the eventual per-call/resident split. Reuse useful consumers without importing the prerequisite stack.
#2187 AICore-first submission, two-sided completion and partial-enqueue failure handling Later closure work. Its PrepareTail wait and lack of the target publication-bank/Root protocol require redesign before capture integration.
#2028 Per-run completion events, status retirement and FIFO ownership Later queue work. Its two-run scope does not replace the full execution-domain migration.
#2193 Non-destructive capacity refusal Potential supporting fix after checking the current freeze predicate and rebasing; not a substitute for immutable preparation.

These are sources of implementation ideas, not merge approvals or prerequisites to merge unchanged. Rewriting the integration on current main is acceptable when it is smaller and clearer than preserving the old stacks.

Merely renaming PreparedExecution leaves its mixed lifetimes intact. Adding a second kernel-only executor duplicates scheduling and keeps program mode outside the design. Removing pipeline guards first exposes shared-state writes before their ordering is made safe.

Additional Context

Related: #2162 (runner lifecycle contracts), #1853 (queued execution), #2254 (launch-state publication). This issue establishes the preparation result before those execution/publication changes. In particular, it does not adopt an all-by-value launch payload as the final replay-update mechanism; capture freezes inline arguments, while the agreed design uses explicitly owned publication data for mutable replay bindings.

Inspected baseline and source anchors

Main after #2176: fd5f2d93fc55c784a002049577b0015ebfa4194e.

Design context: the agreed prepare/submit design and unified kernel-mode HTML. The operative contract is restated above so the issue does not depend on access to local design files. Existing primitive probes support the eventual queue/capture design; they do not establish that this production refactor has passed.

Subsequent milestones (context only)

  1. This issue: owned preparation result and production program consumption.
  2. Shared publication/reset/AICore+AICPU/completion closure, consumed by program and kernel; validate real TMR eager and fixed-binding replay.
  3. Bank lifetimes and per-submission completion, followed by coordinated Orchestrator/lane/execution-claim migration; prove third and later submissions can enqueue before predecessor completion.
  4. HBG restoration, complete DFX coverage, multi-graph use and updateable bindings.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions