Repository navigation
[CUDA] Commit and enforce phase-aware GQA dispatch policies - #33316
Chi Lo (chilo-ms) wants to merge 17 commits into
Conversation
There was a problem hiding this comment.
π‘ Changes recommended
The memory policy leaves CUDA plugin GQA kernels with permanently empty route masks, causing every run to fail.
1 open finding
What changed in this PR
Adds phase-aware CUDA GQA dispatch policies tied to workspace accounting and runtime enforcement.
Changes:
- Resolves
auto,latency,memory, andsafeinto phase-specific backend masks. - Enforces committed masks at runtime and validates GQA KV envelopes.
- Expands policy, phase, accounting, and Level-2 commitment tests.
| File | Description |
|---|---|
group_query_attention_workspace_header_test.cc |
Adds phase and ABI assertions. |
group_query_attention_workspace_estimate_test.cc |
Tests policy resolution and accounting. |
resource_accountant_test.cc |
Tests INT32 envelope validation. |
cuda_execution_provider.cc |
Passes policy into L1 estimation. |
resource_accountant.cc |
Centralizes envelope parsing. |
group_query_attention.h |
Stores committed phase masks. |
group_query_attention.cc |
Enforces masks during dispatch. |
group_query_attention_workspace_estimate.h |
Documents resolved policy semantics. |
group_query_attention_workspace_estimate.cc |
Builds phase-aware bounds. |
group_query_attention_workspace_bounds.h |
Defines phases and committed masks. |
group_query_attention_workspace_bounds.cc |
Resolves policies and aggregates phase bounds. |
onnxruntime_session_options_config_keys.h |
Documents policy and envelope behavior. |
resource_accountant.h |
Exposes the validated envelope parser. |
kernel_dispatch_policy.h |
Adds policy-name formatting. |
π§ Review effort: Balanced
π‘ Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Ti-Tai Wang (titaiwangms)
left a comment
There was a problem hiding this comment.
Reviewed f148b46dc8c60bbd6d3008b6c99975a5cde3e4da -> 3526b5a8329c2ae8b763bb0acaeaea51bc4f6c7c with the full five-role team. Requesting changes for two implementation defects and one important regression-test gap; inline comments provide triggering conditions and minimal corrections.
| ID | Severity | Raised by | Finding | Disposition |
|---|---|---|---|---|
| F1 | Major | Critical, Integration | Host-only parser dependency crosses the ordinary CUDA shared-provider boundary | Confirmed by source/link/bridge inspection; no executed link/load repro |
| F2 | Major | Code | Added tests do not execute production runtime policy gates/fallback/no-route behavior | Confirmed missing-test finding, not a claimed route escape |
| F5 | Major | Deep | Existence-based head reachability becomes an invalid sole-route Memory commitment | Confirmed by pinned integer recipes and runtime predicates; no GPU execution |
The F5 head512/envelope64 example is an availability regression (no permitted route despite supported alternatives), not a demonstrated OOM. The declared envelope is still caller-trusted and is not enforced as a runtime input limit.
Minority/disposition notes: Integration's F1 Critical rating is normalized to Major because this is a blocking unmerged build/load regression, not a demonstrated production incident. Readability's proposed Major for unknown policy tokens is rejected as a correctness blocker: fallback to Auto is the explicit parser contract; a typo warning would be a non-blocking improvement. Readability's generic-diagnostics Major is downgraded to Minor; please preserve the missing envelope/shape/oracle reason where practical. Integration retracted the proposed stack-tip merge-conflict/new-regression finding after confirming the bad test access was inherited and normal merging retains the parent fix.
Non-blocking open questions: Critical/Integration ask whether normal/plugin Safe initialization prerequisites intentionally differ when proof is unavailable, and whether a supported ORT_MINIMAL_BUILD configuration can retain GQA while excluding L2 without constructor rejection. Deep/Integration request clarification of L1-to-L2 selection consistency when shape bounds and candidate feasibility change; no additional counterexample beyond F5 was established. Deep also leaves Unfused's BNSH feasibility capture and an inherited head512 XQA recipe question unverified, neither used as a new blocker. CUDA decline/CPU fallback semantics need intent clarification, not universal CPU policy enforcement. Readability's custom-accountant policy drift was not established on the normal factory path; the Latency no-accountant fail-closed question was resolved by the final non-Auto error guard.
Other non-blocking improvements: document constructor/L2/Run mask lifecycle and relaxed-atomic assumptions; distinguish feasible, committed and sized backend sets; explain per-phase aggregation and Auto versus Latency. Failed-XQA-scratch/fallback overlap was not established: the inspected rejection precedes scratch allocation, and cuDNN returns instead of falling through.
Validation/exclusions: no local build, provider-load repro, Run tests, sanitizer, benchmark, concurrency stress or physical-memory/OOM measurement. There is no qualifying exact-head CUDA CI evidence for this child; #33016's framework/plugin results do not validate these new runtime paths. Readability's root coverage was partial; this is not an exhaustive whole-graph accounting or refreshed-stack review. Threat-model coverage concerns availability/resource admission and provider boundaries; no new privilege or information-disclosure issue was established.
β¦ estimator (reader-only) Adds the hardware-neutral session option session.attention_dispatch_policy and threads its value through to the CUDA GroupQueryAttention Level-1 workspace estimator. This is the Tier-1 intent knob from the policy-based workspace estimation design: "latency" favors high-workspace fast routes, "memory" favors low-workspace routes (so more nodes fit on GPU), and "safe" assumes the bounded fallback everywhere. Unset (default) or any unrecognized value means "auto" and keeps the current route-aware behavior. This is a pure no-functional-change reader. The raw string is parsed (WorkspaceEstimatorConfig::attention_dispatch_policy -> AttentionDispatchPolicy enum via ParseAttentionDispatchPolicy) and stored on GQAWorkspaceEstimateConfig::dispatch_policy, but the estimator does not yet consume it, so every policy value produces the identical estimate. A follow-up PR biases route selection on the committed policy (coverage validation and the bounded fallback land in their own PRs). Plumbing mirrors the ep.cuda.gqa_workspace_max_total_sequence_length reader. The enum/parser live in the CUDA GQA estimator header because it is the only consumer today; hoist to a neutral header when a second op consumes it. Tests: extends the FactoryRetainsNarrowWorkspaceEstimatorConfig framework test (config string -> WorkspaceEstimatorConfig field, CPU CI) and adds a provider-test asserting the token parsing (exact-match, unknown -> Auto) and the reader-only invariant (no policy value changes the estimate). Part of the policy-based workspace estimation effort; see docs/annotated_partitioning/policy_based_workspace_estimation.md and the PR chain (#32944, #32945, #33001, #33014, #33016). Base retargets toward main as the stack merges. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
Rename the unreleased option to session.kernel_dispatch_policy. Move the shared enum and parser into a CUDA-independent framework header and retain GQA as the first reader-only consumer. Move token tests into the framework suite and preserve estimator behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
f148b46 to
9f1c163
Compare
Default the optional reader policy explicitly to std::nullopt so partial WorkspaceEstimatorConfig aggregate initializers do not trigger -Wmissing-field-initializers under GCC and Clang. Add a regression for the omitted-policy initialization pattern while preserving reader-only behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
Resolve latency, memory, and safe intents to analytically accounted route masks shared by Level 1, Level 2, and runtime dispatch. Runtime fallback is restricted to the committed mask and non-auto policies fail closed when no permitted route is available. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
Resolve and enforce separate prefill, decode, and chunked-prefill route masks while budgeting the maximum across admitted phases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
Reject memory dispatch during kernel initialization when the Level-2 commitment hook is unavailable, including CUDA plugin builds. Preserve other policies, cover plugin initialization and unrelated kernels, and document the restriction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
Keep envelope validation provider-safe with a shared raw-value parser and local configuration retrieval. Distinguish route reachability from full-domain eligibility and retain a proven covering fallback before committing a policy. Add CUDA Run coverage for every phase, non-aliasing decode fallback, Safe's cuDNN exclusion, no-route errors, and Auto without resource accounting. Reject memory policy in ORT-minimal builds that skip Level-2 commitment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
3526b5a to
769ac8f
Compare
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Strong implementation of phase-aware GQA dispatch policy commitment and runtime enforcement, including the separation of existential reachable_backends from full-domain covering_backends and the header-only ParseCudaGqaWorkspaceMaxTotalSequenceLength validator. Left three inline comments on decode_fallbacks unioning in Memory policy decode selection, ORT_QUICK_BUILD / BFloat16 handling in BuildBounds's coverage loop, and Safe policy initialization consistency across normal vs. plugin/minimal builds.
Reject unknown non-empty session.kernel_dispatch_policy values with INVALID_ARGUMENT before creating accountants, including when partitioning is disabled. Keep empty and auto defaults, retain validated raw tokens, and enforce the CUDA consumer invariant. Forward policy through the GQA config helper and cover parser rejection, factory validation, and node-adapter defaults/forwarding. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24b20465-fd4d-4a64-8174-aa0622c5164d
Keep provider-safe GQA envelope parsing and phase-aware policy enforcement while accepting the reader's strict parser and centralized config construction. Update the GQA runtime and node-adapter regression to the strict parser and enforcing consumer contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24b20465-fd4d-4a64-8174-aa0622c5164d
Keep Memory decode fallbacks independent of prefill selections. Prove Flash coverage with exact graph head metadata and the matching FP16/BF16 predicate, including quick builds. Retain Safe route restrictions when no workspace envelope can be estimated. Add scalar, node-adapter, Level-2, and CUDA Run regressions, and align plugin initialization expectations with strict policy validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24b20465-fd4d-4a64-8174-aa0622c5164d
Ti-Tai Wang (titaiwangms)
left a comment
There was a problem hiding this comment.
Re-reviewed the actual stacked delta ce93b4849f438c1e45061e317e1bc376cf70c38b -> 8c746850cea0130b98c66d563992ca0118d1db2a with the full five-role team. No new substantiated implementation blocker was established in the bounded review. The previous findings are addressed in the inspected source, but I am leaving a COMMENT rather than approval because the exact-head CUDA build/Run evidence remains outstanding. This PR still targets the #33042 reader branch, not main, and is currently draft.
Prior-finding dispositions:
- Shared-provider parser dependency: addressed by the raw-string/scalar header helper. Host/provider retrieve config locally; the normal CUDA constructor no longer calls the native host ConfigOptions overload. No new framework linkage/bridge is used.
- Existential Flash eligibility used as sole-route coverage: addressed by separating reachable from covering backends, retaining a proven phase-local fallback, and using executable-graph static-head provenance and the correct FP16/BF16 predicates. The previous unknown-head-bound-512 counterexample now retains Flash|Unfused with the 213,248-byte bound; exact static geometry is checked directly rather than inferred from a smaller eligible head.
- Missing production enforcement tests: coverage added. Tests now call InferenceSession::Run and check CUDA assignment, phase/mask/selected-route diagnostics, independent output-cache alias rejection, output or intentional no-route failure, and Auto/Safe controls.
- Decode fallback and initialization: decode commits its own selected.backends, not prefill selections. Safe may retain route restrictions without a proven workspace bound; capacity-aware placement still requires proof. Memory rejects unavailable commitment, including the inspected plugin/minimal cases.
Validation limitation: this exact head has only seven lint/docs/policy checks, with no qualifying CUDA build or test result. QA verified that the requested selectors exist, but none of the six available local binaries has proven reviewed-head provenance. No stale binary was executed as evidence and no full rebuild was started. The needed production batch is:
GTEST_FILTER='GroupQueryAttentionDispatchPolicyTest.*:GroupQueryAttentionWorkspaceEstimateTest.KernelCommits*' \
GTEST_COLOR=no timeout 300s \
./onnxruntime_provider_test --gtest_filter=CUDA_EP_Unittest.AllThis requires an exact-head nonminimal/non-plugin CUDA internal-test build; Flash/MEA/cuDNN controls require their corresponding build/device support. Please retain actual OK versus SKIPPED versus compile-excluded distinctions. Source assertions do not establish numerical output, actual backend dispatch, or link/load success.
Non-blocking questions/follow-ups: consider nonuniform inputs and returned-cache assertions in a follow-up numerical/cache-sensitive case; clarify Auto versus Latency and the constructor/L2/Run mask lifecycle/commitment side effect; document reachable/covering/committed/permitted terminology. The explicit-empty numeric-envelope versus empty-policy difference is inherited contract behavior, not a new blocker. Cross-build initialization and token-validation behavior still need relevant execution coverage.
No Critical/Major finding was overruled for this PR in the new round. The Critical lane covered availability/resource boundaries and opt-in diagnostic metadata, not a broader exploit audit. Excluded: local build/Run/sanitizer, measured VRAM/OOM, numerical/performance/concurrency certification and exhaustive transitive consumers. Level-2 is still verification/commitment, not an automatic repartition loop; the caller-declared envelope remains an estimation input rather than runtime admission enforcement or a whole-session no-OOM guarantee. This comment records source-level closure of the previous issues, not runtime clearance or dismissal of the previous review.
### Description <!-- Describe your changes. --> Add reader-only plumbing for the hardware-neutral session option `session.kernel_dispatch_policy`. The intent is generic across operators and EPs. `KernelDispatchPolicy` and the shared, header-only `TryParseKernelDispatchPolicy` live in `core/framework/kernel_dispatch_policy.h`, with no CUDA or graph dependencies. CUDA GQA is the first consumer, not the owner of the policy. For valid values, **no policy changes runtime dispatch, workspace estimates, or partitioning** in this PR. `latency`, `memory`, and `safe` remain intent metadata for future policy resolution. In particular, `memory` does not reduce the reservation, and `safe` does not select a bounded fallback or provide a no-OOM guarantee. #### Reader contract - Unset, empty, and explicit `auto` resolve to `Auto`. The other valid tokens are exactly `latency`, `memory`, and `safe`. - Unknown, differently cased, whitespace-only, and whitespace-padded non-empty values fail session initialization with `INVALID_ARGUMENT`; they never silently resolve to `Auto`. Validation runs even when partitioning is disabled. - The accountant factory retains the validated raw optional string without changing other settings. The CUDA consumer enforces successful parsing rather than silently accepting an invalid configuration. - `GetGroupQueryAttentionWorkspaceEstimateConfig` accepts `dispatch_policy = KernelDispatchPolicy::Auto` alongside the envelope and initializes both fields in one place. The node-estimator overload and CUDA test bridge forward the policy through that helper. - Setting the policy alone does not enable partitioning or non-windowed GQA estimation without a KV envelope. - This replaces the earlier, unreleased attention-specific option name; there is no compatibility alias. #### Integration and regression coverage Preserve #33014/#33016's envelope validation against `[0, INT32_MAX]`, invalid-value diagnostics, and fail-closed GQA placement when no proven estimate is available. Reuse the exported graph-config helper instead of duplicating node parsing. Keep envelopes, eligibility, and sizing local to GQA; other operators and EPs can adopt the shared intent independently. Framework regressions cover valid-token parsing, rejected tokens (including `Memory`, `SAFE`, `memroy`, and ` memory `), unchanged parser output on failure, validation with partitioning enabled and disabled, raw-token retention, unset defaults, and policy-only configuration not enabling partitioning. Existing KV-envelope boundary tests remain intact. CUDA metadata regressions cover default and explicit policy forwarding through the node-config helper/test bridge, identical bytes/backend sets for windowed and non-windowed estimation, and unchanged decline without a non-windowed envelope. #### Validation for this review update - Changed-file lintrunner/clang-format check: passed for all 10 edited C++ files. - `git diff --check`: passed. - No full ORT build or C++ regression suites were run locally for this update, as requested. Earlier-head build evidence does not validate this head; full framework/CUDA validation is left to CI. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> Provide a generic policy representation and reader without coupling other consumers to GQA or CUDA. Rejecting typos now prevents future enforcement (including #33316's committed policies) from silently falling back to `Auto` and bypassing the requested restrictions. This PR builds on #33016, which is now merged, and targets `main`. Committed policies, operator/EP-specific resolution, route restrictions, runtime coverage/envelope enforcement, bounded fallback, and reduced policy-bound estimates remain separate follow-ups. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Chi Lo <lochi@microsoft.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9 Copilot-Session: 24b20465-fd4d-4a64-8174-aa0622c5164d
Preserve strict policy validation and profile-missing Level-1 accounting from main while retaining phase-local route commitments and runtime regressions. Explain missing non-windowed Memory envelopes and document initialization-only mask publication and workspace aggregation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
|
Ready for re-review at 8fc52ed. Merged current main after #33042 landed and resolved the conflicts while preserving strict token validation, main's missing-profile Level-1 accounting, and all seven inline-comment fixes/regressions. Also documented initialization-before-Run / relaxed-atomic mask assumptions and max-of-phase workspace aggregation, and added a focused initialization regression for the explicit missing non-windowed Memory-envelope diagnostic. Repository lintrunner passed on the final 15-file C++ delta, as did policy-delta whitespace and source-invariant checks. No local builds or C++/GPU test execution were performed, per request; CUDA/quick-build execution still requires new-head CI. The four original threads remain open for reviewer confirmation; their existing fix explanations are retained. The three later threads were already resolved by the reviewer. |
Use logging supplied by the CUDA provider bridge instead of including native host logging types. Pass a typed output-name array to the session Run string-span overload in the production dispatch-policy tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b95559c4-5cbe-4787-8dd7-ffa45a2157f9
|
CI fixes pushed in e1ec319.
Passed: |
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Thanks for addressing the three findings from the previous round (Memory decode fallback independence, static_head_size / BFloat16 Flash coverage under ORT_QUICK_BUILD, and Safe policy retention without a workspace bound).
In the current CUDA CI runs (Test Linux CUDA x64 Release, Windows GPU CUDA CI Pipeline Test Job, Test Linux TensorRT x64 Release), 5 unit tests in CUDA_EP_Unittest.All are failing:
GroupQueryAttentionWorkspaceEstimateTest.H512EstimatorDominatesCompleteRuntimeWorkspace(line 542),GroupQueryAttentionWorkspaceEstimateTest.GetCapabilityBudgetUsesLevel1Estimate(line 730), andGroupQueryAttentionWorkspaceEstimateTest.KernelDeclaresPrepackedHeadSinkRoot(line 1686):- See inline comment on
AggregateCommittedPhasesingroup_query_attention_workspace_bounds.cc:476: whenhead_sinkis present (has_sink == true, excludingUnfused/MEA) and FlashAttention is either disabled (kMath) or does not cover the head size (head = 512, orhead = 64in CI'sORT_QUICK_BUILD=ONwhere Flash only compileshead = 128),bounds.reachable_backendsis{GQAReachableBackend::Xqa}(decode-only), socommitted_backends.prefillisNoneandAggregateCommittedPhasesfails withUnavailable.
- See inline comment on
GroupQueryAttentionWorkspaceEstimateTest.SingleTokenShapeDoesNotAdmitChunkedPrefill(line 1001):- See inline comment on
group_query_attention_workspace_estimate_test.cc:1000:Config()defaults toconfig.enable_xqa = true, socommitted_backends.decodeunderSafeisGQAReachableBackend::Xqa | GQAReachableBackend::Unfused(0x11) rather thanGQAReachableBackend::Unfused(0x10).
- See inline comment on
GroupQueryAttentionWorkspaceBoundsTest.AggregatesExclusiveRoutesWithMax(group_query_attention_workspace_estimate_test.cc:1376):- Because
GetGQAWorkspaceAggregateForPermittedPhase(group_query_attention_workspace_bounds.cc:282) now sizesGQAExecutionPhase::Decodewithsequence_length = 1instead ofbounds.sequence_length_bound(4),unfused_only.total_workspace_bytesatS = 1(37,120bytes) is now smaller thanxqa_only.total_workspace_bytes(140,030bytes for 108 SMs), failingASSERT_GT(unfused_only.total_workspace_bytes, xqa_only.total_workspace_bytes). Increasingxqa.present_kv_cache_capacity_bound(e.g., to2048) orxqa.batch_size_boundin that test will makeunfused_onlyexceedxqa_onlyatS = 1.
- Because
Keep all-admitted-phase accounting fail-closed. Size H512 sink scratch with explicit decode-only bounds, and use quick-build-compatible head128 Flash geometry for the Level-1 budget and Level-2 prepacking fixtures while retaining observable XQA conversion savings. Disable XQA in the Unfused-only single-token case, increase KV capacity for the decode route-maximum comparison, and cover rejection of decode-only routes when prefill is still admitted. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24b20465-fd4d-4a64-8174-aa0622c5164d
|
Review-fixture corrections pushed in f0d95174ac, addressing all five failures in the latest review without changing production estimator behavior. The two inline threads document the H512 decode-only bounds, quick-build-compatible head128 sink fixtures, and explicit XQA disablement in the single-token case. The remaining review-summary failure, Validation: $env:PATH="$PWD\.venv\Scripts;$env:PATH"
$files = @(git diff 314ff8d4e87816bafa1b8e0fefa476c896c4dedd --name-only --diff-filter=ACMR -- include onnxruntime | Where-Object { $_ -match '\.(cc|h)$' } | ForEach-Object { $_.Replace('/', '\') })
& .\.venv\Scripts\lintrunner.exe @filesResult: passed, all 15 C++ files,
Static integer-formula checks: passed for the corrected decode inequality and for observable XQA prepack savings / the generous discovery budget over 1-1024 SMs. These checks do not execute production C++ or CUDA. Not run, per request: local ORT/CUDA builds or C++/GPU tests. The exact new-head CUDA/TensorRT CI results still need to confirm the reported failures are cleared. The four older review threads remain open for reviewer confirmation. |
Retain both the GQA raw-envelope parser regression and the MatMulNBits chunk-policy default regression at their conflicting insertion point. Preserve current main accounting and normalization updates alongside the committed GQA policies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 24b20465-fd4d-4a64-8174-aa0622c5164d
|
Resolved the conflict by merging current Kept both additions in Formatting for all 15 PR C++ files, staged/unstaged PR whitespace checks, and targeted source merge checks passed. No local build or C++/GPU test execution was performed, per request; new-head CI still needs to confirm the merge. |
Retain the envelope PR integration regressions while stacking on the shared policy and Level-2 plumbing in #33316. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6d876416-81ec-4982-a9b0-38b8b28b5e4a
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Re-reviewed ea7f7524fa: all five GroupQueryAttentionWorkspace* unit test failures from the previous round are cleanly resolved in f0d95174ac while keeping admitted-phase workspace accounting fail-closed, and CUDA CI is green.
Preserve phase-permitted dispatch masks alongside padded-query cuDNN eligibility and explicit-position RoPE fast-decode safeguards. Retain the new DynamicSparseAttention session options and regression coverage from both parents. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 6d876416-81ec-4982-a9b0-38b8b28b5e4a
75ef2db
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Reviewed the current PR against its current base: no new actionable findings. Rechecked the five prior tianleiwu threads and author replies; all are addressed and already resolved. Current-head Linux CUDA logs show 56 relevant GQA tests passing and the plugin initialization regression passing; rebuilt graph-free helpers passed 4,109 UBSan assertions. Documentation drift, WebAssembly-proxy ArrayBuffer failures, and the canceled React Native job do not establish an introduced CUDA-policy defect. No full local ORT build or production CUDA inference was run.
β¦ations (#33240) ### Description <!-- Describe your changes. --> Extend this PR from GQA envelope plumbing to the GQA, MatMulNBits, and shared-framework L1/L2 reconciliation follow-up for #32944. Stacked on #33316, reusing its shared GQA envelope and committed phase-policy implementation rather than duplicating that work. - Preserve the original non-windowed GQA cross-level and strict-initialization regressions, disable CPU fallback in those integration tests, and distinguish a successful zero-workspace estimate from an unavailable estimate. - Declare the constructed MatMulNBits legacy dequantization or fpA-intB route using the existing shared sizing/chunking helpers. Cover smaller unchunked inputs below the fpA size gate, unknown M with a launch cap, and graph-proven zero versus an unproven zero-shaped hint. Keep the legacy override available when fpA is compiled out. - In strict mode, reject nonzero reservations without an available kernel declaration. A replacement must provide its own declaration against its transferred budget; reuse the existing transfer/removal callbacks instead of introducing another reservation ledger. Preserve default-mode dynamic allocation and diagnostics. - Document the empty-list/unavailable versus nonempty-zero declaration contract and add focused framework/kernel regressions. **Out of scope:** planned backing allocation, session-wide lifetime planning, hard session-budget enforcement, automatic placement, and plugin C-ABI forwarding. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> A partition-time reservation is a budget, not proof that the final kernel fits it. Strict reconciliation must not silently accept an unavailable declaration, including after replacement/fusion. MatMulNBits must also reconcile the actual selected route and the entire hinted chunking envelope, not only its maximum-M endpoint. **Validation** Fresh Windows Release builds completed for the CPU framework target and the in-tree CUDA provider/internal-test target. Commands below ran from their respective build output directories. CPU framework/accounting/envelope selection: **42 passed, exit 0**. ```powershell .\onnxruntime_test_all.exe '--gtest_filter=SessionStateTest.*Workspace*:OpKernelTest.DefaultDeclareWorkspaceRequirementsClearsOutput:ResourceAccountantTest.*:RealAccountantTest.*:CudaGqaWorkspaceEnvelopeTest.*' ``` CUDA selection: **47 inner tests passed, no skips; outer runner passed, exit 0**. Includes all new kernel regressions plus the existing MatMulNBits end-to-end and chunking regressions. ```powershell $env:GTEST_FILTER='MatMulNBitsWorkspace.*:GroupQueryAttentionWorkspaceEstimateTest.DeclaresOneAlignedSlotAndOnlyWorkspaceAtLevel1:GroupQueryAttentionWorkspaceEstimateTest.KernelDeclarationMatchesBoundedNonWindowedLevel1:GroupQueryAttentionWorkspaceEstimateTest.StrictVerificationAcceptsBoundedNonWindowedAgreement' .\onnxruntime_provider_test.exe '--gtest_filter=CUDA_EP_Unittest.All' ``` Additional native CUDA MatMulNBits source compilation with `USE_FPA_INTB_GEMM=0`, into an independent object/PDB without reusing the fpA-on PCH: **passed**. This is a compile check, not a full fpA-off runtime build. ```text lintrunner -r origin/chilo/gqa-committed-policy --take CLANGFORMAT --output oneline git diff --check origin/chilo/gqa-committed-policy ``` Both checks **passed**. **Local validation limits/workarounds** - CUDA coverage is CUDA 12.8 / T1000 SM75, compact fpA, in-tree EP; Flash/MEA/TRT-fused attention are off. No SM80+ backend coverage is claimed. - Windows heap checking was disabled with `onnxruntime_ENABLE_MEMLEAK_CHECKER=OFF`. With checking enabled, all 42 assertions passed but shutdown exited unsuccessfully; running only the unchanged `ResourceAccountantTest.AccountForAllNodes_CorrectlyUsesPreStoredCosts` also passed its assertions and failed the shutdown check. The leak cause remains unresolved. - Local CUDA compilation used `-allow-unsupported-compiler`, `_CL_=/wd4310 /wd4702`, and `NVCC_APPEND_FLAGS=--ptxas-options=-w` for warnings in unmodified CUTLASS/Abseil and SM75 FP8 code. GoogleTest's Abseil integration was disabled through a build-only CMake project hook after the host/module copies aborted on duplicate Windows `SymInitialize` (error 87). These workarounds are not repository changes. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Chi Lo <lochi@microsoft.com> Copilot-Session: 7fa98d07-aec3-41b7-92b8-b0ec317a95bf Copilot-Session: 6d876416-81ec-4982-a9b0-38b8b28b5e4a
Preserve explicit-query fast-path exclusions and masked-value workspace accounting alongside phase-aware dispatch masks. Retain the decode-only H512 fixture and exercise masked-value bounds under all dispatch policies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 599afb40-ee9c-4798-b9a2-f240f998fc67
Tianlei Wu (tianleiwu)
left a comment
There was a problem hiding this comment.
Reviewed all 22 changed files at ae324eae42bf305c45a2a32601ac6ca1590fbda5. Requesting changes for one newly identified numerical-correctness issue: Memory can commit MEA for a learned head_sink, replacing its value with zero-logit smoothing. The inline comment gives a concrete admitted geometry and correction.
The five previously owned threads are addressed and already resolved; no duplicate thread actions are needed. Exact-head CI is SUCCESS, including native Linux/Windows CUDA and plugin test jobs, but the added production cases do not cover nonzero sinks with MEA enabled. No local build or CUDA execution was performed; this finding follows from the pinned dispatch, workspace, and softmax implementations.
| #endif | ||
| } | ||
| if (flash_covers) covering = covering | GQAReachableBackend::Flash; | ||
| if (mea_covers) covering = covering | GQAReachableBackend::MemoryEfficient; |
There was a problem hiding this comment.
[P1] MEA is not a mathematically covering route for an explicit head_sink. IsGQAMemoryEfficientEligible only uses has_sink in the H512 preference; it does not reject the tensor. EfficientAttention never forwards data.head_sink and only enables zero-logit smooth softmax.
For Flash+MEA enabled, FP16 SM80/108 SMs, B1/S4/Hq=Hkv8/head128/cache64/envelope64, separate Q/K/V, no bias/rotary/QK norm, and head_sink=1, Memory ranks MEA (131,084 bytes) below Flash (131,456 bytes) and commits it for prefill. Auto executes Flash. With Q=K=0 and V=1, the final row should be 4/(4+exp(1)) β 0.5954; Memory instead computes 4/5 = 0.8.
Please exclude sink-bearing MEA candidates and enforce that eligibility guard at dispatch, or implement actual per-head sink support. Add a nonzero-sink Memory-versus-Auto Run() regression with both backends enabled. This is a source-derived counterexample, not a local GPU execution result.

Description
Resolve
session.kernel_dispatch_policyfor CUDA GroupQueryAttention into runtime-enforced route masks for prefill, decode, and chunked prefill.autopreserves existing phase-applicable dispatch behavior.latencypreserves the existing per-phase priority: XQA -> cuDNN -> Flash/fast-decode -> MEA -> unfused.memoryindependently selects the minimum-workspace covering route set for each phase, including a phase-local covering fallback when needed. Decode does not inherit higher-workspace prefill selections.saferestricts dispatch to routes with analytical workspace recipes and excludes cuDNN. It remains usable without a declared shape/envelope workspace bound; this route restriction is not itself a workspace-bound commitment.Every runtime dispatch branch checks the current phase's permitted mask. A non-auto policy returns an explicit phase-specific error when no permitted route can serve the run, rather than escaping to an unaccounted route.
Accounting and eligibility
ORT_QUICK_BUILDrestrictions.memoryrequires successful Level-2 commitment and is rejected at GQA initialization in CUDA-plugin, CUDA-minimal, and ORT-minimal configurations where that commitment cannot run.saferetains its constructor-installed route restrictions if estimation is unavailable; capacity-aware placement still requires a proven estimate.auto/latencypreserve its dispatch behavior, while strict capacity-aware accounting declines an estimate when it is reachable.Regression coverage
Added scalar, node-adapter, Level-2, plugin-initialization, and production
InferenceSession::Run()regressions for phase-local decode selection, exact-static head-128 Flash coverage across FP16/BF16 and quantized/nonquantized caches, quick-build versus unknown-head behavior, and Safe with missing envelopes or dynamic sequence shapes. Runtime cases assert CUDA assignment, permitted masks, selected routes, numerical output, and explicit no-permitted-route failures. Safe/cuDNN cases include an Auto control and explicit unsupported-device/build/version skips. A focused initialization regression also verifies that non-windowed Memory without an envelope identifies the required session option explicitly.Latest review fixture corrections
The five reported CI failures are addressed without weakening all-admitted-phase accounting. H512 rotary/sink sizing now uses explicit decode-only bounds, and a separate regression preserves estimate rejection when prefill has no route under Auto, Latency, Memory, or Safe. The Level-1 budget and Level-2 prepacking fixtures use static head128 with Flash enabled for general phases (including quick builds) and a window64 that keeps XQA conversion savings observable. The single-token Unfused-only fixture disables XQA explicitly. The exclusive-route maximum fixture uses KV2048 so its Unfused decode workspace exceeds XQA's at query length one.
Latest revision: repository lintrunner and whitespace checks passed on the complete 15-file C++ PR delta. Static integer-formula checks also confirmed the corrected workspace inequalities and prepacking sensitivity; these are not C++/CUDA execution results. No local builds or C++/GPU test execution were performed, per request; new-head CI must confirm the corrections.
Validation
Latest base merge
ea7f7524fa: lintrunner on all 15 PR C++ files andgit diff --check origin/main -- include onnxruntime/git diff --cached --check origin/main -- include onnxruntimepassed. Source checks confirm both conflicting test bodies are unchanged, all framework regressions from both parents are retained (accounting for the PR's existing Reader-to-Value test rename), and the prior GQA fixture corrections remain unchanged. Main's MatMulNBits/packed-attention placement block, strict dispatch-policy parsing, and chunk forwarding are preserved. No local build or C++/GPU test execution was performed; the merged head requires CI.Passed on the refreshed 15-file C++ PR delta, using the existing isolated environment and CI-pinned clang-format 20.1.8 / lintrunner 0.13.1:
Result: passed,
ok No lint issues.git diff --check origin/main -- include onnxruntime- passed.git diff --cached --check origin/main -- include onnxruntimebefore the merge commit - passed.Not run, per request: local ORT/CUDA builds or C++/GPU test execution. Compilation and CUDA/quick-build regression execution require new-head CI confirmation; lint/source checks are not substitutes for those results.
Stack and scope
#33042 has merged. This PR targets main directly and includes main at
6188bc0900, integrated inea7f7524fa. The merge preserves strict dispatch-policy validation and GQA policy enforcement alongside main's MatMulNBits/packed-attention Level-1 accounting and separate Q/K normalization epsilon updates. Both tests at the conflicting framework-test insertion point are retained. The Level-2 GQA envelope plumbing from #33240 is included. The coordinated design is documented in #32944.GQA only; other kernels are unchanged.
latencyis an ordered heuristic, not a calibrated timing model. Shape/KV envelopes remain estimation declarations rather than runtime-enforced input limits. Whole-graph lifetime accounting and allocator/runtime reserves remain separate work; this does not provide a whole-session no-OOM guarantee.Motivation and Context
Make the selected phase-aware policy enforceable at runtime without admitting an unaccounted fallback. Address review findings that could inflate decode workspace through prefill-route inheritance, reject statically supported Flash-only nodes under quick builds, or inconsistently require a workspace envelope for Safe in ordinary versus plugin/minimal builds.