Skip to content

Make workspace input shapes optional-aware - #32312

Merged
Ti-Tai Wang (titaiwangms) merged 7 commits into
mainfrom
titaiwangms/workspace-optional-input-shapes
Sep 4, 2026
Merged

Ti-Tai Wang (titaiwangms) merged 7 commits into
mainfrom
titaiwangms/workspace-optional-input-shapes

Conversation

@titaiwangms

@titaiwangms Ti-Tai Wang (titaiwangms) commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Why

DeclareWorkspaceRequirements() currently receives a dense span<const TensorShape>. That loses positional correspondence when an optional input is omitted and prevents Level 2 workspace estimation for valid signatures with an internal hole, for example:

  • PackedMultiHeadAttention: missing bias with later token_offset / cumulative_sequence_length
  • GroupQueryAttention: missing seqlens_k with later total_sequence_length
  • MatMulNBits: missing optional g_idx with later bias

The resolver also dropped partial shapes wholesale, conflating “input is missing”, “input is present but shape metadata is unavailable”, and “input is present with unknown dimensions”.

What changed

  • Add an owned, positional WorkspaceInputShape descriptor with three explicit states:
    • Missing
    • PresentWithShape
    • PresentWithoutShape
  • Preserve rank-0 tensors, zero extents, partial shapes (-1 per unknown dimension), and optional holes.
  • Deep-copy dimensions so descriptors remain valid after graph/shadow-graph teardown.
  • Replace the unreleased C++ virtual directly; no compatibility overload is retained.
  • Update MatMulNBits Level 2 to consume the new contract while preserving Level 1/Level 2/runtime workspace parity.
  • Preserve the adapter-side default no-op. Plugin C-ABI forwarding/invocation remains deferred.

MatMulNBits parity

The shared workspace formula now handles known-empty outputs before architecture-specific arithmetic:

  • ordinary case: Level 1 = Level 2 = runtime = 1792 bytes
  • empty output: Level 1 = 0, Level 2 emits no slot, runtime = 0
  • known-zero partial shapes such as [0, unknown, K] are recognized as empty
  • invalid negative dimensions and checked-arithmetic overflow remain unavailable/error paths

#32071 integration constraints

#32071 uses Level-2 declarations as synthetic negative allocation IDs in the existing activation MemoryPattern.
The first run for a compatible feed-shape key traces workspace allocation/free while the kernel still uses
GetScratchBuffer(). Later compatible runs can return an offset in the normal per-run pattern backing buffer;
an unavailable pattern or a request larger than the declared capacity falls back to GetScratchBuffer().
This is not persistent Initialize()-time allocation and does not protect the first run from OOM.

The current #32071 pilot preplans only kernels that explicitly opt in and declare exactly one slot.
The PA/PMHA follow-up uses that contract for both operators:

  • PackedAttention declares one 256-byte-aligned root containing projection and Attention regions.
  • PackedMultiHeadAttention declares one 256-byte-aligned Attention root.

The declarations alone do not opt either kernel into planning. The future integration must atomically add
SupportsPreallocatedWorkspace(), retrieve slot 0, and split PA's root at its declared aligned Attention offset.
Until then, PA retains its two dynamic allocations and PMHA retains its one dynamic allocation. Generic multi-slot
framework support remains available, but PA does not require a multi-slot planner extension.

Deferred Phase-B semantics

This PR intentionally does not add:

  • max-shape provenance to the descriptor
  • a distinct marker for “proven zero” versus “unavailable”
  • plugin C ABI forwarding
  • workspace offset planning/allocation
  • partition/resource-accounting policy

Those semantics belong to the planner/accounting integration, where runtime bound checks and fallback behavior can be defined coherently.

Compatibility with #32071

This PR should merge first. #32071 should then rebase and update its Level-2 caller to pass the same positional WorkspaceInputShape span while retaining its reservation verification and execution-plan registration.

Validation

  • CPU framework/session targeted tests: 29 passed
  • CUDA MatMulNBits workspace tests: 16 passed
  • same-session positive-M then zero-M runtime coverage
  • SM90 empty-output host regression
  • core and adapter header-isolation probes
  • C++ formatting and git diff --check

Design tracking: #29775

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Introduces optional-aware, positional workspace shape metadata for Level-2 estimation and updates CUDA MatMulNBits workspace handling.

Changes:

  • Adds three-state WorkspaceInputShape resolution while preserving optional-input holes.
  • Handles zero-sized MatMulNBits outputs consistently across estimation and runtime.
  • Expands framework/CUDA tests and updates design documentation.

No actionable issues identified.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.

Show a summary per file
File Description
include/onnxruntime/core/framework/workspace_input_shape.h Defines presence-aware shape metadata.
include/onnxruntime/core/framework/op_kernel.h Updates the Level-2 virtual contract.
include/onnxruntime/ep/adapter/op_kernel.h Mirrors the contract for plugin builds.
onnxruntime/core/framework/node_shape_resolver.h Preserves positional input metadata.
onnxruntime/core/framework/session_state.cc Passes resolved entries to kernels.
onnxruntime/contrib_ops/cuda/quantization/matmul_nbits.h Updates MatMulNBits declarations.
onnxruntime/contrib_ops/cuda/quantization/matmul_nbits.cc Handles partial and empty shapes.
onnxruntime/contrib_ops/cuda/quantization/matmul_nbits_workspace_estimate.h Exposes shared dimension-product logic.
onnxruntime/contrib_ops/cuda/llm/fpA_intB_gemm/fpA_intB_gemm.h Returns zero workspace for empty outputs.
onnxruntime/test/framework/max_shape_override_test.cc Tests all shape states and optional holes.
onnxruntime/test/framework/session_state_test.cc Tests the default declaration behavior.
onnxruntime/test/providers/cuda/test_cases/matmul_nbits_workspace_test.cc Tests formula edge cases.
onnxruntime/test/providers/cuda/test_cases/matmul_nbits_e2e_workspace_test.cc Tests positional and runtime parity.
docs/annotated_partitioning/future_directions_constrained_env.md Documents the revised contract and scope.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@titaiwangms
Ti-Tai Wang (titaiwangms) force-pushed the titaiwangms/workspace-optional-input-shapes branch from ac8b280 to 8f8ac3f Compare August 28, 2026 22:31
@titaiwangms

Copy link
Copy Markdown
Contributor Author

Chi Lo (@chilo-ms) Can you take a look and check if the PR understands #32071 correctly? We will need multi-slots support as Attention is much more complicated.

Copilot AI added 3 commits August 31, 2026 18:28
Preserve positional optional-input holes and partial shapes for Level-2 workspace declarations. Keep MatMulNBits Level-1, Level-2, and runtime sizing aligned for empty outputs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Document the current first-run tracing strategy, one-slot planner limit, and PackedAttention multi-slot requirement separately from future persistent preallocation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Keep the positional optional-input layout while omitting unsupported bias in compact builds so MatMulNBits workspace parity continues to exercise the CUTLASS GEMM path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Copilot AI added 3 commits September 1, 2026 22:40
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Require planned offsets to honor declared alignment and distinguish the current PA and PMHA dynamic allocation counts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The broad framework API and CUDA workspace changes require final human review.

Review details
  • Files reviewed: 15/15 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

@titaiwangms
Ti-Tai Wang (titaiwangms) merged commit f98e809 into main Sep 4, 2026
92 of 93 checks passed
@titaiwangms
Ti-Tai Wang (titaiwangms) deleted the titaiwangms/workspace-optional-input-shapes branch September 4, 2026 03:07
Ti-Tai Wang (titaiwangms) added a commit that referenced this pull request Sep 4, 2026
## Summary

Add MatMulNBits-equivalent operator-side workspace estimation for CUDA
`PackedAttention` and `PackedMultiHeadAttention`:

- Level 1 derives a conservative estimate from the node, resolved input
shapes,
  CUDA device properties, and the EP's resolved attention options.
- Level 2 declares the same estimate from positional
`WorkspaceInputShape`
  metadata and constructed kernel state.
- Existing graph-free runtime recipes remain the single source of truth
for
  workspace bytes and layouts.
- PackedAttention declares one 256-byte-aligned root in slot 0, with
internal
  projection and attention regions.
- PackedMultiHeadAttention declares one 256-byte-aligned attention root
in slot 0.

Level 1 is log-only, matching the current MatMulNBits pilot. This PR
does not
add #32071-specific planner APIs or change runtime `GetScratchBuffer()`
behavior.

## Route aggregation

Runtime routes are mutually exclusive, so the estimate uses:

```text
PackedAttention:
  align_up(projection_bytes, 256) + max(feasible TRT, MEA, unfused recipes)

PackedMultiHeadAttention:
  max(feasible Flash, TRT, MEA, unfused recipes)
```

Route reachability is evaluated conservatively for every runtime shape
up to
the supplied maximum geometry. This is necessary because Flash/MEA
thresholds
and attention-bias alignment gates are not monotonic when moving from a
maximum
shape to a smaller runtime shape. Unfused fallback is always retained,
and a
failure to size any included route makes the estimate unavailable rather
than
silently underestimating.

## Shape and zero semantics

- Missing mandatory inputs, shapeless required inputs, unknown
dimensions,
malformed geometry, and checked-arithmetic overflow produce no estimate.
- `WorkspaceInputShape` does not carry max-shape provenance, so
zero-shaped
  framework hints are conservatively treated as unavailable.
- Exact zero behavior remains supported by the graph-free runtime
recipes.
- At the current Level-2 boundary, both unavailable and zero are
represented by
  an empty requirements list.

## Planner integration

- Both operators fit #32071's current one-slot pilot. Generic framework
  multi-slot support remains unchanged.
- A declaration alone is not planner opt-in.
`SupportsPreallocatedWorkspace()`,
slot-0 retrieval, and PA root slicing must land atomically in the
planner
  integration.
- Until then, PA retains its two dynamic allocations and PMHA retains
its one
  dynamic allocation.

## Build boundaries

The framework adapters and kernel overrides are excluded from:

- CUDA minimal builds
- `DISABLE_CONTRIB_OPS` builds
- CUDA plugin EP builds

The graph-free workspace recipes remain available to the shared BERT
attention
infrastructure where required.

## Validation

- 18/18 PA/PMHA workspace estimator tests
  - includes direct production-kernel Level-2 declaration tests
  - route-threshold, max-not-sum, aligned-root padding/no-padding,
    optional-hole, zero, overflow, and malformed geometry coverage
- 23/23 existing packed-attention workspace recipe tests
- 20/20 existing hand-calculated runtime parity cases
- 26/26 PackedAttention/PackedMultiHeadAttention runtime operator tests
- CUDA provider-test build
- 145 CUDA internal tests executed: 143 passed, 2 unrelated
LeanAttention skips
- `DISABLE_CONTRIB_OPS` and CUDA-minimal compile-guard probes
- C++ formatting and diff checks

## Dependency

This is a stacked follow-up to #32312. The base should change to `main`
after
#32312 merges.

Tracking: #29775

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
This was referenced Sep 12, 2026
Chi Lo (chilo-ms) pushed a commit that referenced this pull request Sep 17, 2026
Add MatMulNBits-equivalent operator-side workspace estimation for CUDA
`PackedAttention` and `PackedMultiHeadAttention`:

- Level 1 derives a conservative estimate from the node, resolved input
shapes,
  CUDA device properties, and the EP's resolved attention options.
- Level 2 declares the same estimate from positional
`WorkspaceInputShape`
  metadata and constructed kernel state.
- Existing graph-free runtime recipes remain the single source of truth
for
  workspace bytes and layouts.
- PackedAttention declares one 256-byte-aligned root in slot 0, with
internal
  projection and attention regions.
- PackedMultiHeadAttention declares one 256-byte-aligned attention root
in slot 0.

Level 1 is log-only, matching the current MatMulNBits pilot. This PR
does not
add #32071-specific planner APIs or change runtime `GetScratchBuffer()`
behavior.

Runtime routes are mutually exclusive, so the estimate uses:

```text
PackedAttention:
  align_up(projection_bytes, 256) + max(feasible TRT, MEA, unfused recipes)

PackedMultiHeadAttention:
  max(feasible Flash, TRT, MEA, unfused recipes)
```

Route reachability is evaluated conservatively for every runtime shape
up to
the supplied maximum geometry. This is necessary because Flash/MEA
thresholds
and attention-bias alignment gates are not monotonic when moving from a
maximum
shape to a smaller runtime shape. Unfused fallback is always retained,
and a
failure to size any included route makes the estimate unavailable rather
than
silently underestimating.

- Missing mandatory inputs, shapeless required inputs, unknown
dimensions,
malformed geometry, and checked-arithmetic overflow produce no estimate.
- `WorkspaceInputShape` does not carry max-shape provenance, so
zero-shaped
  framework hints are conservatively treated as unavailable.
- Exact zero behavior remains supported by the graph-free runtime
recipes.
- At the current Level-2 boundary, both unavailable and zero are
represented by
  an empty requirements list.

- Both operators fit #32071's current one-slot pilot. Generic framework
  multi-slot support remains unchanged.
- A declaration alone is not planner opt-in.
`SupportsPreallocatedWorkspace()`,
slot-0 retrieval, and PA root slicing must land atomically in the
planner
  integration.
- Until then, PA retains its two dynamic allocations and PMHA retains
its one
  dynamic allocation.

The framework adapters and kernel overrides are excluded from:

- CUDA minimal builds
- `DISABLE_CONTRIB_OPS` builds
- CUDA plugin EP builds

The graph-free workspace recipes remain available to the shared BERT
attention
infrastructure where required.

- 18/18 PA/PMHA workspace estimator tests
  - includes direct production-kernel Level-2 declaration tests
  - route-threshold, max-not-sum, aligned-root padding/no-padding,
    optional-hole, zero, overflow, and malformed geometry coverage
- 23/23 existing packed-attention workspace recipe tests
- 20/20 existing hand-calculated runtime parity cases
- 26/26 PackedAttention/PackedMultiHeadAttention runtime operator tests
- CUDA provider-test build
- 145 CUDA internal tests executed: 143 passed, 2 unrelated
LeanAttention skips
- `DISABLE_CONTRIB_OPS` and CUDA-minimal compile-guard probes
- C++ formatting and diff checks

This is a stacked follow-up to #32312. The base should change to `main`
after

Tracking: #29775

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Copilot-Session: c04148cc-7ace-4cf4-b981-0ddc92334e78
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants