Skip to content

Sync with Microsoft ONNX Runtime - 15112026 - #1395

Open
ai-fw-intg wants to merge 140 commits into
ovep-developfrom
sync_msft_15112026
Open

ai-fw-intg wants to merge 140 commits into
ovep-developfrom
sync_msft_15112026

Conversation

@ai-fw-intg

Copy link
Copy Markdown

Automated daily backmerge from ORT main to ovep-develop. No conflicts detected. Do NOT squash or rebase - use merge commit only.

adrastogi and others added 30 commits November 4, 2026 13:02
### Description
<!-- Describe your changes. -->

Adds int8 data support to the WebGPU `Gather` kernel.

- `int8` is added to the `T` type constraint of every WebGPU Gather
registration (opsets 1-10, 11-12, 13+).
- int8 uses the packed-byte path that bool and uint8 already use (four
1-byte elements per `u32`). Gather only moves data, so int8 is copied as
raw bytes. `unpack4xU8` reads each byte, and the `Int8x4` `SetByOffset`
keeps each lane's low byte. The two's-complement bit pattern, and so the
sign, is preserved.
- bool, uint8 and int64 behavior is unchanged.

Tests in `onnxruntime/test/providers/webgpu/tensor/gather_op_test.cc`
run only on the WebGPU EP with `kOrtSessionOptionsDisableCPUEPFallback`
set, and skip if the EP is unavailable:
- `Gather_int8_axis0_webgpu` / `Gather_int8_axis1_webgpu`: values
include -128, -1, 0 and 127. They use int32 and int64 indices, negative
indices, 2-D indices, and output sizes that do and don't fill the last
packed word.
- `Gather_int8_scalar_indices_webgpu`: 0-D indices, giving 0-D and 1-D
outputs.
- `Gather_int8_all_opsets_webgpu`: opsets 7, 11 and 13, one for each
registration.
- `Gather_int8_all_byte_values_webgpu`: all 256 int8 values, with 257
outputs that span two workgroups and end on a partial word.
- `Gather_int8_then_cast_to_float_webgpu`: Gather(int8) -> Cast(float)
graphs with runtime and initializer tables, 2-D and 0-D indices, and two
Gathers on one table. This mirrors the WebNN conformance graphs and
catches an int8 table that is read as unsigned.

The existing all-EP CPU tests `Gather_axis1_indices2d_int8` and
`Gather_axis1_neg_indices2d_int8` now also run on the WebGPU kernel.

### 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. -->

The new WPT page
[`webnn/conformance_tests/gather-cast-int8-table.https.any.js`](https://wpt.live/webnn/conformance_tests/gather-cast-int8-table.https.any.js)
fails 6 required subtests on the WebGPU EP. Each failing graph reads an
int8 table with `gather` (constant or runtime table, followed by `cast`
to float32 and sometimes `mul`/`reshape`, 0-D indices, or two gathers on
one table). The WebGPU Gather kernel didn't register int8:

```
ep.cc:96 Ep::GetCapabilityImpl webgpu kernel not found in registries for Op type: Gather
This session contains graph nodes that are assigned to the default CPU EP, but fallback to CPU EP has been explicitly disabled
```

WebNN disables CPU fallback, so these graphs failed to build. The
cast-then-gather variants already passed.

This is one of several WebGPU EP fixes for WebNN conformance.

**Validation**

- Built locally with the WebGPU EP. This commit was merged with main
`121e34d92b` together with a separate Relu int32 change.
- `onnxruntime_provider_test
--gtest_filter="WebGpuActivationTest.*:ActivationOpTest.Relu*:GatherOpTest.*:CastOpTest.*:GatherElementsOpTest.*:GatherNDOpTest.*"`:
**passed**, 268/268, 0 skipped. This includes all six new
`Gather_int8_*_webgpu` tests and the existing `Gather_axis1_*_int8`
tests, which now run on WebGPU.
- Negative check: removing the
`type_constraints.push_back(DataTypeImpl::GetTensorType<int8_t>());`
line makes all six `Gather_int8_*` tests **fail** at session init with
`fallback to CPU EP has been explicitly disabled`. This is the same
error the WPT page hits.
- `lintrunner -a` and `clang-format --dry-run -Werror` (20.1.8) on the
changed files: clean.
- WPT in the browser. Setup: plugin EP built from main `121e34d92b`,
this PR and the Relu int32 PR (local merge `5c68bbb9f9`); Edge Canary
159.0.4372.0; RTX Spark N1X / D3D12; ORT runtime 1.28.3.
- `webnn/conformance_tests/gather-cast-int8-table.https.any.js?gpu`:
**PASS 9/9**. Before this change, 6 required subtests failed with
"Failed to build graph".
- `webnn/conformance_tests/gather.https.any.js?gpu`: still **PASS
39/39**.

Co-authored-by: Aditya Rastogi <adityar@ntdev.microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
### Description
<!-- Describe your changes. -->

Adds int32 support to the WebGPU EP `Relu` kernel for opset 14+.

- `onnxruntime/core/providers/webgpu/math/unary_elementwise_ops.cc`: the
`Relu` opset 14 kernel now uses the existing `SignedNumberTypes()`
helper (float, float16, int32) instead of `WebGpuSupportedFloatTypes()`.
Opsets 6-12 and 13 stay float-only because ONNX added the integer types
in Relu-14. The shader is unchanged: `select(x_value_t(0), a, a >
x_value_t(0))` is valid WGSL for `vec4<i32>`.
- `onnxruntime/test/providers/webgpu/activation/activation_op_test.cc`:
new `WebGpuActivationTest.Relu_Int32_Opset14_WebGpu`. It runs on the
WebGPU EP only with `kOrtSessionOptionsDisableCPUEPFallback=1`, so a
missing kernel fails the test instead of silently running on CPU (the
CPU EP does register int32 Relu-14). It covers `INT32_MIN`, `-1`, `0`,
`1` and `INT32_MAX` with shape `{7}` (partial trailing vec4) and `{1, 2,
2, 2}` (full vec4s). It skips before constructing `OpTester` when the
WebGPU EP is unavailable.

Out of scope: int8 and int64 Relu, which WGSL does not support natively.

#### Validation

Built with the WebGPU EP from a local, unpushed merge of this commit and
a separate WebGPU Gather commit into `main` (121e34d).

- `onnxruntime_provider_test
--gtest_filter="WebGpuActivationTest.*:ActivationOpTest.Relu*:GatherOpTest.*:CastOpTest.*:GatherElementsOpTest.*:GatherNDOpTest.*"`:
**passed**, 268/268 with 0 skipped. This includes
`WebGpuActivationTest.Relu_Int32_Opset14_WebGpu`.
- Negative check: with the Relu-14 registration reverted to
`WebGpuSupportedFloatTypes()`,
`WebGpuActivationTest.Relu_Int32_Opset14_WebGpu` **fails** at session
init with "fallback to CPU EP has been explicitly disabled". This
confirms the test catches a missing WebGPU kernel.
- `lintrunner -a` and clang-format 20.1.8 on the changed files: no
issues.
- WPT `webnn/conformance_tests/relu.https.any.js?gpu`: **16/18 passed**,
up from 15/18 before. "relu int32 4D tensor" now passes. The 2 remaining
failures are the optional int8 and int64 subtests, which are out of
scope. Tested with the WebGPU plugin EP built from `main` 121e34d
plus this PR and the Gather int8 PR (local merge `5c68bbb9f9`), Edge
Canary 159.0.4372.0, NVIDIA RTX Spark N1X on D3D12, and ORT runtime
1.28.3.

### 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. -->

The W3C WebNN WPT subtest `webnn/conformance_tests/relu.https.any.js`
"relu int32 4D tensor" failed on the WebGPU EP with "Failed to build
graph". WebNN disables CPU fallback, and WebGPU `Relu` had no int32
kernel, so the node was assigned to CPU and session creation failed.

Co-authored-by: Aditya Rastogi <adityar@ntdev.microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
### Description

This change fixes shape mismatch handling for cases where the requested
shape is effectively equivalent to the existing tensor shape at the
element level, but differs in rank representation.

In particular, it allows reuse when the tensor has a single element and
the shapes are represented as `{1}` and `{}`. This covers the
scalar/single-element case that was previously failing in WebNN
applications and test cases.

The implementation does **not** reuse buffers for arbitrary reshapes
just because the total number of elements matches. For example, shapes
like `{4,5}` and `{2,10}` are still treated as incompatible and are
correctly rejected.

### Example

- Allowed: `{1}` ↔ `{}`
- Rejected: `{4,5}` ↔ `{2,10}`

### Impact

This resolves failures in WebNN cases such as `softsign` with positive
float32 0D tensors.
### Description
This PR adds Python bindings for the Model Package APIs. Python
applications can now create, inspect and edit model packages, and select
a variant and create an inference session from one. It also exposes
set_ep_context_binary_information on ModelCompiler.

## Changes

- Add pybind bindings for model package authoring (ModelPackage) and for
loading and selecting a variant (ModelPackageContext,
ModelPackageOptions, ModelPackageComponentContext).
- Add ModelCompiler.set_ep_context_binary_information.
- Link model_package into the Python module and export the new classes
from onnxruntime.
- The bindings are not built in minimal builds.


### Motivation and Context
The python API's are helpful in creating sample applications for public
adoptions.
This pull request updates the GitHub Actions workflows to improve
security when handling pull requests from forks. The main change is to
ensure that jobs running on self-hosted runners with managed identities
only execute trusted code from the main repository, preventing untrusted
fork code from gaining elevated permissions.

Security improvements for workflow jobs:

* Updated the `build-linux-cuda-x64-release` and
`test-linux-cuda-x64-release` jobs in
`.github/workflows/linux_cuda_ci.yml` to only run on self-hosted runners
if the pull request comes from the main repository, and moved job-level
permissions under this condition.
[[1]](diffhunk://#diff-04806013a5e7991ba5606145885d9b0fcd99a7df1f3bb96a2d38fc724ccd9b2aL16-R26)
[[2]](diffhunk://#diff-04806013a5e7991ba5606145885d9b0fcd99a7df1f3bb96a2d38fc724ccd9b2aR61)
* Added a similar conditional check to the `build_test_pipeline` job in
`.github/workflows/reusable_linux_build.yml` to prevent fork-controlled
code from running on self-hosted runners with managed identities.
…#33846)

### Description
<!-- Describe your changes. -->

Replace the `build-and-prep-ort-files` action invocation in
`linux_minimal_build.yml` with explicit workflow steps for requirements
installation, operator-registration validation, inference-only Debug
wheel building and installation, followed by the local
`tools/ci_build/prepare_minimal_build_test_data.py` script. The Python
script does not install packages or modify the Python environment.

The local script preserves source/package conversion passes,
required-operator configs, standalone invoker ops, and custom-op
conversion/cleanup. The preparation build omits `--enable_training_ops`.
Install exactly one built wheel with `--force-reinstall --no-deps`,
preserving requirements pins and rejecting missing/ambiguous wheels.
Custom-op conversion failures are fatal and temporary models are cleaned
up; a missing custom-op library still produces a warning.

Remove the full-build preparation job's ccache cache, statistics
commands, and `--use_cache`. The pinned shared `setup-build-tools`
action still requires ccache version/hash inputs and downloads it, but
`add-ccache-to-path: false` is set and this job does not use it. Other
tool provisioning, artifact upload and downstream jobs remain unchanged.
The test file `test_prepare_minimal_build_test_data.py` is excluded as
requested.

Validation after review changes:
- `.\.venv\Scripts\python.exe -m ruff check
tools\ci_build\prepare_minimal_build_test_data.py` — passed.
- `.\.venv\Scripts\python.exe -m ruff format --check
tools\ci_build\prepare_minimal_build_test_data.py` — passed.
- `.\.venv\Scripts\python.exe -m py_compile
tools\ci_build\prepare_minimal_build_test_data.py` — passed.
- `git diff --check` — passed.
- Inline Python checks of parsed workflow YAML, unchanged downstream
jobs, preserved build flags, and mocked conversion/config generation,
missing-library behavior, failure propagation and cleanup — passed.
- Bash syntax checks for all preparation-job run steps and execution of
wheel-selection logic with a stub pip — passed for one wheel;
zero/multiple wheels correctly rejected before pip.
- Previous commit `37b738543a` passed the full-build preparation job and
all downstream Linux minimal-build jobs in CI. The updated commit still
requires CI validation; no full Linux build or real model conversions
were run locally.

### 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. -->

Keep minimal-build preparation logic in ONNX Runtime as ordinary Python
instead of the external bundled JavaScript action, while removing
training operators from the preparation build. Keep environment setup
explicit in the workflow, as requested in review, and disable ccache for
the preparation job. Existing training-retirement and companion actions
PRs remain untouched.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ng and plugin EP support (microsoft#33839)

### Description
<!-- Describe your changes. -->

This PR accelerates external initializer loading to GPU memory for both
the built-in CUDA Execution Provider and the CUDA Plugin Execution
Provider without introducing external storage dependencies (`libcufile`
/ GPUDirect Storage or DirectStorage):

1. **Lock-Free Multi-Worker Double-Buffered Pinned Staging & Async H2D
Pipeline**:
- Replaces the per-chunk global thread-pool barrier and per-tensor
`cudaStreamSynchronize` barrier with a shared lock-free work queue
(`ExecuteExternalDataLoadTasks` in
`onnxruntime/core/framework/external_data_loader_thread_pool.h`).
- Each reader worker owns a 4 KiB-aligned slice in both double-buffered
pinned staging buffers and a pair of non-blocking CUDA streams, pulling
chunks (`2 MiB` default) via atomic index and overlapping multi-threaded
file reads (`pread` on POSIX / `OVERLAPPED` `ReadFile` on Windows) with
`cudaMemcpyAsync` across tensor boundaries.
2. **CUDA Plugin EP (`PluginExecutionProvider`) Support**:
- Implements `PluginExecutionProvider::GetExternalDataLoader()` using
`host_accessible_memory_info` (`Reserve`/`Free` for pinned memory),
lightweight copy-only `OrtSyncStreamImpl` streams (`copy_only=1`,
skipping unnecessary cuBLAS/cuDNN handle creation), and
`OrtDataTransferImpl` (`CopyTensorAsync`).
- Ensures `CudaDataTransfer::CopyTensorsImpl` and
`CudaSyncStream::FlushImpl` select and restore the target CUDA device
when invoked from reader worker threads.
3. **Cross-Tensor Batch Lifecycle, Offset Sorting, and File-Handle
Caching**:
- Extends `IExternalDataLoader` and `ExternalDataLoaderManager` with
`BeginLoad()`, `FinalizeLoad()`, and `EndLoad()` so external tensors in
`SaveInitializedTensors` are pipelined across tensor boundaries and
synchronized once in `FinalizeLoad()`.
- Sorts initializers in `SaveInitializedTensors` by `(external_location,
external_offset, ort_value_index)` for sequential file access instead of
hash-bucket order, and caches validated `RandomAccessFile` handles per
`SaveInitializedTensors` call.
4. **Conservative Defaults, Model-Size Gating, Session Options, and
Minimal Build Exclusion**:
- Computes the default reader thread count from physical CPU cores
(`clamp(physical_cores / 2, 2, 8)`).
- Uses a conservative **32 MiB** default total pinned staging allocation
(two `16 MiB` buffers, 4x smaller than the previous 128 MiB default).
- Defers pinned buffer, stream, and thread-pool allocation until
`FinalizeLoad()` and gates it on a **16 MiB** minimum total external
initializer size on the device
(`session.external_data_loader.min_size_bytes`), so small models incur
zero pinned-memory or stream-creation overhead.
- Adds session configuration keys
(`session.external_data_loader.threads`,
`session.external_data_loader.pinned_memory_bytes`,
`session.external_data_loader.chunk_bytes`,
`session.external_data_loader.min_size_bytes`) alongside matching CUDA
EP provider options (`external_data_loader_reading_threads`,
`external_data_loader_pinned_memory_bytes`,
`external_data_loader_chunk_bytes`).
- Excludes the feature from minimal builds
(`!defined(ORT_MINIMAL_BUILD)` and `!defined(USE_CUDA_MINIMAL)`).

#### Summary of Changes

| File | Change |
|---|---|
|
`include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h`
| Add
`session.external_data_loader.{threads,pinned_memory_bytes,chunk_bytes,min_size_bytes}`
keys |
| `include/onnxruntime/core/providers/cuda/cuda_provider_options.h` |
Add `external_data_loader_{pinned_memory_bytes,chunk_bytes}` and
conservative defaults to `OrtCUDAProviderOptionsV2` |
| `onnxruntime/core/framework/external_data_loader.h` | Add
`ExternalDataLoaderOptions`, validation/parsing helpers, and
`Configure`/`BeginLoad`/`FinalizeLoad`/`EndLoad` hooks |
| `onnxruntime/core/framework/external_data_loader_thread_pool.h` |
Shared portable `std::thread` worker pool and lock-free double-buffered
`ExecuteExternalDataLoadTasks` pipeline |
| `onnxruntime/core/framework/external_data_loader_manager.{h,cc}` | Add
`BeginLoad`, `FinalizeLoad`, and `EndLoad` batch lifecycle management |
| `onnxruntime/core/framework/session_state_utils.cc` | Sort external
initializers by `(location, offset)`, cache validated file handles, and
bracket loading with `BeginLoad`/`FinalizeLoad`/`EndLoad` |
| `onnxruntime/core/framework/tensorprotoutils.{h,cc}` | Add
`ExternalDataFileCache` to validate and open each external `.data` file
once per `SaveInitializedTensors` pass |
| `onnxruntime/core/providers/cuda/cuda_external_data_loader.{h,cc}` |
Use shared lock-free pipeline, support configurable threads/pinned
memory/chunk size/min model size, and guard minimal builds |
| `onnxruntime/core/providers/cuda/cuda_execution_provider_info.{h,cc}`,
`cuda_provider_factory.cc`, `cuda_execution_provider.cc`,
`provider_bridge_ort.cc` | Parse, validate, and forward new external
data loader options |
|
`onnxruntime/core/session/plugin_ep/ep_plugin_provider_interfaces.{h,cc}`,
`onnxruntime/core/providers/cuda/plugin/*` | Implement
`PluginExternalDataLoader`, copy-only sync streams, device-safe worker
H2D copies, and option validation |
| `docs/Model_Loading_Performance.md` | Document new session options,
provider options, defaults, and model-size threshold |
| `onnxruntime/test/framework/external_data_loader_test.cc`,
`cuda_external_data_loader_test.cc`, `test_cuda_plugin_ep.py` | Add C++
and Python unit tests for session options, provider options, min-size
gating, and invalid-option rejection |

### 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. -->

Loading large ONNX models with external weights (e.g.,
`qwen_flash_next_int4_int8_rc5_contrib_dflash2/model.onnx`, 68.46 GiB
across 899 external tensors in 7 `.data` files) into GPU memory during
`InferenceSession` creation had several bottlenecks:
1. `PluginExecutionProvider` (used when building the CUDA EP as a
plugin) did not implement `GetExternalDataLoader()`, falling back to
per-tensor `mmap` + single-threaded pageable `cudaMemcpy`.
2. In the existing pinned-buffer loader (microsoft#32437 / microsoft#32713 fallback when
`nvidia-fs` is unavailable), a global thread-pool barrier per 64 MiB
chunk and a `cudaStreamSynchronize` barrier at the end of every
`LoadTensor()` call prevented CPU/GPU overlap across tensors `<= 64 MiB`
(705 of 899 tensors), forced all 613 tensors `< 16 MiB` onto a single
thread, iterated over initializers in arbitrary hash-bucket order, and
reopened/revalidated `.data` files for every tensor.

#### Benchmark Comparison
(`qwen_flash_next_int4_int8_rc5_contrib_dflash2/model.onnx`, 68.46 GiB,
899 External Tensors, NVIDIA H200)

| Configuration | Threads | Pinned Memory | End-to-End
`InferenceSession` Time | Effective Throughput | Speedup vs Baseline |
|---|---:|---:|---:|---:|---:|
| **Baseline (`origin/main` CUDA Plugin EP)** | 1 (pageable) | 0 MiB |
14.481 s | 4.73 GiB/s | 1.00x |
| **PR microsoft#32713 (`use_gds=1` -> 4-thread barrier fallback)** | 4 | 128 MiB
| 5.110 s | 13.40 GiB/s | 2.83x |
| **This PR (same 4 threads, 4x less pinned memory)** | **4** | **32
MiB** | **3.730 s** | **18.35 GiB/s** | **3.88x** |
| **This PR (same 4 threads, same 128 MiB pinned memory)** | **4** |
**128 MiB** | **3.657 s** | **18.72 GiB/s** | **3.96x** |
| **This PR (Default: 8 threads from CPU cores, conservative 32 MiB
pinned)** | **8** | **32 MiB** | **2.191 s** | **31.25 GiB/s** |
**6.61x** |
| **This PR (Opt-in: 16 threads, 64 MiB pinned)** | **16** | **64 MiB**
| **1.967 s** | **34.81 GiB/s** | **7.36x** |

Even at the **exact same 4-thread count and 4x smaller pinned memory (32
MiB vs 128 MiB)**, the lock-free cross-tensor pipeline + offset sorting
+ file-handle caching reduces session creation time from **5.110 s to
3.730 s (1.37x faster)**. With the CPU-core-derived default (`8`
threads) and conservative `32 MiB` pinned memory, session creation
completes in **2.191 s (31.25 GiB/s)**.

#### Validation
- `./onnxruntime_test_all
--gtest_filter="*ExternalDataLoader*:*Initializer*"` — **127 tests ran,
126 passed, 1 skipped (32-bit platform check), 0 failed**.
- `ORT_TEST_CUDA_PLUGIN_EP=1 python
onnxruntime/test/python/transformers/test_cuda_plugin_ep.py` — **94
tests ran, 92 passed, 2 skipped, 0 failed** (including
`test_external_data_loader_modes_and_validation`).
- `lintrunner -a` — **passed (0 lint issues)**.

---------

Co-authored-by: Xavier Dupré <xadupre@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ment (microsoft#33481)

### Description
Introduce generic `enableFeatures` and `disableFeatures` lists for named
WebGPU EP features, initially supporting `subgroupMatrix`.

The feature registry is independent of WebGPU device features. Each
session’s execution provider filters kernel-facing feature queries
according to its settings, including when using an externally supplied
device.

Disabling `subgroupMatrix` selects existing fallback kernels for that
session. Sessions sharing a device configure features independently,
regardless of creation order; omitted features use registry defaults.

#### Usage:
- JS (onnxruntime-web / onnxruntime-node):
    ```
executionProviders: [{ name: 'webgpu', disableFeatures:
['subgroupMatrix'] }]
    ```

- C++ provider options / session config entry:
    ```
    session_options.AddConfigEntry(
        "ep.webgpuexecutionprovider.disableFeatures", "subgroupMatrix");
    ```

### Motivation and Context
See above.
…t#32702)

### Description
Add `FlashAttentionPrefillProgram`, a simplified variant of
`FlashAttentionProgram` used for dense prefill on Intel GPUs.

#### Kernel design (and key differences from `FlashAttentionProgram`):
- One query row per thread.
- The full-head K tile is staged before the QK^T + online-softmax
  stage. V is staged just before the PV matmul, in slices of up to 16
  vec4 values, so global-memory latency overlaps with softmax compute
  and V needs less workgroup memory. The default kernel stages both K
  and V at full head size.
- K and V tiles use a transposed layout (`[head_size_vec][kv_step]`),
  so adjacent lanes hit adjacent shared-memory addresses and avoid bank
  conflicts. The default kernel uses `[kv_step][head_size_vec]`.
- Subgroup shuffle is a static code path chosen on the host from the
  adapter's guaranteed minimum subgroup size (`shuffle_chunk =
  min(kv_step, subgroup_min_size)`). Below 8, the kernel reads K/V
  directly from shared memory, which also covers adapters without
  subgroups.
- The workgroup size and KV step are chosen per adapter and shapes.
- No quantized KV cache, TurboQuant LUT, or compressed K/V decoding
  paths.

#### Configuration (host-selected per adapter):
- Default: 64 threads, 16 KV rows per step.
- Xe2: 128 threads / 64 KV rows for query length <= 128, otherwise
  256 threads / 32 KV rows.
- Xe3: 128 threads / 64 KV rows.
- If the K tile and V slice would exceed
  maxComputeWorkgroupStorageSize, fall back to the default
  configuration.

#### Integration:
- Adds CanApplyFlashAttentionPrefill and ApplyFlashAttentionPrefill.
  ApplyDensePrefill selects this kernel when the adapter is Intel and
  the KV cache is not quantized. Otherwise it uses the existing
  FlashAttentionProgram.
- Quantized KV cache (int8 / TurboQuant) is not supported by this
  kernel yet.

#### Tests:
- Parameterize RunFp16HighMagnitudeAttention by head size and add
  head_size 80 and 96 cases, whose head_size / 4 is not a multiple of
  the V slice width.

#### Performance (Phi-4-mini, Intel Panther Lake):

| Metric | Baseline Prefill TPS | Optimized Prefill TPS | Improve |
|---|---|---|---|
| **Prefill-128** | 1961.46 | 1945.12 | -0.83% |
| **Prefill-256** | 2481.54 | 2502.52 | 0.85% |
| **Prefill-512** | 2577.39 | 2774.83 | 7.66% |
| **Prefill-1024** | 2505.69 | 2751.47 | 9.81% |
| **Prefill-2048** | 2346.94 | 2673.69 | 13.92% |
| **Prefill-4096** | 1668.55 | 1985.91 | 19.02% |

#### TODO (follow-up PRs):
- Support quantized KV cache (int8 / TurboQuant).
- Merge back into `FlashAttentionProgram`.

### Motivation and Context
See above.
### Description
<!-- Describe your changes. -->

Add blocking GPU IO-binding and Release proxy runs, align native suites,
and use descriptive browser profiles with automatic log discovery.

### 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. -->

Prepare for JSEP migration.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…icrosoft#33848)

### Description
<!-- Describe your changes. -->

Update the DLPack v1.3 dependency revision and hashes in CMake, vcpkg,
and component governance. Add bidirectional mappings for all implemented
ORT numeric/bool types, including all five float8 variants, packed
float4, int4/uint4, and int2/uint2.

Use native `kDLBool` metadata and remove `is_bool_tensor`, dtype
inspection, and bool-as-uint8 workarounds throughout inference,
ORTModule, Triton, and ATen scalar conversion. The low-level override
API intentionally breaks; uint8 metadata now always imports as uint8.

Export explicit contiguous strides, honor import byte offsets, allow
nullable producer deleters, and add
dtype/storage/lifetime/offset/invalid-metadata regression coverage.
Retain legacy `DLManagedTensor` capsule exchange; versioned capsule
negotiation is not added.


### 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. -->

Modern DLPack provides distinct bool and low-precision dtype codes,
enabling correct zero-copy interchange without historical uint8
workarounds.

float6 remains unsupported because ORT lacks its tensor storage/type
implementation on this branch. Complex tensors are also unimplemented;
string tensors have no compatible DLPack representation.

---------

Co-authored-by: justinchuby <11205048+justinchuby@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#33889)

### Description
<!-- Describe your changes. -->

- Stop requiring import libraries for dynamically loaded CUDA and
TensorRT providers.
- Detect the CUDA DLL in the CMake install tree's lib directory when
staging headers.

### 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. -->

Fix packaging pipeline issues.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description
<!-- Describe your changes. -->

Move `test/providers/cuda/bitwise_ops_test.cc` to
`test/providers/cpu/math/cuda_bitwise_ops_test.cc` under `USE_CUDA`,
where both in-tree and plugin CUDA EP builds include it. Preserve all
nine tests, integer types, opsets, broadcasting and edge cases
unchanged, including explicit CUDA selection and disabled CPU fallback.
The existing provider factory selects the plugin EP in plugin builds.

Validation: evaluated the repository's CMake source-selection clauses
for both build modes (suite included exactly once); verified the
original test body is unchanged; MSVC `/WX /Zs` CPU-only compile check
and `git diff --cached --check` passed. CUDA-enabled build/execution was
not run: this local worktree has no build and the CUDA toolkit is not
installed.

### 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. -->

Addresses [the review comment on
microsoft#33646](microsoft#33646 (comment)):
the CUDA-specific source glob excludes plugin builds, leaving these
kernels untested by CUDA Plugin EP CI. This is a follow-up to merged
microsoft#33646.

Signed-off-by: Justin Chu <justinchuby@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…t#33757)

### Description
<!-- Describe your changes. -->

Add one independent, default-off, EP-owned CUDA kernel replacement for
both **FLOAT and BF16**:

```text
ep.cuda.runtime_fusion.unit_swish = 0 | 1
ONNX Swish-24(x, alpha=1) -> com.microsoft.ScaledSiLU-1(x, alpha=1)
```

This PR is based directly on `main` at
`dd543febefd37da323b11c4c472b4ecb6e81e159`, using the region-scoped
`Run` API already merged in microsoft#33652. It **does not depend on microsoft#33705**.
CausalConv remains a separate follow-on PR; there is no separate BF16
Swish PR.

Only exact configuration strings `"0"` and `"1"` are accepted. Alpha may
be absent/defaulted or a FLOAT exactly equal to 1. Non-unit alpha is not
admitted: Swish is `x * sigmoid(alpha*x)`, while ScaledSiLU is
`silu(alpha*x)`.

The replacement uses the existing `rewrite::PatternRewriter` API,
metadata-only discovery, a typed scratch CUDA-kernel probe, and owned
metadata snapshots with graph-owned identity tokens revalidated before
acceptance. It preserves graph outputs and fanout, skips ineligible
anchors before matcher traversal, and checks the target's launch bound.

The adapter separates the common admission gates in `Select` from
`detail::SwishFusion::Discover` and the case-local `OfferSwish`. Offers
carry deferred optimization callbacks rather than modifying the graph
during discovery. Acceptance retains the existing region-scoped `Run`,
the exactly-one-rewrite/one-target checks, and input/output identity
revalidation. It does not import `RunOnce` or the unmerged
CausalConv/multi-sink changes from microsoft#33705. Configuration strings, the
internal `unit_swish_scaled_silu_v1` identifier, and diagnostics remain
unchanged.

Admission retains the main-graph/unfiltered-view, optimization-level,
exact opset-import, full-CUDA-build, consumer, layout, resource, and
ORT-loader guards. Symbolic, anonymous, scalar, and empty shapes are
supported without guessing workload sizes. Learned initializer payloads
and external files are not read during discovery.

**No new CUDA kernel or arithmetic, operator schema, public API,
input-model conversion, model-ID whitelist, CausalConv fusion, RMS, or
Scan implementation is introduced.** Existing CUDA `ScaledSiLU` kernels
are reused.

**Validation**

**Standalone adapter refactor:** built all objects and provider
libraries afresh from this checkout, using only copied cached dependency
sources. No previously built objects or libraries were reused. Release,
H200/sm90, CUDA 13.3, QUICK_BUILD ON, native CUDA profiling OFF.

| Exact command | Result |
|---|---|
| `cmake --build
/mnt/data/titaiwang/runtime-fusion/swish-refactor-20261104/build/Release
--target onnxruntime_optimizer onnxruntime_test_all
onnxruntime_provider_test --parallel 24` | Passed; fresh build,
including the new Swish translation unit |
| `./onnxruntime_test_all --gtest_filter=UnitSwishHostTest.*
--gtest_output=xml:/mnt/data/titaiwang/runtime-fusion/swish-refactor-20261104/host.xml`
| **13 passed**, zero failures/errors/skips |
| `./onnxruntime_provider_test
--gtest_filter=CudaRuntimeFusionTest.UnitSwish*
--gtest_output=xml:/mnt/data/titaiwang/runtime-fusion/swish-refactor-20261104/provider.xml`
| **11 passed**, zero failures/errors/skips |
| `clang-format --dry-run --Werror
onnxruntime/core/optimizer/cuda_runtime_fusion.cc
onnxruntime/core/optimizer/cuda_runtime_fusion_internal.h
onnxruntime/core/optimizer/cuda_runtime_fusion_swish.cc` | Passed |
| `git diff --check` | Passed |

Both fresh test commands ran from
`/mnt/data/titaiwang/runtime-fusion/swish-refactor-20261104/build/Release`,
with `CUDA_VISIBLE_DEVICES=0` and
`LD_LIBRARY_PATH=/mnt/data/titaiwang/runtime-fusion/swish-refactor-20261104/build/Release:/usr/local/cuda-13.3/lib64:/mnt/data/titaiwang/runtime-fusion/venv/lib/python3.12/site-packages/nvidia/cudnn/lib`.
Provider library mappings, tested source hashes, generated CMake/Ninja
source registration, XML counts, protected-build preservation, and owned
cache cleanup were verified. No test inputs, assertions, or test source
files changed.

The bounded refactor was reviewed directly; no actionable findings were
found. Existing predicates, diagnostics, callback lifetime/ownership,
region `Run`, postconditions, and admission order were checked against
the baseline. This fresh pass does not rerun the full provider suite,
whole-model qualification, non-CUDA variants, or cross-architecture
coverage.

**Pre-refactor qualification:** source
`74ca7dec28844f26504f92aac052591d4b77c456`. Proper offline Release build
on H200/sm90 with CUDA 13.3 and QUICK_BUILD; existing cached
dependencies only. The build was rerun after fixing standalone-test
`-Werror=unused-function` errors caused by orphaned causal-only helpers.
The archived results below describe that revision, not a rerun of the
refactored adapter.

| Exact command | Result |
|---|---|
| `cmake --build
/mnt/data/titaiwang/runtime-fusion/build-bf16-unit-swish/Release
--target onnxruntime onnxruntime_test_all onnxruntime_provider_test
--parallel 8` | Passed |
|
`/mnt/data/titaiwang/runtime-fusion/build-bf16-unit-swish/Release/onnxruntime_test_all
--gtest_filter=UnitSwishHostTest.*:CUDARuntimeFusionHostTest.*:PatternRewriterTests.*:PatternComponentTests.*:PatternCapabilityTests.*:ReplacementComponentTests.*:CheckAndBindComponentTests.*:MatchComponentTests.*:FunctionTest.*
--gtest_output=xml:/mnt/data/titaiwang/runtime-fusion/swish-causal-cleanup-20261030/swish-final/host.xml`
| **296 passed**, zero failures/errors/skips |
|
`/mnt/data/titaiwang/runtime-fusion/build-bf16-unit-swish/Release/onnxruntime_provider_test
--gtest_filter=CudaRuntimeFusionTest.*:CudaRuntimeFusionProbe.ZeroBatch:CausalConvWithStateTest.*-*LocalAuthentic*
--gtest_output=xml:/mnt/data/titaiwang/runtime-fusion/swish-causal-cleanup-20261030/swish-final/provider.xml`
| **69 passed**, zero failures/errors/skips |

Both test commands ran from the build's `Release` directory. The
provider test loaded that build's CUDA/shared provider libraries; exact
libraries were archived and SHA-256 recorded before subsequent work.

The selected suites include unit-Swish host and CUDA tests. Coverage
includes default-off/malformed/basic policy, typed-kernel rejection,
metadata immutability and stale acceptance, external initializer
headers, shape/launch bounds, graph outputs/fanout,
NHWC/resource/consumer exclusions, ORT file/buffer compatibility, and
both numeric dtypes. Numeric tests compare actual expanded CUDA source
against recovered `ScaledSiLU` with CPU fallback disabled. Non-NaN
values must match bitwise; NaN classification must agree. FLOAT raw-bit
cases and all 65,536 BF16 raw patterns are covered; exhaustive BF16
enumeration is one rank-1 case, with seeded raw-bit coverage at
additional ranks/shapes.

`clang-format --dry-run --Werror` over changed C++ files and `git diff
--check` passed. Full lintrunner was unavailable because
`lintrunner_adapters` was missing; no dependencies were installed.

**Additional unchanged-Qwen diagnostic**

The original Qwen3.8-27B standard BF16 decoder and embedding model were
loaded without conversion, re-export, or editing model files. Batch 1,
12-token prefill and one decode carrying each route's own states. Causal
fusion was disabled; only unit-Swish differed.

```sh
/mnt/data/titaiwang/runtime-fusion/venv/bin/python -B /mnt/data/titaiwang/runtime-fusion/swish-causal-parent-20261030/model.py /mnt/data/titaiwang/runtime-fusion/swish-causal-cleanup-20261030/swish-final/libraries 74ca7de swish-independent-model-final
```

Result: **passed**. All 129 outputs were finite and bitwise identical
off/on at both prefill and decode. ORT profiles recorded 48 unique FLOAT
and 112 unique BF16 recovered nodes. Raw Nsight/CUPTI records confirmed
**96 FLOAT and 224 BF16 `ScaledSiLUKernel` launches** across the two
steps; the disabled route had zero target events. Original model hashes
and external-data file metadata were unchanged. Local harness/profiles
are not committed; generated profiler SQLite files were removed and
profiles compressed.

This is an additional exercised-model result, not a required whole-model
accuracy claim or proof for arbitrary models/generation lengths.

**Review and exclusions**

Pre-refactor five-role static review completed with actual runtime
models verified. Critical/Major findings ledger: empty. Minority report:
none. Nonblocking questions: Critical notes remaining whole-graph
indexing per Swish candidate has not been scaling-benchmarked;
Integration notes ORT serialization inlines source Swish, so the
file/buffer round-trip test alone does not prove a preserved-Swish
artifact takes the loader opt-out. Unsupported-consumer tests and direct
loader wiring are covered separately.

Not checked: other GPU architectures, broad performance/scaling,
long-generation accuracy, and excluded/minimal/plugin build variants.
The numeric results describe exercised inputs, not a universal
cross-platform bitwise guarantee. No models, weights, profiler caches,
or binaries are committed.

### 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. -->

Standard-op exports can preserve unit-alpha Swish even though CUDA
already provides the equivalent ScaledSiLU kernel. Select that
implementation through the EP's capability mechanism without changing
the model or requiring exporter-specific graph rewrites, with one
dtype-qualified replacement rather than separate FLOAT/BF16 PRs.

---------

Co-authored-by: Ti-Tai Wang <18010845+titaiwangms@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ort-circuit for QMoE offload (microsoft#33624)

## Motivation & Summary

Builds on microsoft#33575 (`[CUDA/CPU] Add INT4 and INT3 QMoE CPU/GPU offload
support`) with two decode-path optimizations (numerically equivalent to
within `~1e-5` for the AVX2 cold-expert kernel, and bitwise identical
for the zero-cold doorbell short-circuit) and one C++ test fixture fix:

1. **AVX2 + FMA + F16C cold-expert INT4 kernel
(`qmoe_shared_layout.cc`):**
On x86-64 hosts with `AVX2+FMA+F16C` that do not support `AVX-512` (such
as AMD EPYC Zen 2 on Azure NDv4 A100 VMs and Intel Haswell–Alder Lake),
`CpuHasAvx512()` returns `false` and cold-expert INT4 dequant-GEMM and
FP16/BF16 row conversions fall back to scalar C++ loops (`46.36 ms/tok`
of CPU compute at `25%` GPU residency on 48-layer `Qwen3-30B-A3B`). This
PR adds runtime `CPUID` + `XGETBV` detection (`CpuHasAvx2FmaF16c()`) and
an `AVX2+FMA+F16C` implementation for FP16/BF16 row conversions and
`Avx2Int4GemmRange` (supporting both prepacked SM80 INT4 layout and raw
INT4 layout, FP16 and BF16 scales/biases), plus an $O(1)$ lookup table
in `ReorderedPosition`.

2. **Zero-PCIe doorbell short-circuit
(`session.moe.offload.skip_zero_cold_doorbell`):**
During partial-residency hybrid decode ($M \le 4$), when all $M \times
k$ selected experts for a layer are already GPU-resident (`cold_count ==
0`), the default doorbell path still copies the activation tile and
expert indices to pinned host memory and wakes the CPU doorbell worker
thread. When `session.moe.offload.skip_zero_cold_doorbell="1"` (or
`ORT_QMOE_SKIP_ZERO_COLD_DOORBELL=1`) is enabled under static placement
without cross-layer promotion, `QMoEOffloadClassifyKernel` counts cold
selections via `__syncthreads_count(is_cold)` before issuing any host
writes and, when `cold_count == 0`, advances `doorbell_done_host` and
`doorbell_req_host` directly on the GPU (`__threadfence_system()`) so
`QMoEWaitAndAccumulateKernel` proceeds without PCIe host staging or CPU
worker wakeups.

3. **INT3 CUDA test fixture update (`moe_test.cc`):**
Updates `MoETest.QMoECudaInt3TiledLogHasOneCounterUpdate` to match the
SwiGLU `QMoE` contract introduced in microsoft#33575 (`activation_type =
"swiglu"`, `swiglu_fusion = 1`, `fc1` rows `= 2 * inter_size`, and
unsigned INT3 zero-point code `4`).

## Key Changes

- `onnxruntime/contrib_ops/cpu/moe/qmoe_shared_layout.{h,cc}`:
- Add `CpuHasAvx2FmaF16c()`, `CompilerHasAvx2()`, and C ABI
`qmoe_shared_cpu_has_avx2()` /
`qmoe_shared_set_disable_avx512_for_testing()`.
- Add `Avx2HalfBitsToFloatRow`, `Avx2FloatToHalfBitsRow`,
`Avx2BFloat16BitsToFloatRow`, `Avx2FloatToBFloat16BitsRow`,
`Avx2RoundFp16InPlace`, and `Avx2Int4GemmRange`.
- Replace the linear scan in `ReorderedPosition` with a 32-entry
constant lookup table.
- `onnxruntime/contrib_ops/cuda/moe/qmoe_kernels.{h,cu}`,
`onnxruntime/contrib_ops/cuda/moe/qmoe_offload.{h,cc}`,
`onnxruntime/core/framework/moe_offload_plan.h`,
`include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h`:
- Add `kOrtSessionOptionsMoeOffloadSkipZeroColdDoorbell`
(`session.moe.offload.skip_zero_cold_doorbell`, default `"0"`).
- Short-circuit PCIe host staging and CPU doorbell wakeups when
`cold_count == 0` and cross-layer promotion is inactive; retire
pre-completed sequence numbers cleanly in `DoorbellService`.
- Allocate optional `QMoEOffloadTelemetry`
(`ORT_QMOE_OFFLOAD_TELEMETRY=1`) in device scratch memory and copy back
once in `~QMoEOffload()`.
- `onnxruntime/test/contrib_ops/moe_test.cc`,
`onnxruntime/test/contrib_ops/qmoe_shared_layout_test.cc`,
`onnxruntime/test/python/transformers/test_qmoe_shared_layout.py`,
`onnxruntime/test/python/test_qmoe_offload_v4.py`:
  - Fix `MoETest.QMoECudaInt3TiledLogHasOneCounterUpdate`.
- Add C++ and Python unit tests covering `AVX2+FMA+F16C` vs. scalar
numerical parity (`max_abs_diff < 1e-5`, including all 65,536 FP16 half
patterns and partial-range vector interiors) and zero-cold doorbell
bitwise parity, sequence counter transitions, and cross-layer promotion
fallback.
- `docs/contrib_ops/cuda/moe_qmoe.md`:
- Document `AVX-512 -> AVX2+FMA+F16C -> scalar` cold-expert dispatch,
`session.moe.offload.skip_zero_cold_doorbell`, and environment variables
(`ORT_QMOE_SKIP_ZERO_COLD_DOORBELL`, `ORT_QMOE_OFFLOAD_TELEMETRY`,
`ORT_QMOE_CPU_DISABLE_AVX512`).

## Verification & Benchmarks

### Unit & Provider Tests
- `onnxruntime_test_all --gtest_filter="*MoETest*:*QMoE*"`: **6 / 6
passed**
- `onnxruntime_provider_test
--gtest_filter="QMoESharedLayoutTest.*:MoETest.*"`: **91 / 91 passed**
- `pytest onnxruntime/test/python/test_qmoe_offload_v4.py
onnxruntime/test/python/transformers/test_qmoe_shared_layout.py
onnxruntime/test/python/transformers/test_qmoe_cuda.py`: **153 / 153
passed**

### End-to-End 48-Layer `Qwen3-30B-A3B` (`QMoE` INT4, `block_size=32,
weights_prepacked=1`) Decode Latency (`ORT_QMOE_OFFLOAD_TELEMETRY=0`, 5
Trials `mean ± stdev`)
Measured on 1x NVIDIA A100-SXM4-80GB + AMD EPYC 7V12 (Zen 2,
`AVX2+FMA+F16C`, no `AVX-512`), 5 independent trials of 10 warmup + 30
decode steps ($M = 1$, $k = 8$, 128 experts/layer) with
`ORT_QMOE_OFFLOAD_TELEMETRY=0` (and a separate
`ORT_QMOE_OFFLOAD_TELEMETRY=1` pass to record wakeup/short-circuit
counts):

| GPU Residency (Experts / Layer) | microsoft#33575 Baseline (Scalar Cold CPU,
ms/tok) | AVX2 Cold Kernel (`skip_zero_cold=0`, ms/tok) | AVX2 +
Zero-Cold Doorbell (`skip_zero_cold=1`, ms/tok) | Speedup vs. microsoft#33575
(`skip=0` / `skip=1`) | Zero-Cold Short-Circuits / Token (`skip=1`) |
CPU Doorbell Wakes / Token (`skip=0` $\to$ `skip=1`) | Min Logit Cosine
vs. Scalar | Top-1 Token Parity |
| :--- | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| **32 / 128 (25%)** | 54.46 ms (18.4 tok/s) | **21.60 ± 0.37 ms** (46.3
tok/s) | **21.89 ± 0.55 ms** (45.7 tok/s) | **2.52x / 2.49x** | 7.78 /
48 | 48.00 $\to$ **40.23** (-16.2%) | 0.999561 | **30 / 30 (100%)** |
| **64 / 128 (50%)** | 15.52 ms (64.4 tok/s) | **10.80 ± 0.10 ms** (92.6
tok/s) | **10.66 ± 0.23 ms** (93.8 tok/s) | **1.44x / 1.46x** | 36.65 /
48 | 48.00 $\to$ **11.35** (-76.4%) | 0.999818 | **30 / 30 (100%)** |
| **96 / 128 (75%)** | 9.04 ms (110.6 tok/s) | **8.30 ± 0.19 ms** (120.4
tok/s) | **8.56 ± 0.41 ms** (116.8 tok/s) | **1.09x / 1.06x** | 46.98 /
48 | 48.00 $\to$ **1.02** (-97.9%) | 0.999883 | **30 / 30 (100%)** |
| **128 / 128 (100%)** | 8.31 ms (120.4 tok/s) | **7.55 ± 0.06 ms**
(132.5 tok/s) | **7.61 ± 0.26 ms** (131.4 tok/s) | **1.10x / 1.09x** | —
| 0.00 $\to$ **0.00** | 1.000000 | **30 / 30 (100%)** |

*(Note: `skip_zero_cold_doorbell="1"` is 100% bitwise identical
(`max_abs_diff = 0.0`, `cosine = 1.000000`) to
`skip_zero_cold_doorbell="0"` across all residencies. On an uncontended
host, single-stream decode latency for `skip=0` vs. `skip=1` is within
noise because GPU resident GEMVs overlap the zero-cold doorbell wakeup,
while `skip=1` eliminates the 4 KB/layer PCIe host staging writes and
reduces CPU doorbell wakeups by 76.4% at 50% residency and 97.9% at 75%
residency.)*

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…icrosoft#33699)

### Mechanism
In bounded host-cache offload mode
(microsoft#33622),
QMoEOffload::RunColdExperts fuses per-expert chunked demand loads
(FileExpertStore::LoadExpertChunk and FinishLoadExpert) with FC1 and FC2
tile execution in a single parallel dispatch. Previously, the FC1 and
FC2 stages indexed group slots in raw 0 .. group_size - 1 order, so a
demand-missing slot (slot_ready == 0) at a lower slot index caused
worker threads to spin on its readiness barrier before reaching
already-cached ready slots (slot_ready == kReadyDoneVal).

This change adds BuildReadyFirstSlotOrder and
RunReadyFirstFusedColdExpertGroup in qmoe_shared_layout.h to stably
partition group slots before parallel dispatch so initially ready cached
slots execute before demand-loading slots in FC1 and FC2. Each slot
retains its original activation input, lease binding, intermediate
buffer, output buffer, and reduction order. When miss_load_count == 0
(all cache hits), reordering is bypassed. Pre-dispatch handling of
in-flight prefetches (BeginLoadExpert returning -1) and lease cleanup
behavior are unchanged.

### Base & Tested Configuration
- **Base branch**: Applies cleanly on top of
microsoft#33622 (commit
5855bd4); ready-first slot ordering is
independent of CPU SIMD ISA.
- **Tested configuration on Zen 2**: Both baseline and candidate
benchmark builds merged
microsoft#33622 with
microsoft#33624 (commit
2ced7eaf86764c6cf25e38c2ba083c54251e9a45) so cold-expert INT4 GEMMs on
the AVX2-only AMD EPYC 7V12 host executed Avx2Int4GemmRange rather than
ScalarInt4GemmRange. AVX2 was part of both benchmark builds, not a
functional requirement of ready-first scheduling.

### Scoped Benchmark Summary
Autoregressive greedy single-token decode on Qwen3-30B-A3B INT4
(full_benchmark.onnx, 48 layers, 128 experts/layer, top_k=8,
hidden=2048, intermediate=768, block_size=32), 1x NVIDIA A100-SXM4-80GB
+ AMD EPYC 7V12 (8 SpinPool CPU threads),
tail_substitution_threshold=0.0, skip_zero_cold_doorbell=0. Evaluated
across N = 8 balanced pairs (2 complete 4x4 cyclic Latin squares across
4 prompts x 32 generated tokens = 124 post-first tokens/run,
counterbalanced across AB/BA orders = 32 paired requests/condition):

| Condition (N = 8 Latin-Square pairs, 124 post-first tokens/run) |
Baseline Decode Wall (ms, mean ± SD) | Candidate Decode Wall (ms, mean ±
SD) | Paired Wall Diff (Cand - Base, mean ± 95% CI) | Baseline Sustained
(tok/s, mean ± SD) | Candidate Sustained (tok/s, mean ± SD) | Paired
Throughput Diff (mean ± 95% CI) |
|---|---:|---:|---:|---:|---:|---:|
| **Primary**: adaptive_promo_on, gpu_slots=32, host_cache_slots=16
(2.04 GB), prewarm=1 | 3592.00 ± 72.82 | 3533.61 ± 61.54 | **-58.38 ±
27.70 ms** (-1.62% ± 0.74%, 95% CI [-2.36%, -0.88%], p = 0.0016, 8/8
faster) | 34.534 ± 0.690 | 35.101 ± 0.613 | **+0.567 ± 0.256 tok/s**
(**+1.65% ± 0.77%**, 95% CI [+0.88%, +2.42%], median +1.43%) |
| **Cache-Hit Control**: static, gpu_slots=32, host_cache_slots=95
(12.11 GB), prewarm=1 | 3470.58 ± 60.32 | 3452.16 ± 39.59 | -18.42 ±
30.80 ms (-0.52% ± 0.88%, 95% CI [-1.40%, +0.37%]) | 35.738 ± 0.614 |
35.924 ± 0.410 | +0.186 ± 0.316 tok/s (+0.53% ± 0.89%, 95% CI [-0.36%,
+1.42%]) |

### Output Parity & Validation
- **Output parity**: Across all 64 paired requests (2,048 generated
token steps), generated token sequences and final-step float32 logits
SHA-256 hashes matched between baseline and candidate.
- **Cache-hit control**: No statistically detectable regression in the
tested cache-hit control (host_cache_slots=95, paired decode wall-time
difference -0.52% ± 0.88%, 95% CI [-1.40%, +0.37%]).
- **Unit & regression tests**: Added
QMoESharedLayoutTest.ReadyFirstFusedColdExpertGroupCoversMixedHitsMissesDuplicatesAndFailures
(13/13 non-AVX512 C++ tests in QMoESharedLayoutTest.* on the pure
submission branch, 15/15 on the combined AVX2 branch, and all
non-skipped Python tests in test_qmoe_offload_v4.py and
test_qmoe_shared_layout.py pass).

### Limitations
- Reorders compute slots within mixed ready + demand-loading groups
only; synchronous LoadExpertChunk I/O (pread + TransposeInt4Scales)
still executes on the same SpinPool CPU worker threads, yielding 1.65%
higher throughput (95% CI [+0.88%, +2.42%]) in the tested Qwen
INT4/A100/Zen 2 configuration.
- Benchmark timings above were collected on the minimal ready-first
binary (175145b1...); subsequent review-only hygiene edits (MSVC
intrin.h guard, group_size <= MaxGroupSlots bounds check, test placement
for clean apply on microsoft#33622,
and reverting an unrelated 2-line GroupLeaseGuard edit for scope
isolation) were validated with the C++ and Python regression suites
without re-running the timed benchmark campaign.

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

Support batched right-padded GQA chunks and populated idle entries
(`query_seqlens[b] = 0`) on CPU and CUDA, including single-token steps.
Skip padded preprocessing and attention work while preserving physical
tensor strides and the sliding-window history needed by the first valid
query in each chunk.

This follows microsoft#33503 and microsoft#33505, both already merged. Other execution
providers continue to reject `query_seqlens`; the legacy
multi-token/past-context batch restriction remains when the input is
absent.

## Summary of Changes

### Length semantics and correctness

- Accept `0 <= Q[b] <= min(S, T[b])` with `T[b] >= 1`. An idle entry
keeps its absolute total and cache unchanged. Initially empty idle
entries remain unsupported.
- Honor explicit lengths at `S = 1`, rather than treating every entry as
active.
- Fix CPU flash dispatch for equal resident totals but different past
lengths: the causal offset cannot be shared in that case.
- Preserve staging/eviction behavior: eviction must not discard the
preceding `W - 1` positions needed by the first token of a chunk.
- Clarify that `total_sequence_length` bounds absolute totals, not
windowed cache capacity.

### CPU

- Bound unpack/transpose, RoPE, FP16 conversion, naive QK/softmax/SV and
MLAS flash query work by the valid row count.
- Keep padded physical strides for head, batch, output and bias
addressing.
- Skip idle attention while preserving required past-cache copies for
separately allocated outputs.
- Cover FP32/FP16 inputs and INT8/INT4 caches; retain default MLAS
behavior when valid query counts are not supplied.

### CUDA

- Guard padding before Q/K/V loads, QK-Norm, RoPE, quantization and
cache append.
- Skip idle aliased-cache staging seed/copy-back and unused
ungroup/dequantization rows.
- Bound FlashAttention/MEA query tiles and output stores by device-side
valid lengths.
- Skip padded unfused softmax/output rows and use masked V scratch to
avoid `0 * NaN` contamination from unused cache rows. Include that
scratch in runtime and bounded workspace calculations.
- Bypass XQA, fast Flash decode and cuDNN SDPA with explicit query
lengths because those paths do not represent idle query entries. No host
synchronization is added to inspect query lengths.

**Remaining work:** unfused CUDA cuBLAS QK/SV GEMMs still use dense
physical query dimensions. Partially filled fused tiles retain
tile-granular arithmetic. Scratch allocations and upstream Q/K/V
projection nodes are not made ragged by this change.

### Regression coverage and documentation

- Replay prompts `[513, 1025]` with `S = W = 512`, CPU cache capacity
1023 and CUDA capacity 512:

  | Chunk | Valid queries | Absolute totals |
  |---|---|---|
  | 1 | `[512, 512]` | `[512, 512]` |
  | 2 | `[1, 512]` | `[513, 1024]` |
  | 3 | `[0, 1]` | `[513, 1025]` |

- Compare valid outputs and resident caches with independent unpadded
single-entry full-cache calls. Include all-idle chunks, idle decode,
resumed decode, mixed first/continuation entries, additional eviction,
and equal-total/different-past cases.
- Poison padded Q/K/V and unused floating-cache rows with NaNs. Prebind
sentinel outputs and verify padded rows are not written. The sentinel
check is an optimization regression, not a new public padding-output
guarantee.
- Exercise packed/unpacked inputs, RoPE, FP16/BF16 CUDA, FP32/FP16 CPU,
and INT8/INT4 caches.
- Assert native FlashAttention/MEA/math dispatch without CPU fallback,
exercise MEA large-head accumulation, and replay CUDA graphs while
changing device query lengths.
- Update operator schema, generated operator documentation and CPU/CUDA
guides.

## Testing

Validated locally on H200 with CUDA 13 using the existing incremental
build and feature-source overlays:

- Rebuilt Python runtime, CPU/MLAS, CUDA provider and provider-test
targets, including dependent FlashAttention/MEA translation units.
Verified compiled feature-source and staged-provider parity.
- GQA C++ suite: **123 passed, 14 skipped** (137 tests).
- Focused MEA/unfused workspace GTests: **23 passed**. Both changed
workspace test files compile; additional standalone layout/bounds checks
passed. The main build has CUDA EP internal tests disabled, so the
complete estimator/internal-test suite was not run.
- Targeted Python query-length/windowed suites: **112 passed, 2
skipped**, plus **148 passing subtests**.
- Final new optimization suite rerun: **36 passed**, plus **48 passing
subtests**, including all three CUDA-graph backends.
- Independent NumPy-oracle replay: **96 CPU calls and 156 CUDA calls
passed**; CUDA dispatch verified for FlashAttention, MEA, math and
automatic selection.
- All configured lintrunner checks and `git diff --check` passed.

The CPU output-sentinel test was also run before optimization and
reproduced padded output writes for both flash settings and both
cache-alias modes.

## Checklist

- [x] CPU and CUDA changes included
- [x] Regression tests added/updated
- [x] Existing no-input behavior and other-EP rejection retained
- [x] Documentation and backend limitations updated

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
)

Updates the requirements on
[setuptools](https://github.com/pypa/setuptools) to permit the latest
version.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/pypa/setuptools/blob/main/NEWS.rst">setuptools's
changelog</a>.</em></p>
<blockquote>
<h1>v84.2.1</h1>
<h2>Bugfixes</h2>
<ul>
<li>Changed wheel tags and stable-ABI validation to use sysconfig data.
(<a
href="https://redirect.github.com/pypa/setuptools/issues/5360">#5360</a>)</li>
<li>Fixed unimportable extensions on free-threaded Python 3.13 and 3.14
when
<code>Extension.py_limited_api</code> is enabled. These builds now use
their
version-specific extension suffix instead of using the unsupported
<code>.abi3t</code>
suffix. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5363">#5363</a>)</li>
</ul>
<h2>Improved Documentation</h2>
<ul>
<li>Replaced broken link to Python Eggs documentation with an archived
version from the Wayback Machine. (<a
href="https://redirect.github.com/pypa/setuptools/issues/1929">#1929</a>)</li>
</ul>
<h1>v84.2.0</h1>
<h2>Features</h2>
<ul>
<li>Added support for building abi3t extensions and abi3.abi3t wheels on
Python
3.15 and newer. See :pep:<code>803</code> and the <code>Python 3.15
&quot;What's New&quot; entry
&lt;https://docs.python.org/3.15/whatsnew/3.15.html#pep-803-abi3t-stable-abi-for-free-threaded-builds&gt;</code>_
for more details. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5193">#5193</a>)</li>
<li>Updated vendored packaging version to 26.3, which adds support for
the
<code>abi3t</code> tag from :pep:<code>803</code>. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5361">#5361</a>)</li>
</ul>
<h2>Bugfixes</h2>
<ul>
<li>Use target sysconfig data for stable-ABI extension filenames. (<a
href="https://redirect.github.com/pypa/setuptools/issues/5351">#5351</a>)</li>
</ul>
<h1>v84.1.0</h1>
<h2>Features</h2>
<ul>
<li><code>setuptools.archive_util</code> now raises the new
<code>UnsafeMember</code> exception when
an archive member would be extracted outside of the extraction
directory,
where previously such a member was silently skipped. Aborting makes a
malicious or malformed archive visible to the caller instead of yielding
a
quietly incomplete extraction, and matches the behavior of the
standard</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/pypa/setuptools/commit/3895f9829fc0e51882981773a823a658eb1d1636"><code>3895f98</code></a>
Bump version: 84.2.0 → 84.2.1</li>
<li><a
href="https://github.com/pypa/setuptools/commit/7c5cb7a14aaa61d5fec6144a4a08a3911257f0d2"><code>7c5cb7a</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5362">#5362</a>
from jameshilliard/fix/abi3t-target-config</li>
<li><a
href="https://github.com/pypa/setuptools/commit/00595bf726c0b813c0f5e0945bf9e5e8a0033744"><code>00595bf</code></a>
Use sysconfig data for wheel tags and stable-ABI validation</li>
<li><a
href="https://github.com/pypa/setuptools/commit/873b29c064a6981cb9764c064f6c5fe0c56b0954"><code>873b29c</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5363">#5363</a>
from ngoldbaum/fix-3.14t</li>
<li><a
href="https://github.com/pypa/setuptools/commit/d8bc01b24240f8d6418f6b2855e87a2c523f6ef4"><code>d8bc01b</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5330">#5330</a>
from Topgearfanboy/main</li>
<li><a
href="https://github.com/pypa/setuptools/commit/e27271e1b2dc4342b057c3a0ea489380ab6d5231"><code>e27271e</code></a>
Apply review comments from <a
href="https://github.com/jameshillard"><code>@​jameshillard</code></a></li>
<li><a
href="https://github.com/pypa/setuptools/commit/aa98f8596d2bb45323d4838ff48daed0578668e3"><code>aa98f85</code></a>
add newsfragment</li>
<li><a
href="https://github.com/pypa/setuptools/commit/3301fa6500c3ea286581df83c038d80d8c5f9589"><code>3301fa6</code></a>
Avoid .abi3t extension suffixes on Python 3.13t and 3.14t</li>
<li><a
href="https://github.com/pypa/setuptools/commit/301e27a484f17e175acf6b692fccc634f9a20c49"><code>301e27a</code></a>
Bump version: 84.1.0 → 84.2.0</li>
<li><a
href="https://github.com/pypa/setuptools/commit/39a7c2ecd80bb1c393b3867d9673027d490322cb"><code>39a7c2e</code></a>
Merge pull request <a
href="https://redirect.github.com/pypa/setuptools/issues/5193">#5193</a>
from ngoldbaum/abi3.abi3t</li>
<li>Additional commits viewable in <a
href="https://github.com/pypa/setuptools/compare/v61.0.0...v84.2.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-java](https://github.com/actions/setup-java) from
6.0.1 to 6.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-java/releases">actions/setup-java's
releases</a>.</em></p>
<blockquote>
<h2>v6.1.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Preserve compound Liberica build versions from .sdkmanrc by <a
href="https://github.com/brunoborges"><code>@​brunoborges</code></a>
with <a href="https://github.com/Copilot"><code>@​Copilot</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/1268">actions/setup-java#1268</a></li>
<li>Support Temurin on Linux RISC-V by <a
href="https://github.com/yawkat"><code>@​yawkat</code></a> in <a
href="https://redirect.github.com/actions/setup-java/pull/1269">actions/setup-java#1269</a></li>
<li>Stop GPG agent before removing signature-verification home by <a
href="https://github.com/brunoborges"><code>@​brunoborges</code></a>
with <a href="https://github.com/Copilot"><code>@​Copilot</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/1273">actions/setup-java#1273</a></li>
<li>Prefer Zulu 4-segment hotfix builds when resolving version ranges by
<a href="https://github.com/brunoborges"><code>@​brunoborges</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/1278">actions/setup-java#1278</a></li>
<li>Support Temurin JEP 322 patch versions like 26.0.2.1+1 by <a
href="https://github.com/brunoborges"><code>@​brunoborges</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/1279">actions/setup-java#1279</a></li>
<li>chore(deps): bump undici from 6.28.0 to 6.29.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/1274">actions/setup-java#1274</a></li>
<li>chore(deps): bump the monthly-npm-updates group with 13 updates by
<a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/1276">actions/setup-java#1276</a></li>
<li>feat: support Maven server credential origins by <a
href="https://github.com/YunaBraska"><code>@​YunaBraska</code></a> in <a
href="https://redirect.github.com/actions/setup-java/pull/1282">actions/setup-java#1282</a></li>
<li>Support Maven plugin repositories in generated settings.xml by <a
href="https://github.com/brunoborges"><code>@​brunoborges</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/1286">actions/setup-java#1286</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yawkat"><code>@​yawkat</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-java/pull/1269">actions/setup-java#1269</a></li>
<li><a
href="https://github.com/YunaBraska"><code>@​YunaBraska</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/setup-java/pull/1282">actions/setup-java#1282</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-java/compare/v6.0.1...v6.1.0">https://github.com/actions/setup-java/compare/v6.0.1...v6.1.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-java/commit/b843ebf9b913146b38da2eaa7aeddf76074ae1ad"><code>b843ebf</code></a>
Support Maven plugin repositories in generated settings.xml (<a
href="https://redirect.github.com/actions/setup-java/issues/1286">#1286</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/2a69be27b0baa8a7ec1c0ba665dc022b180664c5"><code>2a69be2</code></a>
feat: support Maven server credential origins (<a
href="https://redirect.github.com/actions/setup-java/issues/1282">#1282</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/d0e6e4dbf773b98efde945f446d2099b2c0d8fd2"><code>d0e6e4d</code></a>
chore(deps): bump the monthly-npm-updates group with 13 updates (<a
href="https://redirect.github.com/actions/setup-java/issues/1276">#1276</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/b24925bc49b74c38e5a106894c14cfd876ac1ab5"><code>b24925b</code></a>
chore(deps): bump undici from 6.28.0 to 6.29.0 (<a
href="https://redirect.github.com/actions/setup-java/issues/1274">#1274</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/47b36480ae3ac5671badb6bde2dec0c1898a1cc9"><code>47b3648</code></a>
Support Temurin JEP 322 patch versions like 26.0.2.1+1 (<a
href="https://redirect.github.com/actions/setup-java/issues/1270">#1270</a>)
(<a
href="https://redirect.github.com/actions/setup-java/issues/1279">#1279</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/74920aab4a9e7a33c5bd4fd3c8d5a7ba260ae795"><code>74920aa</code></a>
Prefer Zulu 4-segment hotfix builds when resolving version ranges (<a
href="https://redirect.github.com/actions/setup-java/issues/1278">#1278</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/a78ec39f1243adc9be41d35a49593a4c665a604c"><code>a78ec39</code></a>
Stop GPG agent before removing signature-verification home (<a
href="https://redirect.github.com/actions/setup-java/issues/1273">#1273</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/97c5a5e13aa773f277f72c1287dda3c789f1366c"><code>97c5a5e</code></a>
Support Temurin on Linux RISC-V (<a
href="https://redirect.github.com/actions/setup-java/issues/1269">#1269</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/1aa87b638dacaa70f1c903fa9ec9cbd91058e2ff"><code>1aa87b6</code></a>
Preserve compound Liberica build versions from .sdkmanrc (<a
href="https://redirect.github.com/actions/setup-java/issues/1268">#1268</a>)</li>
<li>See full diff in <a
href="https://github.com/actions/setup-java/compare/de7274f081f381c8f8158605e0321c36c376e2e6...b843ebf9b913146b38da2eaa7aeddf76074ae1ad">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/setup-java&package-manager=github_actions&previous-version=6.0.1&new-version=6.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps
[reviewdog/action-misspell](https://github.com/reviewdog/action-misspell)
from 1.28.0 to 1.30.4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/reviewdog/action-misspell/releases">reviewdog/action-misspell's
releases</a>.</em></p>
<blockquote>
<h2>Release v1.30.4</h2>
<h2>What's Changed</h2>
<ul>
<li>Do not add bump:patch label to Renovate updates under
.github/workflows by <a
href="https://github.com/shogo82148"><code>@​shogo82148</code></a> in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/106">reviewdog/action-misspell#106</a></li>
<li>chore(deps): update shogo82148/actions-create-release action to
v1.9.3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/reviewdog/action-misspell/pull/105">reviewdog/action-misspell#105</a></li>
<li>chore(deps): update debian:bookworm-slim docker digest to 99c0b25 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/107">reviewdog/action-misspell#107</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/reviewdog/action-misspell/compare/v1.30.3...v1.30.4">https://github.com/reviewdog/action-misspell/compare/v1.30.3...v1.30.4</a></p>
<h2>Release v1.30.3</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update debian:bookworm-slim docker digest to 7ff6ba3 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/104">reviewdog/action-misspell#104</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/reviewdog/action-misspell/compare/v1.30.2...v1.30.3">https://github.com/reviewdog/action-misspell/compare/v1.30.2...v1.30.3</a></p>
<h2>Release v1.30.2</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update shogo82148/actions-create-release action to
v1.9.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/reviewdog/action-misspell/pull/102">reviewdog/action-misspell#102</a></li>
<li>chore(deps): update debian:bookworm-slim docker digest to 7c7b2c9 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/103">reviewdog/action-misspell#103</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/reviewdog/action-misspell/compare/v1.30.1...v1.30.2">https://github.com/reviewdog/action-misspell/compare/v1.30.1...v1.30.2</a></p>
<h2>Release v1.30.1</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update debian:bookworm-slim docker digest to 3783cc0 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/101">reviewdog/action-misspell#101</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/reviewdog/action-misspell/compare/v1.30.0...v1.30.1">https://github.com/reviewdog/action-misspell/compare/v1.30.0...v1.30.1</a></p>
<h2>Release v1.30.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update docker/setup-buildx-action action to v4.4.0 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/97">reviewdog/action-misspell#97</a></li>
<li>chore(deps): update docker/setup-qemu-action action to v4.4.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a>[bot] in
<a
href="https://redirect.github.com/reviewdog/action-misspell/pull/98">reviewdog/action-misspell#98</a></li>
<li>chore(deps): update docker/setup-buildx-action action to v4.4.1 by
<a href="https://github.com/renovate"><code>@​renovate</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/99">reviewdog/action-misspell#99</a></li>
<li>chore(deps): update reviewdog to 0.21.2 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/100">reviewdog/action-misspell#100</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/reviewdog/action-misspell/compare/v1.29.0...v1.30.0">https://github.com/reviewdog/action-misspell/compare/v1.29.0...v1.30.0</a></p>
<h2>Release v1.29.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update reviewdog to 0.21.1 by <a
href="https://github.com/github-actions"><code>@​github-actions</code></a>[bot]
in <a
href="https://redirect.github.com/reviewdog/action-misspell/pull/96">reviewdog/action-misspell#96</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/reviewdog/action-misspell/compare/v1.28.0...v1.29.0">https://github.com/reviewdog/action-misspell/compare/v1.28.0...v1.29.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/840bfbe9f804da9afb0bd739dc4689012f3fdd2d"><code>840bfbe</code></a>
bump v1.30.4</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/f7adfdcacdf85006907c11d17c62edfa68266dbd"><code>f7adfdc</code></a>
Merge branch 'master' into releases/v1</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/1c17fc3ca4b903b577de596481aa4365503105a1"><code>1c17fc3</code></a>
Merge pull request <a
href="https://redirect.github.com/reviewdog/action-misspell/issues/107">#107</a>
from reviewdog/renovate/debian-bookworm-slim</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/f69a6daac74945c95da853c607b3e753957edcd5"><code>f69a6da</code></a>
chore(deps): update debian:bookworm-slim docker digest to 99c0b25</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/54fea886b39d94597183a4f83b70e8812bb036ac"><code>54fea88</code></a>
Merge pull request <a
href="https://redirect.github.com/reviewdog/action-misspell/issues/105">#105</a>
from reviewdog/renovate/shogo82148-actions-create-rel...</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/fb2fb9906b77c393fce65307cff35992f5b721f5"><code>fb2fb99</code></a>
chore(deps): update shogo82148/actions-create-release action to
v1.9.3</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/5880861e120a77a9e30e8379242c3a1377431556"><code>5880861</code></a>
Merge pull request <a
href="https://redirect.github.com/reviewdog/action-misspell/issues/106">#106</a>
from reviewdog/renovate-no-label-for-workflows</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/ad26c0c350ac80b230429822d5d1f0ad7d3ee547"><code>ad26c0c</code></a>
Do not add bump:patch label to Renovate updates under
.github/workflows</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/3467363dab5b42db2b1372c5fd2b1771fea2ea48"><code>3467363</code></a>
bump v1.30.3</li>
<li><a
href="https://github.com/reviewdog/action-misspell/commit/6a5fb87f98d9153207a0ea34373ab0898db8c707"><code>6a5fb87</code></a>
Merge branch 'master' into releases/v1</li>
<li>Additional commits viewable in <a
href="https://github.com/reviewdog/action-misspell/compare/ba7ac4030fa6812f8c8b2d4e516af8bc99553c32...840bfbe9f804da9afb0bd739dc4689012f3fdd2d">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=reviewdog/action-misspell&package-manager=github_actions&previous-version=1.28.0&new-version=1.30.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 7.0.1 to 7.0.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Improves artifact download retries when the service returns HTTP 429
(rate limiting), including honoring valid Retry-After headers.</li>
<li>Updates <code>@​actions/artifact</code> to v6.3.1.</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/tunc-d"><code>@​tunc-d</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/821">actions/upload-artifact#821</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v7.0.1...v7.0.2">https://github.com/actions/upload-artifact/compare/v7.0.1...v7.0.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/cf430e030ddbb5b0abf93d22962f4752f3646cd9"><code>cf430e0</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/822">#822</a>
from actions/tunc-d-prepare-upload-v7-0-2</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/c2acdedd35a8824a1552c7137f8c18288c3ea469"><code>c2acded</code></a>
chore: prepare v7.0.2 release</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/4687c1bbaa0a58abb517d90b4bbade6754c80c1a"><code>4687c1b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/821">#821</a>
from actions/tunc-d-upload-artifact-package-bump</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/8cbe1bebdb858105d8fdd88f81404d4de4595719"><code>8cbe1be</code></a>
Bump <code>@​actions/artifact</code> to 6.3.1</li>
<li>See full diff in <a
href="https://github.com/actions/upload-artifact/compare/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a...cf430e030ddbb5b0abf93d22962f4752f3646cd9">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=7.0.1&new-version=7.0.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
### Description
Raises the MLAS LinearAttention test tolerance from 1e-4 to 2e-4.

The NEON kernel uses FP32 FMA reductions and reassociates the recurrence
relative to the double-precision test oracle. On Windows ARM64,
accumulated rounding differences can slightly exceed the previous
tolerance.

### Motivation and Context
Fixes microsoft#33862

Signed-off-by: Patryk Kaiser <patryk.kaiser@arm.com>
…33690)

On Arm64 the NHWC transformer can rewrite a 1-D Conv into a float
NhwcFusedConv, but that kernel accepted only 2-D kernels and failed at
run
time with

conv.cc:269 Conv with channels_last layout currently supports 2D
kernels.

so session creation failed for every Conv1d model at ORT_ENABLE_ALL --
for
example the two kernel_shape=[3] convolutions of the Whisper encoder.
Windows
ML creates its session at ORT_ENABLE_ALL with no optimization-level
control,
so callers had no in-band way around it.

An NWC tensor [N, W, C] has exactly the memory layout of NHWC [N, 1, W,
C].
The kernel's existing layout-conversion fallback therefore handles 1-D
with a
unit height: the channels-last spatial slice, output-shape reorder,
fallback
buffer sizing and NHWC<->NCHW conversions are generalized from a fixed
four
dimensions to N + kernel_rank + C. No new compute path is added. The
NHWC fast
path stays 2-D only, gated explicitly on kernel_rank == 2, and 2-D
behavior is
unchanged.

Fixing the kernel rather than the transformer closes the failure
regardless of
which path produced the node. ValidateInputShape and ComputeKernelShape
both
run before the rejected check, so reaching it proves the failing node
held a
genuine rank-3 input and weight -- the exact state this change handles.

Tests: four new FusedConvTest cases. Stride 1 and stride 2 match the
shape
classes of Whisper's /conv1/Conv and the failing /conv2/Conv; a
fused-sum case
covers the generalized manual-sum path; and Cpu_Conv1D_NcwCrossCheck
runs the
same data through the existing NCW FusedConv so the expected values do
not
rest on one reference. Before this change the three NHWC cases fail with
the
exact message above and the cross-check passes; after it all four pass.
The
existing 2-D NHWC tests also pass, through the generalized fallback
path.
### Description
<!-- Describe your changes. -->

Adds int4/uint4 support to the WebGPU EP for the W3C WebNN
`quantizeLinear`/`dequantizeLinear` conformance (WPT) cases. Every gap
was found by WPT running on the WebGPU EP with CPU fallback disabled
(Edge Canary, RTX/D3D12).

Commits:
1. **Support int4 and uint4 in Reshape.**
- This is why the DQ cases failed. Chromium's WebNN ORT backend builds
opset-21 models. It reshapes a broadcastable scale and zero point to the
scalar or 1-D shape that (De)QuantizeLinear takes: `[1]` becomes a
scalar, and `[1,1,2,1]` becomes `[2]` for per-axis.
- The CPU Reshape kernels register only IRv9 types, which don't include
int4, so constant folding can't fold a Reshape of an int4/uint4 zero
point. WebGPU Reshape didn't claim the 4-bit types either, so the graph
failed to build.
- int8 zero points pass only because CPU folds their Reshape. The
DequantizeLinear kernel already handled int4/uint4, including odd sizes,
so it is unchanged.
- Reshape is a pure copy/view, so int4/uint4 are added from opset 21,
the first opset whose schema allows them.
2. **Add int4 and uint4 QuantizeLinear output.**
- int4/uint4 `y`/`y_zero_point` for opsets 21-22, 23, 24, 25-27 and 28.
- Each invocation packs 8 nibbles into one u32 word, with the first
element in the low nibble. Odd element counts work, and packed output
bytes are never shared between invocations.
- Results saturate to [-8, 7] / [0, 15]. The 4-bit zero point is read
from packed u32 storage and sign-extended for int4.
- Unchanged from microsoft#33683: the exact-quotient rounding, the `precision`
filter in both GetCapability paths, and the int8/uint8 WGSL. The plugin
EP looks kernels up in the same registry, so it claims the new types
without changes to `ep/ep.cc`.

Semantics and packing (two 4-bit values per byte, sign extension,
blocked quantization, saturation ranges) follow @edgchen1's unmerged
branch
[`edgchen1/webgpu_quantizelinear`](https://github.com/microsoft/onnxruntime/tree/edgchen1/webgpu_quantizelinear).
That branch refactors QL/DQ into a WGSL template plus
`quantization_utils`, but it predates microsoft#33683. This PR applies the same
semantics to main's current kernel instead of porting the refactor.

Tests are pinned to WebGPU with CPU EP fallback disabled:
- `onnxruntime/test/providers/webgpu/tensor/quantize_linear_test.cc`:
- The WPT int4/uint4 QL and DQ vectors (f32 and f16), both directly and
with the Reshape nodes Chromium inserts.
- Rounding and saturation, multi-word per-axis and blocked zero points
with odd sizes, all opsets, `output_dtype` without a zero point, and a Q
-> DQ round trip.
- `onnxruntime/test/providers/webgpu/tensor/reshape_op_test.cc`:
int4/uint4 Reshape, including to a scalar, from both an input and an
initializer.

The existing CPU `QuantizeLinearOpTest.Int4/UInt4/OddLarge_*` tests now
also run on WebGPU.

Validation (Windows ARM64, NVIDIA RTX Spark N1X / D3D12, at 50323bf):
- `onnxruntime_provider_test
--gtest_filter="WebGpuQuantizeLinearTest.*:WebGpuDequantizeLinearTest.*:TensorOpTest.Reshape*:QuantizeLinearOpTest.*:DequantizeLinearOpTest.*:QuantizeLinearOp21BlockedTest.*:QuantizeLinearOpMLFloat16Test.*:QuantizeLinearPrecisionTest.*"`:
188 tests, 184 passed, 0 failed, 4 skipped. The skips are DML-only.
- Sensitivity checks, both applied and rebuilt:
- With the Reshape 4-bit types disabled (`since_version >= 99`),
`TensorOpTest.Reshape_int4_webgpu` and
`WebGpuDequantizeLinearTest.Int4WebNNConformance_Float/Float16` fail at
session initialization, because the node lands on CPU.
`Int4PerAxisMultiWordZeroPoint`, which has no Reshape, still passes.
- With the nibble order swapped in the QuantizeLinear shader, every
`WebGpuQuantizeLinearTest.Int4*` test fails on values.
- WPT, using the plugin EP (`--use_webgpu shared_lib`) built from
50323bf with Edge Canary 159.0.4372.0 and ORT runtime 1.28.3:
  - `quantizeLinear`: 29/29 pass (was 15/29)
  - `dequantizeLinear`: 33/33 pass (was 27/33)
  - `reshape`: 67/67 pass
  - `qdq_subgraph`: 43/43 pass

### 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. -->
This fixes the WebNN conformance failures on the WebGPU EP:
- `quantizeLinear.https.any.js`, 14 subtests (f32 and f16 each):
  - int4 zeroPoint of odd size and of even size
  - 2D with int4 zeroPoint of even size
  - 2D with int4 zeroPoint and block_size = [3, 2]
  - uint4 zeroPoint of odd size and of even size
  - 1D with uint4 zeroPoint and block_size = 3
- `dequantizeLinear.https.any.js`, 6 subtests:
  - uint4 and int4 1D tensors of odd size, with f32 and f16 1D scale
- uint4 4D tensor with broadcasting f32/f16 4D scale and uint4 4D
zeroPoint

WebNN disables CPU fallback, so an unclaimed node makes the graph fail
to build.

---------

Co-authored-by: Aditya Rastogi <adityar@ntdev.microsoft.com>
Co-authored-by: edgchen1 <18449977+edgchen1@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
### Description
Disable x86-specific tests and fix
LabelEncoder.ExternalDataInKeysTensorOpset4 test on s390x.

### Motivation and Context
These changes clean up some testsuite failures on s390x.

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…icrosoft#29713) (microsoft#29792)

### Description
Fixes microsoft#29713.

On the CUDA EP, a device copy scheduled for a weight retained as an
in-memory-external `OrtValue` initializer can have a source and
destination that are the **same physical host buffer**. The host->host
branch of `GPUDataTransfer::CopyTensor`/`CopyTensorAsync` did not handle
this:

- **Non-cuda-graph:** `ORT_ENFORCE(dst_data != src_data)` fired -> hard
failure.
- **CUDA-graph capture:** the `HOST_ACCESSIBLE` `cudaStreamSynchronize`
is illegal during capture -> `CUDA 900` -> `cudaStreamEndCapture` `CUDA
901`, invalidating the capture.

This became reachable once microsoft#29158 (initializer retention) landed.

### Fix
Early-return the no-op self-copy at the top of the host->host branch in
both methods, **before** the `HOST_ACCESSIBLE` stream sync (the key to
keeping capture valid). This matches `CPUDataTransfer::CopyTensor` and
the existing GPU->GPU guard.

### Testing
Adds a CUDA EP internal regression test (`gpu_data_transfer_test.cc`)
covering sync, async, and cuda-graph-capture self-copies. Verified
failing before the fix (ORT_ENFORCE / CUDA 900->901) and passing after,
on an RTX 3050 with a CUDA 12.8 `sm_86` build.

---------

Co-authored-by: Trisha-sarvam <trishawadhwani@sarvam.ai>
Co-authored-by: Cursor <cursoragent@cursor.com>
### Description
<!-- Describe your changes. -->

Remove ACL EP code.

### 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. -->

The ACL EP was already deprecated. Following up with the removal.

### Release notes draft

```
Removed the deprecated ACL (Arm Compute Library) execution provider, including its build options and standalone C registration API.

Python's `get_all_providers()` no longer lists `ACLExecutionProvider`. Applications should remove this name from explicit provider lists. Requests containing it now follow unknown-provider handling: the default `InferenceSession` constructor can retry with fallback providers (usually CPU), while `set_providers()` or construction with fallback disabled raises an error.
```

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…NT3 cold experts (microsoft#33916)

## Summary

This PR fixes Windows WDDM and bounded-host-cache issues in QMoE CPU/GPU
offload, adds tail-expert probability threshold pruning
(`session.moe.offload.min_expert_weight`), and optimizes prefill and
decode throughput for mixed-precision (`INT4` / `INT3` / `INT2`) QMoE
models on consumer GPUs (e.g., RTX 4090 `24 GB` VRAM + `30 GiB` RAM):

1. **Fix Windows `FileExpertStore::InitializeMapped` &
`QMoEOffload::InitializeBoundedHostCache` (`qmoe_offload.h`,
`qmoe_offload.cc`, `qmoe_shared_layout.cc`)**:
- Propagate `external_file_path` and `external_file_offset` from
`MoeExpertSourceDescriptor` into
`QMoEOffload::InitializeBoundedHostCache()`.
- On Windows (`#elif defined(_WIN32)` in
`FileExpertStore::InitializeMapped`), accept committed `MEM_MAPPED` (or
`read_opt_enabled`) mappings via `VirtualQuery` when `source.file_path
== nullptr`.
2. **Fix pinned memory budget accounting & persistent decode pinned
starvation (`qmoe_offload.cc`)**:
- Add `SessionPromotionBudget::HeldBytes()` and compute `reserved =
bounce_held + std::max(decode_held, reserve_target)` in
`QMoEOffload::ComputeShared` so promotion bounce allocations (`16 MiB`)
are not conflated with persistent decode headroom (`24 MiB`).
- In `QMoEOffload::EnsurePersistentDecodeState`, release idle promotion
bounce and landing-ring pinned staging when
`try_reserve_decode_pinned()` needs headroom.
3. **Automatic machine-aware session planning
(`qmoe_session_controller.h`)**:
- On Windows hosts where `ullTotalPhys < host_expert_bytes + 24 GiB`,
automatically prefer direct OS file-backed mapping
(`use_bounded_file_cache = false` unless
`ORT_QMOE_FORCE_BOUNDED_HOST_CACHE=1`), avoiding multi-GiB private heap
commits and enabling 2-bank parallel pinned wave staging.
- For full-model sessions (`num_layers >= 24`, `total_vram >= 16 GiB`,
`total_full_gpu_bytes >= 8 GiB`), automatically raise implicit
`device_working_bytes` to `560 MiB` and implicit `pinned_bytes` to `160
MiB`, and adapt `admitted_gpu_expert_budget` against
`platform_free_vram` (DXGI local budget) and `SessionBudgetAccount`
without spilling into WDDM non-local shared memory.
- Enable `EvictUploadedHostPages` (`VirtualUnlock`) on Windows
`MEM_MAPPED` views.
4. **8K single-tile streaming prefill, 2-bank double-buffered wave
staging, and default Windows `PrefetchVirtualMemory`
(`qmoe_offload.cc`)**:
- Default `stream_rows` to `8192` across `INT2`, `INT3`, and full-budget
`INT4` layers.
- Automatically halve `wave_experts` (`32 -> 16`) in `ComputeShared`
when needed so `INT3` layers fit `stage_weight_banks = 2` (full
double-buffered CPU staging + PCIe H2D DMA + GPU Tensor-Core GEMM
overlap).
- Extend `ORT_QMOE_WIN_PREFETCH_MMAP` (default `1` on Windows) to all
file-mapped integer-bank layers.
5. **Tail-Expert Probability Threshold Pruning
(`session.moe.offload.min_expert_weight`, `qmoe_kernels.cu`,
`moe_kernels.cu`, `qmoe_offload.cc`)**:
- Add `kOrtSessionOptionsMoeOffloadMinExpertWeight`
(`session.moe.offload.min_expert_weight`, env fallback
`ORT_QMOE_MIN_EXPERT_WEIGHT`) to skip non-top-1 routed experts (`rank >=
1`) whose probability after `SoftmaxTopK` is strictly below
`min_expert_weight` (`topk_scales[route] = 0.0f`, `topk_indices[route] =
-2`), always keeping at least the top-1 expert (`rank == 0`).
- Support `ORT_QMOE_SKIP_TAIL_COLD_ONLY=1` to retain GPU-resident (`slot
>= 0`) tail experts during decode at zero wall-time cost while pruning
only CPU-cold (`slot < 0`) tail experts inside
`QMoEOffloadClassifyKernel`.
- Skip zero-weight routes in `QMoEOffloadMergeFinalizeCombineKernel` and
`finalizeMoeRoutingKernel` without reading uninitialized contribution
rows, and skip `input_dev -> host_input_out` PCIe copies in
`QMoEOffloadClassifyKernel` when `has_doorbell && cold_count == 0`.
6. **CPU AVX2 `INT2` / `INT3` cold-expert & `SM89` dense `INT8`
Tensor-Core GEMV optimizations (`qmoe_shared_layout_int2_avx2.cc`,
`qmoe_shared_layout_int3_avx2.cc`, `dispatcher.h`,
`paged_attention_impl.cu`)**:
- Add 8-column `Int2Group8PrepackedAvx2` so all 8 columns of each
128-byte SM80 interleaved tile share one activation load while scaling
weights before products.
- Hoist activation vector loads outside `step_col` in `Int3Group4Avx2`
and implement a true 8-column `Int3Group8Avx2`.
- Enable `CanUseInt8TensorCore` on `params.device_sm >= 89` (`SM89`) and
fix MSVC `/WX` `C4459` variable shadowing in `paged_attention_impl.cu`.

## Testing

- `test_qmoe_offload_v4.py` targeted unit tests: **PASS**.
- End-to-end Qwen3.8-Flash-Next RC5
(`qwen_flash_next_int4_int8_rc5_contrib_dflash2_qmoe_2b375_x02_y14_z32_dp23_b64`)
benchmarks on RTX 4090 (`24 GB` VRAM) + Intel i9-13900 (`30 GiB` RAM):
- **`2K` (`2,048` tokens)**: TTFT `8.92 s` (`7.55 s` at
`min_expert_weight=0.08`), decode `12.15–23.43 tok/s` (`24.63–29.63
tok/s` with `min_expert_weight=0.065–0.08`).
- **`8K` (`8,192` tokens)**: TTFT `14.42–15.32 s` (`10.84–12.30 s` with
`min_expert_weight=0.065–0.08`), decode `23.04 tok/s` median / `29.49
tok/s` peak.
- **`32K` (`32,768` tokens)**: TTFT `71.71–73.16 s`, decode `8.22–9.48
tok/s`.
- **`128K` (`131,072` tokens)**: TTFT `536.21–579.64 s`, decode
`7.42–15.27 tok/s`, peak VRAM `21,345 MiB`.
  - **100-Sample MMLU-Pro (`shard 0 of 8`, `max-new 8192`)**:
- Default (`min_expert_weight=0`): **86/100 (`86.0%`)**, `0` truncated,
**`27.39 tok/s` aggregate decode** (`3,196 s` wall time).
- Tail-skip (`min_expert_weight=0.065`, `skip_cold_only=1`): **84/100
(`84.0%`)**, `0` truncated, **`34.70 tok/s` aggregate decode** (`43.21
tok/s` max, **`2,099 s` wall time**; `43.10 tok/s` avg / `53.42 tok/s`
max at `0.080` on 20-item subset).

---------

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

Allow native WebGPU hosts to persist Dawn shader/pipeline blobs without
supplying their own device or relying on a global cache bridge.

- Add a versioned public `OrtDawnCacheInterface` and the
`dawnCacheInterface` provider option.
- Attach host load/store callbacks and an optional isolation key when
ORT creates the Dawn device, with bundled or external Dawn.
- Validate trusted in-process pointer configuration, callback
availability, interface version, external-device incompatibility, and
shared-context interface identity.
- Defer shared allocator context acquisition until first allocation,
retaining the configured context for the allocator lifetime.
- Serialize default-context acquisition and configured creation under
one mutex, eliminating the lookup/fallback race without weakening
explicit cache-identity checks.
- Document ownership, thread safety, configuration order, and the
companion GenAI requirement; add isolated configuration regression tests
that handle exceptions and no-exceptions builds.
- Exercise real cache callbacks through bundled Dawn, external Dawn, and
the dynamic WebGPU plugin, including cold stores, warm hits, and
isolation-key separation.

The interface caches compiled shaders/pipelines, not model weights.
Existing accelerated weight loading continues to use the ORT-owned
device.

Companion GenAI draft:
microsoft/onnxruntime-genai#2893.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
rui-ren and others added 26 commits November 12, 2026 21:33
…soft#34002)

## Description

Optimizes the existing CUDA MatMulPacked and IQ2_XXS MoEPacked paths
without changing
operator schemas, packed-weight layouts, or exported graphs. NVFP4 uses
vectorized
group decoding, paired BF16 operands, and half-chunk staging for
eligible large-N
Hopper projections. Q8 uses aligned packed-record windows with
stride/alignment
fallbacks; dense IQ2 reconstructs complete BF16 operands using the
original K partitions.

IQ2 experts use exact magnitude-codebook reconstruction and
launch-selected aligned
FC1 activation loads. FP32 scale reconstruction, sign-before-BF16
rounding, FC1/FC2
warp partitions, ReLU-square boundaries, and final reduction order are
preserved.
The shared LoadPacked8 fallback from the standalone-router extraction is
reused.

**Dependency:** microsoft#33994 in
[native stack
#33967](https://github.com/microsoft/onnxruntime/stack/33967).
Mamba and standalone/integrated routing are unchanged. No
requantization, GenAI
inference change, graph conversion, or acceptance-threshold adjustment.

## Summary of Changes

### Packed Projection and Expert Kernels

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh` | Add
vectorized NVFP4/Q8 loads and dense IQ2 BF16 operand reconstruction. |
| `onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu` | Select
eligible optimized paths while retaining architecture/alignment
fallbacks. |
| `onnxruntime/contrib_ops/cuda/moe/moe_packed_iq2.cuh` | Add IQ2 expert
codebook/operand helpers with exact FP32 scale reconstruction. |
| `onnxruntime/contrib_ops/cuda/moe/moe_packed.cu` | Use the expert
helpers and aligned FC1 activation-load specialization. |

### Regression Tests

| File | Change |
|------|--------|
| `onnxruntime/test/contrib_ops/matmul_packed_precision_test.cc` | Cover
production projection widths, NVFP4 operand extremes, Q8 record
windows/stride fallback, and IQ2 complete operands. |
| `onnxruntime/test/contrib_ops/moe_packed_routing_test.cc` | Add
production-width and IQ2 codebook/scale reconstruction cases. |
|
`onnxruntime/test/contrib_ops/cuda_kernels/matmul_packed_kernel_test.cc`
| Pin the compiled TC contiguous-128-K reduction for small/staged NVFP4
paths. |
| `onnxruntime/test/python/transformers/test_gguf_packed_ops.py` |
Exercise default-rounded byte-offset IOBinding fallbacks without a model
precision attribute. |

## Testing

**Session-policy compatibility update:** head
`6294c1fd47b493fc5dbbbed6cfad3cc406ca476e`, rebased onto
the default-rounded MatMulPacked contract from microsoft#33962. The removed node
attribute is no
longer emitted by test model factories or assigned through internal
launch parameters.
Default numerical references round weights for both activation dtypes
and every dispatch.

**Validation at optimized stack tip
`a3f2076b65e0d1a5c7e9b82165ffab014e233876`:** 15 native CUDA + 15
compute75-only PTX projection tests, 5 Python format/policy/alignment
tests, and 1 actual
internal CUDA contiguous-128-K cancellation test; zero failures/skips.
CLANGFORMAT,
Ruff/format and whitespace checks pass.

These are focused ABI-matched overlays with fresh changed objects, **not
a clean full-source
build, full CI, performance remeasurement, or new full-model
qualification**. The previous
broader review qualification and historical performance results are
preserved below.

<details>
<summary>Historical measurements and qualification evidence (not
current-head acceptance)</summary>

### Earlier review qualification (historical)

**Review-fix snapshot:** `74847ad6021d5b5431fa5984efb7fa95f6a310cd`.

Added offset-buffer IOBinding fallbacks (NVFP4/Q8 and IQ2 ReLU-square
MoE), nonuniform single-product and bitwise 8-vs-9-row MoE oracles,
all-256-position IQ2 one-hot coverage, NVFP4 high-nibble coverage and an
actual internal contiguous-128-K cancellation regression. Removed
duplicate IQ2 table/decoder logic and dead branches; lowered the
operand-extremes fixture gate to SM80. Seven wrong-mapping mutations
produce nonzero output differences in the new oracle.

**Owning-layer validation:** 20 C++ + 2 Python IOBinding + 1 actual
internal CUDA cancellation test; zero failures/skips.

**Integrated tip regression:** 51 C++ provider/schema tests, 5 actual
internal CUDA tests and 2 Python IOBinding tests passed, zero
failures/skips. All owning-layer provider cases are retained. The final
overlay recompiles the changed CUDA/host/schema/test sources over
ABI-matched preserved ORT support; **not a clean full-source build,
full-CI approval, independent HF parity or new end-to-end
qualification**. Targeted configured clang-format/Ruff and whitespace
checks passed.

These previously reported results are retained for provenance. They have
not been rerun on the rebased head above; earlier CI/build status and
benchmark results do not establish current-head CI, accuracy, or merge
readiness.

Original comparison pins: parent microsoft#33994 at
`a8ff5642f5c85519561964928006413a4fde7859`; candidate
`1b5063c4af651e12bf955bc978c9312e2734a9f9`.

**This is the actual stack-tip comparison**, not the earlier
private-branch
versus microsoft#33940 comparison. That distinction matters: the remote stack tip
did
not yet contain the optimized native kernels.

| Input tokens | Stack ordinary tok/s | Candidate ordinary tok/s | Stack
k=7 tok/s | Candidate k=7 tok/s |
|---|---:|---:|---:|---:|
| 178-254 | 54.36 | **92.42** | 223.84 | **355.42** |
| 427-932 | 54.20 | **92.08** | 185.24 | **293.62** |
| 1028-1663 | 54.25 | **92.04** | 201.48 | **318.91** |

Approximately **70% ordinary** and **58-59% k=7** improvement in this
controlled
comparison. This does not claim that all remaining latency is resolved.
The separate microsoft#33940 equivalent-package result of approximately 109
ordinary /
370 k=7 tok/s on the longest bin is **not** a measurement of this
candidate;
transferring that remaining gain is still outstanding.

Protocol: original frozen 30 real prompts, ten per bin, unchanged
warmups and
per-prompt mode order, natural EOS/512-new-token cap, two reversed-order
passes,
same physical H100 per baseline/candidate shard. Eight logical shards
ran in
waves over GPUs 1,3,4,5,6,7. All admitted runs passed the foreign-client
and
resource guards. No profiler ran in the timing window; clocks were not
locked.
Rates pool decoded tokens over elapsed decode time, excluding the first
token,
not arithmetic means of per-request TPS.

## Correctness and build validation

- Exact same native model package, packed bytes and GenAI libraries in
both arms.
Graph hashes match the preserved source-value audit; full package-file
hashes
  were recorded again. No exported checkpoint/package was modified.
- **22 native CUDA regressions passed, zero skips**, covering
projections,
complete operand rounding/cancellation, IQ2 production widths/codebook
scales,
routing and the standalone router. Changed C++ files passed CLANGFORMAT;
  git whitespace checks passed.
- **1,782 complete live tensor/state hashes per arm**, bitwise equal and
finite
in ordinary and k=7 modes, also equal to the preserved quantized
control.
- Independent full LCB145 ordinary/k=7 probes passed all **512 generated
tokens**
  and complete counters.
- The accepted timing run passed **240 complete measured generation
sequences**
against frozen ordinary-control tokens. Within-mode complete speculative
  counter dictionaries matched between arms and repeats.
- Isolated incremental rebuild on the archived clean microsoft#33994 build; every
affected compilation unit/header dependent was rebuilt and the
provider/test
binary relinked with the production flags. Untouched objects were
reused:
  **this is not a new clean full-source build**.
- CUDA 12.8.93, driver 580.159.04, H100 80GB. Common corrected GenAI
source:
  `c0fd01914265d5157d6da1376c38b4df521a76c5`

([microsoft/onnxruntime-genai#2916](microsoft/onnxruntime-genai#2916)).
Both arms use that same source; its correctness fix is not credited with
the
  kernel speedup.

Accepted statistics SHA256:
`0b9b7e2385b2dd9d7e5f7d459c65ef74338b5f707d1536454e7e27fb9a407c0f`.

</details>

## Checklist

- [x] Review feedback addressed with focused regressions
- [x] Documentation and supported contracts updated
- [x] Native stack order and immediate-parent dependencies preserved
- [ ] Clean full-source/full-CI qualification (not claimed by focused
overlays)


### Python IQ2 alignment regression correction

Commit `f6e5af95c1` migrates
`test_moe_packed_relu_iq2_aligned_input_fallback` from the removed
seven-input compact-routing interface to six-input full-score routing:
`[X, R, G, "", D, W]`, with FP32 selection scores and mixing values.
Explicit `normalize_routing_weights=0`, buffer offsets and the exact
bitwise oracle remain unchanged. No production code changes.

The original test was reproduced failing graph resolution (7 inputs;
schema maximum 6). The corrected actual Python unittest passed on H100
with zero skips, including all four combinations of rows 8/9 and
activation offsets 0/2. Profiles confirm four
`CUDAExecutionProvider/MoEPacked` executions. Ruff lint/format and
whitespace checks passed.

This run used the retained six-input full-score ORT 1.32.0 runtime built
from `3bf5237cd65131701f2fb05435774672afaf1f96`; it is not a fresh
runtime build of this PR, a full Python suite, or full CI approval. The
corrected test file is byte-identical in the synchronized microsoft#34003 head.

---------

Signed-off-by: rui-ren <ruiren1225@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b
…osoft#34003)

## Description

Reduces CUDA packed decode tile/loader overhead above microsoft#34002. Narrows
eligible
eight-row IQ2 FC1 tiles, adds aligned record-window reconstruction for
eligible
IQ2 FC2 rows, and uses full-tile NVFP4 paths only when their
shape/alignment guards
hold. Unsupported geometries retain the existing fallback.

**Dependency:** microsoft#34002 in
[native stack
#33967](https://github.com/microsoft/onnxruntime/stack/33967).
No schema, packed layout, cache/mask precision workaround, or GenAI
source change.
The R8-prefill/R1-ordinary hybrid session/package work is in the
companion
microsoft/onnxruntime-genai#2916, **not implemented by this
native-kernel PR**.

## Summary of Changes

### Packed Decode Specializations

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cuda/moe/moe_packed.cu` | Select narrower FC1
tiles and eligible aligned FC2 loader variants. |
| `onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh`,
`onnxruntime/contrib_ops/cuda/moe/moe_packed_iq2.cuh` | Reuse the shared
IQ2 decoder for aligned word windows, including two-byte-offset records.
|
| `onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu` |
Specialize eligible full NVFP4 output tiles while preserving guarded
fallbacks. |
| `onnxruntime/test/contrib_ops/moe_packed_routing_test.cc` | Exercise
eight-row width/routing boundaries and larger intermediate widths. |

## Testing

**Review-fix snapshot:** `ed6e6e1991fd944f65f1d97472d3f29046d97361`.

Bound aligned-window FC2 to four resident CTAs, kept the R8-specific
narrow FC1 gate decode-only (`!use_prefill_tiles`), simplified the FC2
guard to its real row/base alignment invariant, and reused the lower
shared decoder. Nonuniform regression protection is introduced in
microsoft#33963/microsoft#34002. Mamba replay changes were moved into their owning PR
microsoft#33969; this layer no longer changes Mamba numerics or tests.

**Owning-layer validation:** Integrated stack regression run and
exact-production-kernel H100 A/B below.

**Integrated tip regression:** 51 C++ provider/schema tests, 5 actual
internal CUDA tests and 2 Python IOBinding tests passed, zero
failures/skips. All owning-layer provider cases are retained. The final
overlay recompiles the changed CUDA/host/schema/test sources over
ABI-matched preserved ORT support; **not a clean full-source build,
full-CI approval, independent HF parity or new end-to-end
qualification**. Targeted configured clang-format/Ruff and whitespace
checks passed.

### Review-requested kernel A/B (H100, CUDA 12.8.93)

Exact production kernel/helper text from the integrated head; random
nonuniform IQ2, 512 experts, 16 rotating route sets, R=8. All variant
outputs are bit-identical across all route sets. CUDA-event median: 20
warmups, 9 alternating batches x32 launches; no full-model/cold-cache
guarantee. `k=9` is decode, `k=17` is four-subtile prefill; the latter
remains excluded from the narrow dispatch.

| Hidden | Inter | k | FC1 wide→narrow μs | FC2 plain / window / hinted
μs |
|---:|---:|---:|---:|---:|
| 1024 | 1024 | 9 | 15.035 → 10.888 | 12.874 / 11.966 / 12.062 |
| 1024 | 1024 | 17 | 16.264 → 14.610 | 18.149 / 15.968 / 16.188 |
| 1024 | 2048 | 9 | 18.041 → 15.920 | 21.786 / 20.282 / 20.458 |
| 1024 | 2048 | 17 | 26.279 → 23.879 | 32.182 / 28.613 / 28.801 |
| 2048 | 1024 | 9 | 27.187 → 18.500 | 20.663 / 19.135 / 19.234 |
| 2048 | 1024 | 17 | 28.614 → 25.400 | 29.040 / 25.962 / 26.176 |
| 2048 | 2048 | 9 | 31.466 → 27.515 | 34.251 / 32.346 / 32.446 |
| 2048 | 2048 | 17 | 48.462 → 42.877 | 51.977 / 45.898 / 46.270 |
| 4096 | 1024 | 9 | 49.654 → 32.181 | 30.966 / 29.015 / 29.088 |
| 4096 | 1024 | 17 | 53.387 → 46.004 | 50.201 / 45.097 / 45.371 |
| 4096 | 2048 | 9 | 57.550 → 50.024 | 53.390 / 50.104 / 50.318 |
| 4096 | 2048 | 17 | 91.847 → 79.396 | 90.444 / 80.277 / 80.838 |

The local 12.8 compiler **did not reproduce** the reported
79-register/3-CTA window allocation: unhinted and hinted window kernels
both use 64 registers/4 CTAs here. The selective hint is retained as a
portability cap for the reviewer's newer-toolchain result, with its
local timing tradeoff shown rather than hidden. These kernel-only
measurements do not attribute the older hybrid end-to-end gains below to
the later narrow-tile commit.

<details>
<summary>Historical measurements and qualification evidence (not
current-head acceptance)</summary>

These previously reported results are retained for provenance. They have
not been rerun on the rebased head above; earlier CI/build status and
benchmark results do not establish current-head CI, accuracy, or merge
readiness.

The following results include the companion GenAI runtime and hybrid
package, not just this PR's native kernel changes. They use the original
pinned binaries and package hashes below, not the current rebased ORT
head.

**Unprofiled frozen real30, six H100s, two reversed same-GPU passes, 240
complete measured
generations; original warmups, mode order, EOS/512 cap.**

| Actual input tokens | Before ordinary tok/s | Hybrid ordinary tok/s |
Gain | Original R8/k7 tok/s |
|---|---:|---:|---:|---:|
| 178-254 | 94.40 | 119.95 | +27.1% | 361.46 → 361.57 |
| 427-932 | 94.01 | 119.59 | +27.2% | 298.68 → 298.94 |
| 1028-1663 | 93.89 | 118.90 | +26.6% | 324.25 → 324.31 |

Ordinary TTFT medians: short 357.35→359.00ms, medium 826.97→831.29ms,
long 2153.15→2161.92ms. The earlier static-R1 version's prefill
regression is **not**
the package being qualified here.

Separate same-GPU synthetic-2048 CUDA profiles, 64 captured target
passes:
IQ2 expert work **3.259→1.496ms/pass**, Mamba **0.824→0.423ms/pass**.
These are device-work attribution, not an additional throughput claim.

**Correctness:** all240 exact same-mode sequences and complete counters
match;
388 complete live committed-state boundaries (66.43GB compared), capture
off/on,
two resets, prefix through130; original R8 ordinary/k7 retains1782
complete finite
tensor hashes. Three native kernel tests, seven Mamba operator tests,
fifteen
GenAI tests execute without skips. The new replay test also passes CUDA
memcheck
with zero errors (100 repetitions).

**Scope:** hybrid is ordinary-only. Both speculative arms use the
original R8 package.
The benchmark explicitly keeps two per-mode models resident in each arm;
it is not
a unified hybrid-speculative package or a k7 speedup. No
precision/cache/mask workaround,
no weight repack, no independent HF rerun, no clean-build/full-CI claim.

Reproduce the exact tested graph/config with:
```bash
python examples/python/nemotron-bolt-hybrid.py --input <packed-r8> --output <fresh-same-filesystem-hybrid>
```
Requires onnx-ir/numpy/ml-dtypes and both updated runtimes.
External-data validation
stays enabled; payloads are hardlinked inside the output package, not
copied.

Pins:
- ORT: `0357a7dfe47d3c383bf36be62015162b6a612d5e`
- Compiled/common GenAI: `d73a6e627d6d20a5a1688b9fbd46237069a7be89`
- Published GenAI: `db6ffd29fc96e319f645ff461efa05c643235f29`
(converter/docs-only child)
- CUDA provider:
`fac33c75d0336236736aa96456268057b628d93d0b9901d49598e275bf335275`
- GenAI shared library:
`f977660a408bc0a01a31151c7280282ba443fa256785680ae3e841654eec9be7`
- Tested hybrid graph:
`aaf5d6ae06b6740ab5b3af523359581930d2b6c42c38a18529a22737c2cfe530`
- Config:
`77f2d920d2b04e17884c3d2ee691d9053225b957c047454ebd0a4ea3649dac44`
- Unchanged packed payload:
`06d3d508e8d11235d0b770484b6b59764c2f297c3383b6d0de75648d26c11867`

Full commands, per-case exact tokens/counters, raw kernel traces,
provider maps,
UUID/admission receipts, and rejection evidence remain on the validation
host under
`/opt/bolt-runtime-fixes-20261108-v1/evidence/ordinary-r1-v1`. Sealed
manifest SHA256:
`412b3898f09565557b01e82906358f017f9df3227db2bf330850245a52d32bbc`.
Root-disk binaries were reloaded and verified with full ordinary/k7
generation;
the large model payload still resides on the existing tmpfs, not
reboot-persistent.
Original package/deployment untouched; no merge.

</details>

## Checklist

- [x] Review feedback addressed with focused regressions
- [x] Documentation and supported contracts updated
- [x] Native stack order and immediate-parent dependencies preserved
- [ ] Clean full-source/full-CI qualification (not claimed by focused
overlays)

---------

Signed-off-by: rui-ren <ruiren1225@gmail.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f4d0e1a3-a389-4cc8-9c85-0fd0e3ffce5b
…ron Bolt (microsoft#34147)

## Description

This PR stacks on top of microsoft#34003 to close the remaining prefill and
decode latency gap between native `com.microsoft` contrib ops
(`MoEGroupRouter`, `MoEPacked`, `MatMulPacked`) and the `v11_gguf`
custom-op baseline on the 88-layer `NVIDIA-Nemotron-3.5-Bolt-74B-A9B`
model (`rc7`). It extends `MoEPacked` and `MatMulPacked` with optional
fusion attributes (`routed_scaling_factor`, `routing_epsilon`,
`activation_type`) so per-layer Top-K routing normalization/scaling and
shared-expert ReLU² epilogues fuse directly into the operator kernels,
and optimizes the CUDA `MoEGroupRouter`, `MoEPacked`, and `MatMulPacked`
kernels on Hopper (`sm_90`).

## Summary of Changes

### Operator Schema & Documentation

| File | Change |
|------|--------|
| `onnxruntime/core/graph/contrib_ops/contrib_defs.cc` | Add
`routed_scaling_factor` (`FLOAT`, default `1.0`) and `routing_epsilon`
(`FLOAT`, default `0.0`) to `com.microsoft::MoEPacked(1)`, and
`activation_type` (`STRING`, default `"none"`, supporting `"none"`,
`"relu2"`/`"relu_squared"`, `"silu"`) to
`com.microsoft::MatMulPacked(1)`. |
| `docs/ContribOperators.md` | Update generated contrib operator schema
documentation for `MatMulPacked` and `MoEPacked`. |

### CUDA Kernel Optimizations

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cuda/moe/moe_group_router_impl.cu` | Fuse
`AddSelectionBiasKernel` into `SigmoidScoresKernel`,
`SigmoidScoresR8Kernel`, and `SigmoidLogitsKernel` (eliminating 40
separate kernel launches per step); add `SigmoidScoresR8Kernel<CudaT,
kAligned>` (`<<<experts, 128>>>`, 4 warps splitting `K`) so `rows == 8`
speculative verify reads `projection_weight[e, :]` once for all 8 rows
(`11.89 us -> 5.76 us/layer`). |
|
`onnxruntime/contrib_ops/cuda/moe/moe_packed.h`<br>`onnxruntime/contrib_ops/cuda/moe/moe_packed.cc`<br>`onnxruntime/contrib_ops/cuda/moe/moe_packed.cu`
| Fuse `(selected_weight / (sum + routing_epsilon)) *
routed_scaling_factor` into `FullScoreRoutingKernel` and
`FullScoreRoutingGenericKernel`; launch 1 warp/CTA (`<<<rows, 32>>>`)
when `rows <= 64` (`18.18 us -> 9.81 us/layer`); hoist weight row
pointers and use 2-byte aligned `LoadIq2SubBlock16Stage` +
`DecodeIq2StageToBf16` with `__launch_bounds__(KW * 32, ...)` in
`MoEPackedReluIq2ContiguousKKernel` across all `K` (including `K=1280`
5-block FC2). |
| `onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh` | Add
`LoadIq2SubBlock16Stage<kAlignedU16>` and `DecodeIq2StageToBf16` (using
`bf16x2` sign-mask bit injection before FP32 scale multiplication and
single `bfloat162` rounding) and `LoadQ8SubBlock16AlignedStage` +
`DecodeQ8StageToBf16` to eliminate intermediate float arrays and reduce
register pressure. |
|
`onnxruntime/contrib_ops/cuda/quantization/matmul_packed.h`<br>`onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cc`<br>`onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu`
| Add `activation_type` epilogue fusion (`ApplyMatMulPackedActivation`)
across Tensor Core, GEMV, and prefill paths, and use
`LoadIq2SubBlock16Stage`/`DecodeIq2StageToBf16` and
`LoadQ8SubBlock16AlignedStage`/`DecodeQ8StageToBf16` (`Q8_0` LM head
`310.8 us -> 266.3 us`, `IQ2_XXS` `sh_dn` `19.30 us -> 14.77 us`). |

### Unit Tests

| File | Change |
|------|--------|
| `onnxruntime/test/python/transformers/test_gguf_packed_ops.py` | Add
`test_matmul_packed_activation_types`,
`test_moe_packed_routed_scaling_factor_and_routing_epsilon` (including
`inter_size=1280` 5-block IQ2_XXS), and
`test_moe_group_router_r8_and_fused_bias`. |
| `onnxruntime/test/contrib_ops/matmul_packed_precision_test.cc` | Add
`ActivationTypeRelu2AndSiluAcrossDispatchPaths`. |
| `onnxruntime/test/contrib_ops/moe_packed_routing_test.cc` | Add
validation tests for nonfinite `routed_scaling_factor` and
negative/nonfinite `routing_epsilon`. |

## Motivation and Context

On NVIDIA H200 (`sm_90`, CUDA 13.0) with
`NVIDIA-Nemotron-3.5-Bolt-74B-A9B` (`rc7`, 88 layers, `k=7` MTP verify
`rows=8`, CUDA graph enabled):

| Metric | `rc7` Baseline (PR microsoft#34003) | `rc7` + This PR | `v11_gguf`
Custom Ops | Delta vs PR microsoft#34003 |
|---|---:|---:|---:|---:|
| **ONNX Graph Nodes** | 2,912 | **1,272** | 1,155 | **-1,640 nodes
(-56.3%)** |
| **CUDA Graph Kernel + Memcpy Launches / Round** | 2,009 | **729** |
690 | **-1,280 launches (-63.7%)** |
| **`nsys` CUDA Graph Replay GPU Time / Round** | 16.562 ms | **12.408
ms** | 11.596 ms | **-4.154 ms (-25.1%)** |
| **MMLU-Pro 200 Accuracy (`k=7`)** | 119/200 (59.50%) | **121/200
(60.50%)** | 119/200 (59.50%) | **+1.00%** |
| **Prefill Throughput (`500` prompts, `k=7`)** | 536.5 tok/s | **729.3
tok/s** | 685.6 tok/s | **+35.9% (+6.4% vs `v11_gguf`)** |
| **Decode Throughput (`k=7`, normal EOS)** | 268.88 tok/s | **349.91
tok/s** | 378.89 tok/s | **+30.1%** |
| **Decode Throughput (`k=7`, `--disable-eos`)** | 304.67 tok/s |
**394.65 tok/s** | 428.88 tok/s | **+29.5%** |
| **Decode Throughput (`k=0`, no MTP)** | 77.60 tok/s | **106.10 tok/s**
| 109.76 tok/s | **+36.7% (96.7% of `v11_gguf`)** |

## Testing

- Ran `onnxruntime/test/python/transformers/test_gguf_packed_ops.py` on
H200 (`sm_90`), including all existing and newly added `MatMulPacked`,
`MoEPacked`, and `MoEGroupRouter` tests.
- Validated MMLU-Pro 200 accuracy (`121/200 = 60.50%`), prefill (`500`
prompts), and decode (`100` prompts, `k=7` and `k=0`) on
`NVIDIA-Nemotron-3.5-Bolt-74B-A9B` (`rc7`).

## Checklist

- [x] Tests added/updated
- [x] No breaking changes (all new attributes have backward-compatible
defaults)
- [x] Documentation updated (`docs/ContribOperators.md`)

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

### Description
Make the min-blocks-per-SM hint architecture-conditional via
`__CUDA_ARCH__`,
which nvcc redefines on each per-architecture device-code compilation
pass.
Below SM89 the hint drops to `1` (a no-op occupancy hint on dead code);
at
SM89+ it stays `3`, preserving the residency-pinning behavior from
microsoft#32433
unchanged.

No behavior change on SM89+. No currently-selected shape or dispatch
path is
affected outside of fixing compilation for pre-Ada targets.

### Motivation and Context
`MatMulBlockScaledFp8MmaGemvKernelPinned` (added in microsoft#32433) carries
`__launch_bounds__(32 * KSplit, 3)`. For the only instantiation that's
ever
launched (`KSplit = 16`), that's `__launch_bounds__(512, 3)`, which
requires
512 * 3 = 1536 threads resident per SM.

`Fp8MmaGemvPinsResidency` in `matmul_block_scaled_fp8_tiling.h` gates
this
entry point to SM89+ (Ada), where the max resident threads/SM is exactly
1536 — the intended fit. But nvcc still codegens the template
instantiation
for every architecture passed to `--generate-code`, and on Turing
(`sm_75`,
max 1024 threads/SM) 1536 exceeds the hardware limit. `ptxas` rejects
it:

```
ptxas error : Value of threads per SM for entry ...MatMulBlockScaledFp8MmaGemvKernelPinned... is out of range. .minnctapersm will be ignored
ptxas fatal : Ptx assembly aborted due to errors
```

This breaks any build that includes `sm_75` in its target architectures,
even though the kernel is unreachable there at runtime.

Note that Nvidia T4 (entry-level GPU available in AWS and GCP) is sm_75.

### Tests
Rebuilt `matmul_block_scaled_fp8.cu.o` for `sm_75`, `sm_80`, `sm_89` —
compiles
clean (previously failed with the `ptxas` error above on `sm_75`).

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…crosoft#34159)

### Description

Forward the initializer-data callback into `OrtGraphToProto` subgraph
recursion, keeping the same mutable callback state throughout a
traversal. Preserve the empty-callback path and both public function
signatures.

The recursive call currently omits the callback, so nested initializers
silently stay inline and nested callback errors are never reported.
Passing the `std::function` by value instead would copy mutable captures
into each branch, potentially reusing external-data offsets. A
conditional `std::ref` wrapper shares the active callback during
synchronous recursion without wrapping an empty function.

Adds generated, CPU-only regressions in the existing EP graph suite:
- root, sibling and depth-two initializers, including same-named
initializers with different values;
- a mutable value-captured offset, checking every external-data
location/offset/length and the corresponding bytes;
- external-file reload and actual inference for every `If` branch;
- both GraphProto/ModelProto overloads, omitted/empty callbacks, and
exact nested error propagation with no subsequent callbacks.

#### Validation

Built and tested on macOS arm64, Apple Clang 17, CPU-only Release
shared-library build, based on
`a8246c0d094f1ab0d6bf236228e5e67683321cd7`. No minimal build or operator
exclusions were used.

```sh
source .venv/bin/activate
python tools/ci_build/build.py \
  --build_dir build/MacOS --config Release --update --build --parallel 4 \
  --target onnxruntime_ep_graph_test --build_shared_lib \
  --cmake_generator Ninja --skip_submodule_sync --skip_tests \
  --cmake_extra_defines FETCHCONTENT_TRY_FIND_PACKAGE_MODE=NEVER
# Target-only builds do not run the general test target's fixture-copy step.
cmake -E copy_directory onnxruntime/test/testdata build/MacOS/Release/testdata
cd build/MacOS/Release
./onnxruntime_ep_graph_test --gtest_filter='EpGraphTest.*'
```

- **Before:** both added regressions fail against the unmodified header.
The nested fixture serializes eight initializers but invokes the
callback once; nested rejection incorrectly returns success.
- **After:** all **20 EP graph tests pass**, including the two added
regressions; no skips.
- **Mutation checks:** forwarding the callback by value fails the
offset/data/output assertions; unconditionally wrapping the empty
callback fails the inline serialization control. The intended fix was
restored, rebuilt and the full suite rerun afterward.
- `lintrunner` and `git diff --check` pass.

<details>
<summary>Selected output from the actual local runs</summary>

Baseline:
```text
Expected equality of these values:
  callback_calls
    Which is: 1
  inline_initializers.size()
    Which is: 8

Value of: status.IsOK()
  Actual: true
Expected: false

[  PASSED  ] 0 tests.
[  FAILED  ] 2 tests
```

Restored final patch:
```text
[==========] 20 tests from 1 test suite ran. (48 ms total)
[  PASSED  ] 20 tests.
```
</details>

Windows execution has not been tested locally. Existing macOS telemetry
duplicate-class and model-fixture warnings were not suppressed.

### Motivation and Context

Fixes microsoft#34137. Thanks to @zadesai for the reproducer and the
reference-forwarding approach.

This fixes the existing header-only EP utility. microsoft#33921 concerns FLOAT16
tensor attributes, while microsoft#34014 adds a separate serialization C API;
neither fixes this callback omission.

AI assistance: OpenAI Codex assisted with implementation, independent
source review, and execution of the reported local tests. The results
above are from those actual automated runs.

Signed-off-by: Silu Panda <31051721+SiluPanda@users.noreply.github.com>
… libraries (microsoft#34126)

Windows directory junction checks in model_package currently rely on the
MSVC-specific filesystem file_type junction enumerator, which fails to
compile on Windows builds using libc++ or other C++ standard libraries
that only expose standard file_type values and classify NTFS junctions
as directories.

This change queries Win32 file attributes and the reparse tag directly
on Windows when symlink_status does not already report a symbolic link,
rejecting name-surrogate reparse points such as NTFS junctions across
all C++ standard libraries while preserving fast early return on
ordinary files and directories.

Validated on Windows by building and running the model_package test
suites, including root, nested, and shared_assets junction rejection
tests, and by verifying clean warning-free compilation under clang-cl
with libc++.

Co-authored-by: Mustapha Jaber <mustjab+microsoft@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…icrosoft#34099)

### Description

Since `huggingface_hub` 1.32, the Hugging Face Hub cache stores Xet
files once per cache in a [blob store shared across
repos](https://huggingface.co/docs/huggingface_hub/guides/manage-cache#shared-blobs-across-repos)
(`<cache>/blobs/<hash prefix>/<hash>`), and the repo's `blobs/<etag>`
becomes a relative symlink to it. A model and its external data in one
snapshot can then resolve into different folders (for example
`blobs/28/…` and `blobs/d4/…`, or one in the repo's `blobs/` and one in
the shared store). The symlink fallback from microsoft#27374 only accepts
external data next to the resolved model, so models with external data
loaded from a default `hf_hub_download` path fail with `External data
path escapes model directory`. This PR teaches both external data
validators about the shared store without trusting anything outside the
cache's blob folders.

### Summary of Changes

#### Validation (`onnxruntime/core/framework/tensorprotoutils.cc`)

New Pass 3 in `ValidateExternalDataPath`, reached only when the model is
a symlink and Passes 1–2 fail. If the canonical model directory is in a
snapshot of a cache repo (`<cache>/<type>s--<repo
id>/snapshots/<revision>/…`, also from a subfolder such as `onnx/`),
external data is accepted when:

1. its path does not leave the model directory before symlinks are
resolved (no `..` escape), and
2. both the model and the external data resolve to files under the blob
stores of that cache: the repo's `blobs/` folder or the cache-wide
`blobs/` folder.

`ValidateOpenedExternalDataPath` applies the same blob-store check to
the canonical path of the opened file, so the opened-file validation
from microsoft#33063 also covers the new case. The cost is one extra
canonicalization, and only after the existing passes fail.

| File | Change |
|------|--------|
| `onnxruntime/core/framework/tensorprotoutils.cc` | Add
`IsInHuggingFaceCacheBlobStores` and use it in both validators. |
| `onnxruntime/test/framework/tensorutils_test.cc` |
`HuggingFaceCachePathValidationTest`: 11 tests on a cache built like
`huggingface_hub` does, with two-hop relative symlinks (6 accepted
layouts, 5 rejected). |
| `onnxruntime/test/python/onnxruntime_test_python_symlink_data.py` |
End-to-end `InferenceSession` test for the shared store and for a mixed
repo-local/shared layout. |

#### Security notes

- Paths are compared in canonical form. A canonical path has no
symlinks, so a file whose canonical path is under `<cache>/blobs` is
stored in that real folder. If a `blobs/` folder is itself a symlink or
junction, nothing matches (`huggingface_hub` also never uses a symlinked
`blobs/` folder as the shared store).
- The model itself must resolve into the blob stores. This rejects
symlinked models that point outside the cache, and `symlink/..` tricks
in the model path.
- The no-`..` requirement keeps a malicious model from reaching other
cached repos' files. In a real cache, the entries of a snapshot folder
are symlinks that `huggingface_hub` creates to files of the same repo.
- Someone who can write into the cache root gains nothing new. With the
existing Pass 2 (for example ORT 1.31.1), they can already make a model
read any blob by putting the model file in the same shard folder
(verified). `huggingface_hub` also gives the store and shard folders the
same permissions as the cache root.
- Unchanged: empty, absolute, and in-memory-tag locations are still
rejected before any fallback, and Passes 1–2 behave as before.

#### Comparison with microsoft#33974

microsoft#33974 targets the same issue. It also checks the
`.huggingface-shared-blobs` marker (version `1`) and blob names (hex,
40/64 characters, 2-character shard), and requires a `models--` repo
folder. These checks are not security boundaries, since anyone who can
create the layout can also create the marker and names. They do tie ORT
to `huggingface_hub` internals, so a future layout change would break
loading again. I built both and loaded the same synthetic caches:

| Scenario | microsoft#33974 | This PR |
|---|---|---|
| Shared store, model and data in different shards | loads | loads |
| Mixed repo-local/shared blobs (both directions) | loads | loads |
| `datasets--…` repo | fails | loads |
| Model folder reached through a symlinked directory | fails | loads |
| Shared store marker version other than `1` | fails | loads |
| Location `../x`; data symlink outside the cache; symlinked `blobs/` |
rejected | rejected |

### Motivation and Context

Fixes microsoft#33950. Downstream projects currently work around it by pinning
`huggingface_hub<=1.31`, setting `HF_HUB_DISABLE_SHARED_BLOBS=1`, or
copying files out of the cache.

### Testing

- Real cache: reproduced the issue with `onnxruntime==1.31.1` and
`huggingface_hub==2.4.0` (`onnx-community/sam2.1-hiera-tiny-ONNX`, fresh
`HF_HOME`). With this PR, the same cache loads. The two mixed layouts
created by downloading one of the files with
`HF_HUB_DISABLE_SHARED_BLOBS=1` also fail with 1.31.1 and load with this
PR.
- `onnxruntime_test_all
--gtest_filter='HuggingFaceCachePathValidationTest.*:PathValidationTest.*:GetExtDataFromTensorProtoTest.*'`:
all pass. Without the `tensorprotoutils.cc` change, the 6 tests for
accepted layouts fail. Removing any one of the conditions (no `..`
escape, model in a blob store, `blobs/` folder bound, repo folder name,
symlinked `blobs/`, opened-file check) makes the targeted test fail.
- `python -m pytest
onnxruntime/test/python/onnxruntime_test_python_symlink_data.py`: 4
passed (plus 2 subtests).
- Full `onnxruntime_test_all` on Linux x64 (CPU, Release): 2897 passed.
`lintrunner`: no issues.
- Not run locally: Windows and WASM. The new tests skip when symlinks
cannot be created, and the load test is excluded on WASM like the other
external-file tests in that file.

### Checklist

- [x] Tests added/updated
- [x] No breaking changes
- [ ] Documentation updated (not applicable)

---------

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

## Description

This PR builds on microsoft#34147 (`main`) to enable and accelerate large-chunk
(`R` up to `4,096`) prefill across the native `com.microsoft` CUDA
contrib operators (`Mamba2Verify`, `MoEPacked`, `MoEGroupRouter`,
`MatMulPacked`, and `GroupQueryAttention`) for
`NVIDIA-Nemotron-3.5-Bolt-74B-A9B`. Combined with the companion
`onnxruntime-genai` dynamic-prefill runtime in
[microsoft/onnxruntime-genai#2961](microsoft/onnxruntime-genai#2961),
prefill throughput on NVIDIA H200 (`sm_90`) reaches **`10,185 tok/s`
(`k=7`) / `10,429 tok/s` (`k=0`) at `L = 2048`** and **`11,424 tok/s`
(`k=7`) / `11,587 tok/s` (`k=0`) at `L = 3968`** — **`2.45×–2.67×`
faster than `llama.cpp` peak (`ub=4096`)** and **`13.98×–15.73×` faster
than fixed `R=8` prefill**.

## Summary of Changes

### `Mamba2Verify` Large-`R` Prefill & Right-Aligned Snapshots

| File | Change |
|------|--------|
|
`onnxruntime/core/graph/contrib_ops/fused_state_space_defs.h`<br>`onnxruntime/contrib_ops/cuda/sequence/fused_state_space.cc`<br>`docs/ContribOperators.md`
| Lift the `R <= 16` and `slots >= R` constraints (`R >= 1`, `slots >=
1`). When `R <= slots`, behavior is unchanged (`0..R-1` written,
`R..slots-1` preserved). When `R > slots`, only the trailing `slots`
tokens (`R - slots .. R - 1`) write snapshots `0 .. slots - 1` so slot
`slots - 1` holds the final recurrent state without writing intermediate
HBM snapshots. |
| `onnxruntime/contrib_ops/cuda/sequence/fused_state_space_impl.cu` |
Add 2D sequence-and-channel tiled `MambaConvPrefillKernel`, race-free
`MambaConvWriteSnapshotsKernel` (safe under in-place `conv_state`
aliasing), and `MambaSsmPrefillKernel<4, 16>` (register-resident state
scan with 36 KiB tiled shared-memory staging and exact 4-partition
readout parity). Aliasable state pointers are not `__restrict__`, and
the grouped RMS normalization launch is sliced into 65,535-row grid-y
chunks so any `R <= INT_MAX` launches. |

### `MoEPacked`, `MoEGroupRouter`, `MatMulPacked` &
`GroupQueryAttention` Prefill Optimizations

| File | Change |
|------|--------|
|
`onnxruntime/contrib_ops/cuda/moe/moe_packed.h`<br>`onnxruntime/contrib_ops/cuda/moe/moe_packed.cu`
| Raise `kMoEPackedMaxChunkRows` to `4096` so `L <= 4096` executes in a
single chunk, and add `BuildMoEPackedTilesKernel<64>` +
`MoEPackedReluIq2PrefillTcKernel<kFc1, 8>` so each IQ2_XXS weight
sub-block is decoded once per up-to-64 routes in shared memory instead
of once per 8 routes. Each MMA accumulator chain covers one 64-wide K
step and partials are combined with FP32 adds, matching the rounding of
the warp-split decode kernels (~1.4% kernel time on A100). |
|
`onnxruntime/contrib_ops/cuda/moe/moe_group_router_impl.h`<br>`onnxruntime/contrib_ops/cuda/moe/moe_group_router_impl.cu`<br>`onnxruntime/contrib_ops/cuda/bert/linear_attention_gates.cc`
| Add a zero-workspace `cublasGemmEx` Tensor Core GEMM + in-place
`SigmoidLogitsKernel` path for `rows > 16`, while keeping
`SigmoidScoresR8Kernel` for `rows == 8`. The schema now states that the
FP32 projection reduction order depends on the row count. |
| `onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu` | Add
templated `MatMulPackedBf16DequantFastKernel` (`IQ2_XXS`, `NVFP4`,
`Q8_0`), widen BF16 prefill tile width up to `18560` so projections
execute in a single `cublasGemmEx` call, and apply `NVFP4`
`global_scale` via `CUBLAS_POINTER_MODE_DEVICE` to eliminate
intermediate FP32 buffers and `M=128` sub-tiling. The cuBLAS epilogue
can round `global_scale` products one ulp differently from an FP32
multiply followed by the cast (documented in the schema). The activation
epilogue is sliced into 65,535-row grid-y chunks. |
|
`onnxruntime/contrib_ops/cuda/bert/group_query_attention.cc`<br>`onnxruntime/contrib_ops/cuda/bert/group_query_attention_impl.cu`<br>`onnxruntime/contrib_ops/cuda/bert/attention_data.h`<br>`onnxruntime/contrib_ops/cuda/bert/cudnn_fmha/cudnn_flash_attention.h`<br>`onnxruntime/contrib_ops/cuda/bert/cudnn_fmha/cudnn_flash_attention.cc`
| Prefer `FlashAttention` for small `R <= 16` shared-KV verify steps in
auto mode (so `R=8` verify uses `FlashAttention` without
`ORT_ENABLE_CUDNN_FLASH_ATTENTION=0` while large-`R` prefill uses Hopper
`cuDNN SDPA`), keep `cudnn_sdpa` during CUDA graph capture when its plan
is already cached (`cudnn_sdpa::has_cached_graph`) and fall back only
when a non-capturable plan build would be needed, and route cuDNN SDPA
workspace allocations through arena-pooled `GetScratchBuffer`
(eliminating synchronous `cudaMalloc`/`cudaFree` stalls). |

### Follow-ups from microsoft#34147

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cuda/moe/moe_packed.cu` | Use zero
coefficients when `sum + routing_epsilon == 0` (previously Inf/NaN
rows), matching the documented normalization contract. |
|
`onnxruntime/contrib_ops/cuda/moe/moe_packed.cc`<br>`onnxruntime/core/graph/contrib_ops/contrib_defs.cc`
| Reject non-default `routed_scaling_factor`/`routing_epsilon` without
`router_weights`; legacy softmax routing silently ignored them. |
|
`onnxruntime/core/graph/contrib_ops/bert_defs.cc`<br>`docs/ContribOperators.md`
| Document the row-count-dependent `MoEGroupRouter` projection reduction
order (8-row split-K kernel, cuBLAS for `rows > 16`). |

### Unit Tests

| File | Change |
|------|--------|
| `onnxruntime/test/contrib_ops/fused_state_space_op_test.cc` | Update
schema validation test for `slots >= 1`. |
| `onnxruntime/test/contrib_ops/cuda_kernels/fused_state_space_test.cc`
| Add `MambaNormRowsBeyondGridYLimit` (65,537 rows) and
`MambaPrefillInPlaceStatesMatchSeparateOutputs` (aliased vs separate
state buffers for `R = 20/37`, including `state_row = 0`). |
| `onnxruntime/test/contrib_ops/moe_packed_routing_test.cc` | Add
legacy-routing rejection cases for `routed_scaling_factor` and
`routing_epsilon`. |
| `onnxruntime/test/contrib_ops/matmul_packed_precision_test.cc` | Allow
one ulp for BF16 NVFP4 `global_scale` prefill rows (decode and FP32
prefill stay bit-exact). |
| `onnxruntime/test/python/transformers/test_gqa.py` | Add
`test_cuda_graph_capture_reuses_warm_cudnn_sdpa_plan`. |
| `onnxruntime/test/python/transformers/test_gguf_packed_ops.py` | Add
`test_mamba2_verify_prefill_right_aligned_snapshots` (`R = 37, slots =
8` vs sequential `R = 8` chunks) and `m = 65` Tensor Core GEMM coverage
in `test_moe_group_router_r8_and_fused_bias`; add
`test_mamba2_verify_prefill_rows_beyond_grid_y_limit`,
`test_moe_packed_routing_epsilon_zero_denominator` and
`test_matmul_packed_activation_rows_beyond_grid_y_limit`. |

## Motivation and Context

### Prefill Throughput on NVIDIA H200 (`sm_90`, CUDA 13.0,
`NVIDIA-Nemotron-3.5-Bolt-74B-A9B`)

| Prompt `L` | `llama.cpp` Default (`ub=512`) | `llama.cpp` Peak
(`ub=4096`) | Prior ORT (`R=8`, `k=7`) | **This PR (`k=0`)** | **This PR
(`k=7`)** | **Speedup (`k=7`) vs `llama.cpp` Peak / vs Prior ORT** |
|---:|---:|---:|---:|---:|---:|---:|
| **128** | 85.96 ms (`1,489.0 tok/s`) | 86.20 ms (`1,484.9 tok/s`) |
175.28 ms (`730.3 tok/s`) | **52.80 ms (`2,424.3 tok/s`)** | **55.66 ms
(`2,299.6 tok/s`)** | **`1.55×`** / **`3.15×`** |
| **512** | 166.26 ms (`3,079.5 tok/s`) | 166.86 ms (`3,068.4 tok/s`) |
700.32 ms (`731.1 tok/s`) | **83.82 ms (`6,108.6 tok/s`)** | **87.66 ms
(`5,840.7 tok/s`)** | **`1.90×`** / **`7.99×`** |
| **1024** | 332.31 ms (`3,081.4 tok/s`) | 271.43 ms (`3,772.6 tok/s`) |
1,391.56 ms (`735.9 tok/s`) | **120.56 ms (`8,493.6 tok/s`)** | **125.06
ms (`8,187.8 tok/s`)** | **`2.17×`** / **`11.13×`** |
| **2048** | 671.54 ms (`3,049.7 tok/s`) | 493.12 ms (`4,153.2 tok/s`) |
2,810.28 ms (`728.8 tok/s`) | **196.39 ms (`10,428.5 tok/s`)** |
**201.08 ms (`10,184.8 tok/s`)** | **`2.45×`** / **`13.98×`** |
| **3968** | 1,320.22 ms (`3,005.6 tok/s`) | 915.41 ms (`4,334.7 tok/s`)
| 5,462.94 ms (`726.3 tok/s`) | **342.46 ms (`11,586.9 tok/s`)** |
**347.34 ms (`11,423.8 tok/s`)** | **`2.64×`** / **`15.73×`** |

### `nsys` Target Kernel-Family Breakdown at `L = 2048` (`192.76 ms` vs
`483.81 ms` in `llama.cpp` = **`2.51×` faster**)
- **IQ2_XXS MoE Routed GEMMs** (`40` layers): `98.51 ms` vs `137.61 ms`
(**`1.40×` faster**)
- **Mamba2 Conv / SSM Scan / Norm** (`40` layers): `46.42 ms` vs `47.82
ms` (**`1.03×` faster**; conv `2.43 ms` vs `3.42 ms`)
- **NVFP4 Mamba2 Projections** (`40` layers): `25.69 ms` vs `123.21 ms`
(**`4.80×` faster**)
- **IQ2_XXS MoE Shared GEMMs** (`40` layers): `11.63 ms` vs `35.56 ms`
(**`3.06×` faster**)
- **Q8_0 Projections + `M=1` LM Head**: `4.64 ms` vs `13.22 ms`
(**`2.85×` faster**)
- **MoE Routing / Tile Build / Finalize**: `2.39 ms` vs `77.68 ms`
(**`32.45×` faster**)
- **GQA Attention + RoPE / KV**: `1.08 ms` vs `2.76 ms` (**`2.55×`
faster**, `0` synchronous `cudaMalloc`/`cudaFree` calls)

## Testing

- Ran `onnxruntime/test/python/transformers/test_gguf_packed_ops.py` on
H200 (`sm_90`), including
`test_mamba2_verify_prefill_right_aligned_snapshots`,
`test_moe_group_router_r8_and_fused_bias`,
`test_moe_packed_routed_scaling_factor_and_routing_epsilon`, and
`test_matmul_packed_activation_types`.
- Verified end-to-end MMLU-Pro 200 accuracy (`119 / 200 = 59.50%`,
`97.0%` exact choice agreement with microsoft#34147) and speculative decode
throughput (`k=7`) on `NVIDIA-Nemotron-3.5-Bolt-74B-A9B`.
- Verified formatting and linting with `lintrunner -a` (`No lint
issues`).
- On A100 (`sm_80`, CUDA 13.0): `test_gguf_packed_ops.py` (50 tests),
`onnxruntime_provider_test
--gtest_filter='MoEPacked*:MatMulPacked*:MoEGroupRouter*:FusedStateSpace*:Mamba*:GatedDeltaNet*:GroupQueryAttention*:*MultiHeadAttention*:AttentionTest*:PagedAttention*'`
(478 tests), `FusedStateSpaceKernelTest.*` via `CUDA_EP_Unittest.All`,
and the `test_gqa.py` cuDNN/CUDA graph subset. The new boundary,
zero-denominator and CUDA graph tests fail on dc36d14.

## Checklist

- [x] Tests added/updated
- [x] No breaking changes (backward-compatible with `1 <= R <= slots`)
- [x] Documentation updated (`docs/ContribOperators.md`)

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…crosoft#28457)

### Description

This adds `onnxruntime.set_default_logger_callback(callback,
severity=2)`. Python applications can use it to send ONNX Runtime log
messages to any Python callable, such as the standard `logging` module,
instead of stderr.

```python
def set_default_logger_callback(
    callback: Callable[[int, str, str, str, str], None] | None,
    severity: int = 2,  # 0=Verbose, 1=Info, 2=Warning, 3=Error, 4=Fatal
) -> None: ...
```

**Example:**
```python
import logging
import onnxruntime as ort

def ort_log_to_python(severity: int, category: str, logid: str, code_location: str, message: str) -> None:
    level = [logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL][severity]
    logging.log(level, "[ORT:%s] %s", category, message)

ort.set_default_logger_callback(ort_log_to_python, severity=0)  # capture all
sess = ort.InferenceSession("model.onnx")

ort.set_default_logger_callback(None)  # restore the platform default (stderr/OutputDebugString)
```

**Behavior:**
- The callback receives messages from the environment's logging manager,
including messages from existing sessions.
- Installing a callback sets the default logger severity. Session and
run log severities still apply, and existing sessions keep their
configured severity. Passing `None` restores the platform sink and
leaves the severity unchanged.
- The callback runs synchronously, with the GIL held, on the thread that
emits the message.
- Messages from threads that Python does not know about, such as ORT
thread-pool workers and EP-internal threads, go to the platform sink.
Waiting for the GIL on those threads can deadlock session teardown or
abort the process at interpreter exit.
- If the callback logs, those nested messages go to the platform sink,
as do messages whose callback raises. Python exceptions are reported
through `sys.unraisablehook`.
- If log text contains bytes that are not valid UTF-8, those bytes are
backslash-escaped. The message still reaches the callback.
- The API requires an ORT environment created by the Python module.
Otherwise it raises an error.

#### Summary of Changes

| File | Change |
|------|--------|
| `onnxruntime/core/session/ort_env.h`, `ort_env.cc` | Add an optional
`sink_factory` function pointer to
`OrtEnv::LoggingManagerConstructionInfo`. When set, it creates the
environment's default sink and takes precedence over `logging_function`.
It is a plain function pointer rather than `std::function`, so the
struct stays trivially destructible and minimal builds do not grow. |
| `onnxruntime/python/onnxruntime_pybind_state.cc` | Add
`PythonCallbackSink`, a sink whose callback can be replaced and that
falls back to the platform sink. Add the `set_default_logger_callback`
binding. |
| `onnxruntime/python/onnxruntime_pybind_module.cc`,
`onnxruntime_pybind_module_functions.h` | Install the sink through
`sink_factory` when the Python module creates the `OrtEnv`. |
| `orttraining/orttraining/python/orttraining_python_module.cc` | Make
the same change in the training module. |
| `onnxruntime/__init__.py`, `docs/python/api_summary.rst` | Export and
document the new API. |
| `onnxruntime/test/python/onnxruntime_test_python.py` | Add tests for
the new callback (listed under Testing). |

#### Testing

Run the tests from a build with `--enable_pybind`:
```
python -m pytest onnxruntime/test/python/onnxruntime_test_python.py -k "logger_callback or logging_callback"
```

The tests cover:
- delivery of records and their types
- reset with `None`
- invalid arguments
- a raising callback, observed through `sys.unraisablehook`
- a callback that replaces itself, and re-entrancy from a finalizer
- replacing the callback while sessions log on two Python threads
- log text that is not valid UTF-8
- on Linux, a subprocess check that ORT pool threads logging during
session teardown and interpreter exit neither deadlock nor abort

### Motivation and Context

Fixes microsoft#28437.

The Python binding creates the ORT environment without a logging
function. As a result, Python users could only redirect ORT logs by
manipulating file descriptors. The C API already supports a custom
logger through `CreateEnvWithCustomLogger`, and this change gives the
Python API the same capability.

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tianleiwu <30328909+tianleiwu@users.noreply.github.com>
Co-authored-by: Tianlei Wu <tlwu@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#34117)

### Description

- Extend CUDA `VarlenCausalConvWithState` with dynamic grouped two-tap
convolutions, including per-token coefficient deltas, boundary masking,
and schema validation.
- Add opt-in grouped BF16 INT3 MoE prefill, with a compatible SIMT path
and guarded tensor-core acceleration using canonical recomputation for
rounding-sensitive outputs.
- Extend H128/GQA6 XQA support with BF16 INT8/INT4 speculative
verification and BF16 INT4 single-token decoding.
- Optimize INT8 KV prefill through sliding-window-aware gathering,
vectorized dequantization, and revised FlashAttention query tiling.
- Add BF16 shadow caching for global INT8 KV prefill. Retain a
dequantized prefix across prefill chunks and convert only newly appended
tokens, avoiding repeated full-prefix gathering. The optional
`prefill_cache_control` input supplies an epoch, capacity, and
final-chunk flag to explicitly govern reuse.
- Add shadow-cache lifecycle safeguards: epoch invalidation, CUDA-stream
synchronization, failure handling, and final-chunk buffer release.
Missing controls, CUDA graph capture, multi-request batches, and
unsupported configurations retain stateless behavior.
- Expand correctness, dispatch, fallback, and cache-lifecycle coverage;
update operator documentation and CUDA build dependencies.

### Motivation and Context

There are existing bottlenecks in INT3 expert computation and repeated
quantized-KV gathering, alongside gaps in BF16 quantized-cache
speculative attention. These changes provide the CUDA primitives needed
to reduce prefill overhead and support lower-memory speculative
decoding.

Optimizations are restricted to eligible configurations, with grouped
INT3 prefill remaining opt-in. Prefix reuse requires explicit
caller-managed lifetimes and trades temporary BF16 workspace for reduced
dequantization work. The companion GenAI changes supply the necessary
graph lowering and lifecycle controls. Model weights are not
requantized; quantized-KV accuracy still requires application-specific
qualification.

### Benchmarks

Notes:

1. H200, batch 1, 512 output tokens, one warmup and five measured
requests. The below benchmarks compare BF16 KV cache and INT8 KV cache
versions of the RCs. TTFT and decode are medians; peak GPU memory
includes weights and reserved pools, in decimal GB. INT8 KV cache
versions use the optimized tile64 + shadow path; draft KV remains BF16
throughout.

2. Memory usage is not a fair comparison between ORT GenAI and llama.cpp
because ORT GenAI tries to capture as much GPU memory as it can for
future conversations. Memory usage is simply noted here for recording
purposes.

**INT3 RC**
| Context | BF16 TTFT (s) | INT8 TTFT (s) | BF16 Decode (tok/s) | INT8
Decode (tok/s) | BF16 Peak (GB) | INT8 Peak (GB) |
|---|---:|---:|---:|---:|---:|---:|
| 8K* | 1.313 | 1.325 | 446.396 | **480.024** | 105.429 | 89.860 |
| 16K* | 2.684 | 2.706 | 227.500 | **469.024** | 105.429 | 89.860 |
| 32K* | 5.600 | 5.594 | 195.555 | **453.775** | 105.429 | 90.933 |
| 64K | 12.157 | 12.041 | 302.338 | **428.886** | 105.429 | 92.141 |
| 128K | 28.123 | 27.547 | 211.742 | **379.787** | 105.429 | 95.363 |

**INT2 RC**
| Context | BF16 TTFT (s) | INT8 TTFT (s) | BF16 Decode (tok/s) | INT8
Decode (tok/s) | BF16 Peak (GB) | INT8 Peak (GB) |
|---|---:|---:|---:|---:|---:|---:|
| 8K | 1.236 | 1.225 | 280.496 | **420.968** | 84.122 | 68.622 |
| 16K | 2.490 | 2.502 | 405.926 | **441.012** | 84.122 | 68.620 |
| 32K | 5.184 | 5.174 | 357.272 | **429.573** | 84.122 | 69.763 |
| 64K | 11.297 | 11.127 | 275.144 | **391.317** | 84.122 | 70.834 |
| 128K | 26.356 | 25.621 | 197.655 | **346.274** | 84.122 | 74.056 |

**llama.cpp (2-bit)**
| Prompt | TTFT (s) | Decode (tok/s) | Peak GPU (GB) |
|---|---:|---:|---:|
| 8K | 1.387 | 319.586 | 60.888 |
| 16K | 2.839 | 330.673 | 61.250 |
| 32K | 5.919 | 324.807 | 61.924 |
| 64K | 13.035 | 317.357 | 63.268 |
| 128K | 31.620 | 290.775 | 65.952 |
…ft#33957)

## What changes

Return a clear error when an operation has no assigned execution
backend, or names a backend that is not registered, instead of failing
while preparing data copies. This prevents cases where ops could not be
assigned an ep from crashing the browser GPU process when ORT WebGPU is
used as the backend for webnn.

The error identifies the affected node. Unsupported operations return
`NOT_IMPLEMENTED`; invalid backend names return `INVALID_ARGUMENT`.
Validation happens before copy nodes are inserted. Valid CPU-assigned
nodes keep their existing behavior.

`ModifyGraph` now returns `Status` and reports graph modification
through a `bool&` output parameter. Assignment checks run in its
existing initial node scan, before collecting each node's copy
requirements; there is no separate validation traversal in `ApplyImpl`.
`ApplyImpl` propagates failures with `ORT_RETURN_IF_ERROR`. These are
internal helper changes, with no public API/ABI change. The existing
non-CPU-provider guard and subgraph recursion remain unchanged.

## Native tests

**3 tests passed, with no skips, after the refactor.** They cover an
unassigned node, an unavailable named backend, an unchanged valid
CPU-assigned node, and successful CPU-to-GPU-to-CPU copy insertion with
`modified == true`. Invalid assignments are tested after an earlier
valid GPU-assigned node has been processed; node assignments and
connections remain unchanged on failure.

Regression-sensitivity checks used disposable faulty source copies with
the unchanged tests. Dropping the modification flag, omitting a
GPU-to-CPU copy, and changing an earlier valid node's assignment each
failed the intended assertion. The production source was then rebuilt
and all three tests rerun successfully.

From an existing Release build configured with WebGPU:

```powershell
cmake --build build\latest-webgpu\Release --target onnxruntime_test_all --parallel 8
Push-Location build\latest-webgpu\Release
.\onnxruntime_test_all.exe --gtest_filter=TransformerTest.MemcpyTransformer*
Pop-Location
```

The tests use a small test backend and do not depend on GPU hardware.

---------

Co-authored-by: Sushanth Rajasankar <Sushanth.Rajasankar@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds signed int8 and int64 support for Abs, Neg, Relu, and Sign to
improve WebGPU EP coverage on WebNN WPT tests.

The measured WebNN WPT pass rate increased from **96.6% (1,691/1,751)**
to **97.1% (1,701/1,751)** in combined validation. Eight newly passing
integer unary cases correspond to this change; the other two gains are
not attributed to this PR. The selection excludes float16 input/output
cases.

Int64 unary kernels respect the `enableInt64` opt-in; int8 support is
unaffected.

Validation: all 12 native unary tests pass with no skips, covering
enabled/disabled int64 configurations with CPU fallback disabled. WPT
measurements predate the subsequent kernel refactor; WPT was not rerun
afterward.

---------

Co-authored-by: Sushanth Rajasankar <Sushanth.Rajasankar@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…16C/Batch4/40-core cold decode (microsoft#34114)

## Description

Stacks on microsoft#33976 (and integrates microsoft#34066 and microsoft#34067). Optimizes
`com.microsoft::MoEPacked` CPU/GPU hybrid expert offload and
`com.microsoft::MatMulPacked` multi-token (`M=2..8`) MTP verification
for block-packed GGUF MoE models (`Qwen3.8-Flash-Next` `UD-IQ3_XXS`)
based on Nsight Systems (`nsys --cuda-graph-trace=node`) timeline
profiling on NVIDIA H200:

1. **Prefill**: Eliminates cross-stream H2D Copy-Engine head-of-line
blocking by double-buffering per-wave route/tile metadata
(`d_wave_sorted_routes[2]`, `d_wave_tiles[2]`, `d_wave_num_tiles[2]`) on
`wave_staging.copy_stream` and decoupling host `std::memcpy`
(`h2d_done[b]`) from device compute (`compute_done[b]`), increasing true
2-stream compute/H2D overlap **3.77x** (`6.6% -> 24.9%`, `154.4 ms ->
478.8 ms` at `8K`) and cutting `2K–128K` TTFT by **`-14.7% to -25.9%`**
(`+17.3% to +35.0%` prefill tok/s, saving `8.67s–9.72s` at `128K`).
2. **Decode**: Replaces 129 software `MLFloat16::ToFloat()` scale
conversions in `gguf_vec_dot_cpu.h` AVX2 loops with hardware F16C
`_mm_cvtph_ps`, adds 4-route (`Batch-4`) fused AVX2 INT8 (`vpmaddubsw`)
dot-product kernels (`AccumIq2S32Q8Batch4Avx2`,
`AccumIq3Xxs32Q8Batch4Avx2`, `AccumIq4Nl32Q8Batch4Avx2`,
`VecDotGgufRow4xQ8Batch4Avx2`, `VecDotGgufGateUpRow2xQ8Batch4Cpu`),
scales `MoEPackedParallelPool` to `40` physical cores, and dispatches
`MatMulPackedBf16TcWarpKSplit<4, 1>` for `N <= 2560`, cutting
`MoEPackedDoorbellWaitKernel` by **`-49.6%`** (`53.40 -> 26.91 ms/cycle`
exact; **`-81.9%`** to `9.66 ms/cycle` with `tail_sub=0.02`) and
accelerating decode throughput by **`+60.1% to +79.4%`** (exact routing)
and **`+102.8% to +152.5%` (`2.03x–2.53x`)** with tail expert
substitution.

## Summary of Changes

### 1. `MoEPacked` 3-Stage Prefill Pipeline & Cold-Expert Decode
(`onnxruntime/contrib_ops/cuda/moe/moe_packed.cc`)

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cuda/moe/moe_packed.cc` | Double-buffer
`d_wave_sorted_routes[2]`, `d_wave_tiles[2]`, and `d_wave_num_tiles[2]`
in `MoEPackedSharedPrefillWaveStaging` and copy them on
`wave_staging.copy_stream` prior to recording `h2d_done[b]`; synchronize
host `std::memcpy` only on `h2d_done[b]` while `copy_stream` waits on
`compute_done[b]` on the device timeline; parallelize host expert
staging across `w_cnt * 3` tasks; raise
`MoEPackedParallelPool::ResolveThreads()` default cap from `24` to `40`
cores; integrate `Batch-4` + `Batch-2` Q8 cold-expert execution in
`RunColdDecodeStep()` (opt-in via `ep.cuda.moe_packed_cpu_q8_dot=1` or
`ORT_MOE_PACKED_CPU_Q8_DOT=1` so existing FP16/BF16 models retain full
FP32 cold-expert dot precision by default). |

### 2. Hardware F16C & 4-Route (`Batch-4`) AVX2 INT8 GGUF Kernels
(`onnxruntime/contrib_ops/cpu/quantization/gguf_vec_dot_cpu.h`)

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cpu/quantization/gguf_vec_dot_cpu.h` | Add
`Fp16ToFloatF16c` (`_mm_cvtph_ps`) under `ORT_GGUF_CPU_HAS_AVX2_TARGET`
and replace 129 software `Fp16BitsToFloatCpu` calls inside AVX2 loops;
add 4-route fused AVX2 INT8 dot-product kernels
(`AccumIq2S32Q8Batch4Avx2`, `AccumIq3Xxs32Q8Batch4Avx2`,
`AccumIq4Nl32Q8Batch4Avx2`, `VecDotGgufRow4xQ8Batch4Avx2`,
`VecDotGgufRow4xQ8Batch4Cpu`, `VecDotGgufGateUpRow2xQ8Batch4Cpu`) plus
2-route `Batch-2` kernels from microsoft#34067. |

### 3. `MoEPacked` Decode FC2 & `MatMulPacked` Multi-Token GEMV
(`moe_packed.cu`, `matmul_packed.cu`, `gguf_quant_cuda.cuh`)

| File | Change |
|------|--------|
| `onnxruntime/contrib_ops/cuda/moe/moe_packed.cu` | Integrate microsoft#34067
4-warp (`64` output channels/CTA) `MoEPackedFc2Bf16TcKernel<1>` decode
geometry with shared-memory `s_lut` GGUF lookup tables and direct
`__ldg(fc1_row)` activation loads. |
| `onnxruntime/contrib_ops/cuda/quantization/matmul_packed.cu` |
Integrate microsoft#34066 `(NR=2, KW=2)` multi-token GEMV and dispatch
`MatMulPackedBf16TcWarpKSplit<4, 1>` when `N <= 2560` (`M in 2..8`) to
double CTA grid occupancy (`1,280 -> 2,560` CTAs across 132 H200 SMs,
`-45.4%` per-call latency on 72 GDN projection calls/cycle). |
| `onnxruntime/contrib_ops/cuda/quantization/gguf_quant_cuda.cuh` |
Integrate microsoft#34066 uniform `uint16x2` `__ldg` loads in `ReadU32Dev` to
eliminate 50% warp divergence on 2-byte-aligned GGUF blocks (`Q8_0`,
`Q6_K`, `IQ4_NL`, `IQ4_XS`). |

---

## Performance & Accuracy Evaluation (`Qwen3.8-Flash-Next` `UD-IQ3_XXS`
+ `dflash2` `S=8` MTP on H200)

### 1. Setting 1: `30 GiB VRAM + 50 GiB RAM` (`device_expert_bytes =
12.50 GiB`, `6,463` GPU Resident Slots, Peak VRAM = `29.82 GiB`, Peak
`VmRSS` = `35.44–36.09 GiB`)

| Configuration | `2K` TTFT / Decode | `8K` TTFT / Decode | `32K` TTFT /
Decode | `128K` TTFT / Decode | MMLU-Pro Smoke (`20`) Acc | MMLU Tok-Wtd
/ Med TPS | CPU `ms/step` (`us/exp`) |
|---|---|---|---|---|---:|---|---:|
| **1. Baseline (`origin/main` `6cc3c09506`)** | `1.061s` (`1,931 t/s`)
/ `39.18 t/s` | `2.433s` (`3,367 t/s`) / `38.87 t/s` | `9.156s` (`3,579
t/s`) / `39.28 t/s` | `38.790s` (`3,379 t/s`) / `38.31 t/s` | `100.0%`
(`20/20`) | `41.36` / `43.84 t/s` | `61.58 ms` (`43.72 us`) |
| **2. Merged PRs (microsoft#33975+microsoft#33976+microsoft#34066+microsoft#34067, FP32 CPU)** | `1.052s`
(`1,947 t/s`) / `43.48 t/s` | `2.432s` (`3,369 t/s`) / `44.26 t/s` |
`8.961s` (`3,657 t/s`) / `43.09 t/s` | `38.357s` (`3,417 t/s`) / `38.55
t/s` | `100.0%` (`20/20`) | `42.57` / `48.49 t/s` | `61.65 ms` (`43.52
us`) |
| **3. Merged PRs (microsoft#33975+microsoft#33976+microsoft#34066+microsoft#34067, Q8 Batch-2 CPU)** |
`1.035s` (`1,978 t/s`) / `50.17 t/s` | `2.395s` (`3,420 t/s`) / `50.37
t/s` | `8.942s` (`3,665 t/s`) / `49.13 t/s` | `38.318s` (`3,421 t/s`) /
`47.88 t/s` | `100.0%` (`20/20`) | `49.50` / `57.69 t/s` | `47.85 ms`
(`33.35 us`) |
| **4. This PR (Exact Routing)** | **`0.786s` (`2,607 t/s`, `+35.0%`) /
`62.73 t/s` (`+60.1%`)** | **`1.807s` (`4,534 t/s`, `+34.6%`) / `69.30
t/s` (`+78.3%`)** | **`6.813s` (`4,809 t/s`, `+34.4%`) / `69.45 t/s`
(`+76.8%`)** | **`30.124s` (`4,351 t/s`, `+28.8%`) / `61.87 t/s`
(`+61.5%`)** | `95.0%` (`19/20`) | **`67.12` / `79.32 t/s` (`+80.9%`)**
| **`32.80 ms` (`22.89 us`)** |
| **5. This PR + TailSub (`thr=0.02, min_rank=2`)** | **`0.853s` (`2,400
t/s`, `+24.3%`) / `97.11 t/s` (`+147.9%`)** | **`1.969s` (`4,160 t/s`,
`+23.5%`) / `88.70 t/s` (`+128.2%`)** | **`7.495s` (`4,372 t/s`,
`+22.2%`) / `81.71 t/s` (`+108.0%`)** | **`32.830s` (`3,993 t/s`,
`+18.2%`) / `77.68 t/s` (`+102.8%`)** | **`100.0%` (`20/20`)** |
**`97.76` / `108.06 t/s` (`+146.5%`)** | **`14.13 ms` (`25.95 us`)** |

### 2. Setting 2: `22 GiB VRAM + 24 GiB RAM` (`device_expert_bytes =
5.60 GiB`, `2,843` GPU Resident Slots, Peak VRAM = `21.71 GiB`, Peak
`RssAnon` = `0.91–0.95 GiB`)

| Configuration | `2K` TTFT / Decode | `8K` TTFT / Decode | `32K` TTFT /
Decode | `128K` TTFT / Decode | MMLU-Pro Smoke (`20`) Acc | MMLU Tok-Wtd
/ Med TPS | CPU `ms/step` (`us/exp`) |
|---|---|---|---|---|---:|---|---:|
| **1. Baseline (`origin/main` `6cc3c09506`)** | `1.216s` (`1,684 t/s`)
/ `29.39 t/s` | `4.125s` (`1,986 t/s`) / `31.86 t/s` | `15.739s` (`2,082
t/s`) / `31.76 t/s` | `66.065s` (`1,984 t/s`) / `30.32 t/s` | `95.0%`
(`19/20`) | `34.00` / `39.65 t/s` | `74.14 ms` (`42.04 us`) |
| **2. Merged PRs (microsoft#33975+microsoft#33976+microsoft#34066+microsoft#34067, FP32 CPU)** | `1.197s`
(`1,712 t/s`) / `34.54 t/s` | `4.042s` (`2,027 t/s`) / `35.58 t/s` |
`15.762s` (`2,079 t/s`) / `33.70 t/s` | `66.006s` (`1,986 t/s`) / `34.26
t/s` | `95.0%` (`19/20`) | `37.03` / `42.90 t/s` | `73.66 ms` (`42.24
us`) |
| **3. Merged PRs (microsoft#33975+microsoft#33976+microsoft#34066+microsoft#34067, Q8 Batch-2 CPU)** |
`1.230s` (`1,665 t/s`) / `37.75 t/s` | `4.028s` (`2,034 t/s`) / `41.31
t/s` | `15.600s` (`2,101 t/s`) / `36.93 t/s` | `66.186s` (`1,980 t/s`) /
`41.27 t/s` | `95.0%` (`19/20`) | `43.87` / `49.14 t/s` | `57.36 ms`
(`32.47 us`) |
| **4. This PR (Exact Routing)** | **`0.980s` (`2,090 t/s`, `+24.1%`) /
`52.61 t/s` (`+79.0%`)** | **`3.345s` (`2,449 t/s`, `+23.3%`) / `52.73
t/s` (`+65.5%`)** | **`13.205s` (`2,482 t/s`, `+19.2%`) / `56.98 t/s`
(`+79.4%`)** | **`56.343s` (`2,326 t/s`, `+17.3%`) / `50.16 t/s`
(`+65.4%`)** | `95.0%` (`19/20`) | **`62.68` / `70.61 t/s` (`+78.1%`)**
| **`38.21 ms` (`21.71 us`)** |
| **5. This PR + TailSub (`thr=0.02, min_rank=2`)** | **`0.962s` (`2,130
t/s`, `+26.5%`) / `74.21 t/s` (`+152.5%`)** | **`3.321s` (`2,467 t/s`,
`+24.2%`) / `74.47 t/s` (`+133.7%`)** | **`13.191s` (`2,484 t/s`,
`+19.3%`) / `68.41 t/s` (`+115.4%`)** | **`56.890s` (`2,304 t/s`,
`+16.1%`) / `72.87 t/s` (`+140.3%`)** | `95.0%` (`19/20`) | **`89.00` /
`100.57 t/s` (`+153.6%`)** | **`17.55 ms` (`23.32 us`)** |

### 3. Nsight Systems (`nsys --cuda-graph-trace=node`) Before-vs-After
Verification (`30g_50g`, `8192` Context)

| Nsight Systems Metric (`8192` Context, `17` `S=8` MTP Cycles) |
Pre-Optimization | Post-Opt (Exact) | Post-Opt (`tail-sub=0.02`) | Delta
(Post Exact / Tail-Sub vs. Pre) |
|---|---:|---:|---:|---|
| **8K Prefill GPU Window (`Chunk 0 + Chunk 1`)** | `2,354.70 ms` |
**`1,922.92 ms`** | **`1,919.95 ms`** | **`-431.78 ms` (`-18.3%`) /
`-434.75 ms` (`-18.5%`)** |
| **True 2-Stream Compute/H2D Overlap (`stream` & `copy_stream` both
active)** | `154.43 ms` (`6.6%`) | **`478.83 ms` (`24.9%`)** | **`480.18
ms` (`25.0%`)** | **`+324.40 ms` (`3.10x` time / `3.77x` share)** |
| **Both GPU Streams Idle in Prefill** | `293.64 ms` (`12.5%`) |
**`84.03 ms` (`4.4%`)** | **`83.47 ms` (`4.3%`)** | **`-209.61 ms`
(`-71.4%` idle bubble)** |
| **48-Layer Target Verify CUDA Graph Duration (`ms/pass`)** | `84.11
ms/pass` | **`53.36 ms/pass`** | **`38.91 ms/pass`** | **`-30.75 ms`
(`-36.6%`) / `-45.20 ms` (`-53.7%`)** |
| **`MoEPackedDoorbellWaitKernel` (`48` calls/cycle)** | `53.40 ms/cyc`
(`60.6%`) | **`26.91 ms/cyc` (`47.2%`)** | **`9.66 ms/cyc` (`22.7%`)** |
**`-49.6%` (`1.98x` shorter) / `-81.9%` (`5.53x` shorter)** |
| **`MatMulPackedBf16TcWarpKSplit<4, 1>` (`72` GDN calls/cycle, `N <=
2560`)** | `9.44 ms/cyc` (`131.1 us/call` on `<4,2>`) | **`5.15 ms/cyc`
(`71.6 us/call`)** | **`5.17 ms/cyc` (`71.8 us/call`)** | **`-4.29
ms/cyc` (`-45.4%` per-call speedup)** |

## Testing

- `pytest onnxruntime/test/python/transformers/test_gguf_packed_ops.py`:
passes CPU/CUDA/hybrid offload numerical parity and tail-substitution
tests on H200 (`sm_90`).
- End-to-end `2K / 8K / 32K / 128K` context benchmarks and 20-item
MMLU-Pro smoke evaluation under both `30 GiB VRAM + 50 GiB RAM` and `22
GiB VRAM + 24 GiB RAM` settings.

## Checklist

- [x] Tests verified (`test_gguf_packed_ops.py` and MMLU-Pro smoke
evaluation)
- [x] No breaking changes
- [x] Documentation updated

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description
<!-- Describe your changes. -->

Replace the Android setup action's `coreutils`/`ninja-build`
installation and the separate React Native Ninja installation with
offline Ninja version and path checks.

### 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. -->

The Linux runner image already provides coreutils and provisions Ninja
independently of the Debian package. Installing `ninja-build` can
overwrite the image-provided executable and unnecessarily depends on
Ubuntu mirrors; [DNS failures blocked Android
jobs](https://github.com/microsoft/onnxruntime/actions/runs/43042030824/job/130596064083)
at this step.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
### Description
<!-- Describe your changes. -->

Move DirectML compilation in `.github/workflows/windows_dml.yml` to
`ort-github-win-16-amd-scus-ss`, with a dependent test job on the
existing `ort-github-win-6-a10-scus-ss` GPU pool. Preserve the existing
`Windows GPU DML CI Pipeline` check name on the GPU test job.

- CPU: explicit `--update --build --skip_tests`, retaining the original
Visual Studio generator, WCOS/BinSkim settings, vcpkg cache, Python
3.12, C# configuration, documentation/delegate validation, NuGet setup,
and DirectML wheel packaging.
- GPU: install the produced wheel, then run explicit `build.py --test`
with all original feature/test flags. No configure, compilation, wheel
rebuild, or NuGet restore target runs here. Fix `setup_dml_build` so
test-only invocations do not implicitly call `cmake --build --target
RESTORE_PACKAGES`.
- Hand off the runtime output tree, nested CTest registrations, and any
ONNX backend fixtures present in the original build. Relocate producer
build/source/Python/CMake paths, retain runtime DLLs/Python
packages/test fixtures (including hidden files), and exclude native
objects/libraries/debug symbols and dependency build trees. Fail on
missing required test binaries, Python/DML runtime files, registrations,
or a missing/ambiguous wheel.
- Run build-stage regressions on the CPU runner. Coverage includes
build-only wheel packaging/C# configuration and test-only execution
without build commands. The separate `test_dml_test_artifacts.py` module
was removed as requested; the production `dml_test_artifacts.py` helper
remains.

C# scope: the existing workflow uses `--build_csharp` but not
`--build_nuget`. In the current build driver/CMake code this generates
C# build properties; it does not invoke NuGet packaging or `dotnet
test`. That behavior and the delegate-attribute validation are
preserved, not replaced with a different C# test surface.

**Observed performance:** the [successful split
run](https://github.com/microsoft/onnxruntime/actions/runs/42848703495)
reduced GPU-runner occupancy by approximately **45%** and end-to-end
execution time by approximately **24%**, compared with the average of
three successful main runs
([42838643765](https://github.com/microsoft/onnxruntime/actions/runs/42838643765),
[42861308845](https://github.com/microsoft/onnxruntime/actions/runs/42861308845),
[42863264161](https://github.com/microsoft/onnxruntime/actions/runs/42863264161)).

| Metric | Before: combined GPU job (three-run average) | After: split
jobs | Difference |
| --- | --- | --- | --- |
| GPU-runner time | 1h 48m 53s | 1h 00m 21s | 48m 32s less (45%) |
| End-to-end execution | 1h 48m 53s | 1h 22m 29s | 26m 24s faster (24%)
|
| CPU-runner time | None | 21m 22s | Build moved off GPU |

The CPU build step took **16m 18s**; the GPU test step took **56m 31s**.
Artifact staging, upload, download, and relocation took **1m 19s**
combined. End-to-end is measured from the first job start through the
final job completion, including the split's 46-second inter-job gap but
excluding initial queue time. This is an observed comparison, not a
controlled benchmark; there is one successful split sample so far.

**Workflow scan:** examined all 47 workflow YAML files and all 13 local
composite actions. The only active combined DirectML build/test workflow
is `windows_dml.yml`. The DirectML-capable runtime build in
`windows_gpu_doc_gen.yml` already runs on the CPU pool with a dependent
GPU documentation-generation job. Other DirectML strings in CPU
workflows are package cleanup/reference strings, not DML-enabled build
variants.

Other candidates found, deliberately left unchanged:

| Path | Job / remaining GPU-side work |
| --- | --- |
| `.github/workflows/windows_webgpu.yml` |
`webgpu_static_plugin_build_x64_RelWithDebInfo`: combined native
build/test on GPU (separate work already planned; this PR does not
depend on that branch). |
| `.github/workflows/windows_webgpu.yml` |
`webgpu_external_dawn_build_x64_RelWithDebInfo`: configure/build,
external-Dawn host tests, and package export on GPU. |
| `.github/workflows/windows_webgpu.yml` |
`webgpu_dawn_package_build_x64_RelWithDebInfo`: package-backed
ORT/plugin builds, negative configure checks, and GPU host tests. |
| `.github/workflows/windows-web-ci-workflow.yml` |
`build_onnxruntime_web`: WASM is already downloaded from a separate
build, but NPM packaging and browser tests still share the GPU runner.
This is a JS packaging candidate, not another unsplit native WASM build.
|

Windows CUDA/no-cuDNN/CUDA-plugin/TensorRT and the corresponding Linux
workflows already use CPU-build/GPU-test handoffs. Windows WebGPU
built-in/shared-plugin variants also already have split jobs. No
unrelated workflow/composite action, compiler-cache adoption, or
generator migration is included.

**Validation** (isolated local Python environment; commands run from the
repository root):

- `.\.venv\Scripts\python.exe -m unittest tools.ci_build.test_build_args
-q` — passed, 24 tests after removing the artifact test module.
- `.\.venv\Scripts\python.exe -m ruff check tools\ci_build\build.py
tools\ci_build\test_build_args.py
tools\ci_build\github\windows\dml_test_artifacts.py` — passed.
- `.\.venv\Scripts\python.exe -m ruff format --check
tools\ci_build\build.py tools\ci_build\test_build_args.py
tools\ci_build\github\windows\dml_test_artifacts.py` — passed, three
files already formatted.
- `git diff --check` and `git diff --cached --check` — passed before
commit.
- Parsed the revised DirectML workflow with PyYAML and asserted the
production staging/prepare helper calls remain, the deleted test module
is absent, and the remaining build-stage regression invocation is intact
— passed.
- Initial split validation also parsed all 60 workflow/composite YAML
files and all six DirectML PowerShell steps. Assertions comparing
original build options (only stage/skip flags differ),
triggers/concurrency/environment/check name, runner/dependency wiring,
artifact identity/guards, wheel ordering, and unchanged unrelated
workflows/actions passed.
- Locally reproduced the telemetry launcher failure with a missing
producer CMake path, then confirmed both nested CTest launchers executed
after relocation, including forward-slash and escaped Windows paths.
Missing producer/consumer CMake checks failed explicitly as intended.
- [DirectML CI run
42848703495](https://github.com/microsoft/onnxruntime/actions/runs/42848703495)
at commit `0b1507622bc29e9cd1e757e17a65a8653b08bc96` — passed both the
CPU build and GPU test jobs, verifying the artifact handoff and fixing
the four telemetry shutdown tests that previously retained the CPU
runner's absolute CMake path.

Full native DirectML compilation, production wheel installation, GPU
test execution, and the actual GitHub artifact transfer were not run
locally; they were verified by the successful CI run above. No workflow
was manually dispatched and no live cache was modified.

### 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. -->

Use the established 16-core Windows CPU pool for compilation instead of
occupying the six-core GPU pool. Reserve the GPU runner for backend
execution while retaining the existing DirectML CI coverage and
validation settings. The observed successful run saves approximately 49
GPU-runner minutes per invocation and completes approximately 26 minutes
sooner than the recent main-run average. This is an independent PR based
on main, separate from the WebGPU/static-plugin and macOS caching work.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…microsoft#34199)

### Description
<!-- Describe your changes. -->

Move the existing per-type `HasCudaEnvironment(is_float16 ? 530 : 0)`
check to the start of `RunModelWithRandomInput`, before constructing the
random generator, allocating token offsets, or generating inputs,
weights, and biases. Unsupported environments now report `GTEST_SKIP()`
before any `OpTester` is constructed.

The shared guard covers `TestWithRandomData`,
`TestWithRandomDataWithRBP`, and `TestWithRandomDataLargeSeq`. Supported
GPU FP32/FP16/RBP/large-sequence dimensions, seeds, inputs, tolerances,
reference comparisons, and minimum CUDA architectures are unchanged. The
guard remains per invocation: lack of FP16 support does not prevent the
mixed-type cases from exercising supported FP32 inputs. No CI, build
optimization, cache, or image changes.

**Validation — head `b8eda7e79f5c9787ae23670802a2179fc0a2418f`:**

- **Linux ARM64 Debug CI: passed.** The [draft PR
job](https://github.com/microsoft/onnxruntime/actions/runs/43470505744/job/132040829102)
built and tested successfully on `ort-github-linux-16-arm64-eus2-ss`,
the same CPU runner pool as the reference. Its provider-test command was
`/onnxruntime_src/build/Debug/Debug/onnxruntime_provider_test
"--gtest_output=xml:/onnxruntime_src/build/Debug/Debug/onnxruntime_provider_test.Debug.results.xml"`
— passed; **7,024 tests selected**, including all three random-data
cases, each explicitly reported skipped. This is not a zero-match pass.
- `git diff --check` — passed.
- `.\.venv\Scripts\clang-format.exe --dry-run --Werror
onnxruntime\test\contrib_ops\packed_attention_op_test.cc` — passed with
clang-format 20.1.8.
- **Windows x64 CPU-only Debug:** in an isolated `.venv`, after `call
"C:\Program Files\Microsoft Visual
Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"`, ran
`.venv\Scripts\python.exe tools\ci_build\build.py --build_dir build\n
--config Debug --update --build --parallel 12 --skip_submodule_sync
--cmake_generator Ninja --target onnxruntime_provider_test
--disable_memleak_checker` — passed. Build log confirms
`packed_attention_op_test.cc.obj` recompiled and the executable
relinked. Cache confirms Debug and CUDA OFF.
- From `build\n\Debug`: `onnxruntime_provider_test.exe
--gtest_filter=PackedAttentionTest.TestWithRandomData*
--gtest_list_tests` — exit 0; listed exactly the three existing
random-data tests.
- From the same directory: `onnxruntime_provider_test.exe
--gtest_filter=PackedAttentionTest.TestWithRandomData*
--gtest_output=xml:C:\Users\erscor\.copilot\session-state\893b4970-454c-4884-9b9c-2c936909fed7\files\packed-attention-cpu-debug.xml`
— exit 0; **3 selected, 3 skipped, 0 failures**. Local x64 XML reports
10 ms / 4 ms / 0 ms for random data / RBP / large sequence; gtest
reports 16 ms suite time, 19 ms including global setup/teardown. These
are separate x64 results, not the ARM64 performance comparison below.

Local build notes: Visual Studio generation first hit Windows'
260-character MSBuild path limit, so validation used Ninja in this
worktree. The initial default Debug executable compiled successfully and
selected/skipped all three tests, but its experimental Windows
memory-leak checker exited -1 at shutdown; even `--gtest_list_tests`
alone reported shutdown leaks. The clean local validation above uses the
repository-supported `--disable_memleak_checker` option locally only;
Debug optimization settings are unchanged. No repository build settings
were edited.

CUDA hardware/runtime is unavailable locally. GPU execution was not
performed locally; the original architecture expression and supported
GPU path were inspected for unchanged behavior. CPU-only runs verify
early gating, not GPU numerical correctness.

### 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. -->

The CUDA-only random-data tests previously generated large CPU fixtures
before checking whether CUDA was available. **Measured Linux ARM64 Debug
comparison**, using the completed [reference
job](https://github.com/microsoft/onnxruntime/actions/runs/43458960142/job/132000464739)
and successful [after-change draft PR
job](https://github.com/microsoft/onnxruntime/actions/runs/43470505744/job/132040829102):

| Test (`PackedAttentionTest.` prefix) | Before | After | Saved |
| --- | ---: | ---: | ---: |
| `TestWithRandomData` | 266,632 ms | 4 ms (skipped) | 266,628 ms |
| `TestWithRandomDataWithRBP` | 133,346 ms | 3 ms (skipped) | 133,343 ms
|
| **Two reported slow tests** | **399,978 ms** | **7 ms** | **399,971 ms
(~6m40s)** |
| `TestWithRandomDataLargeSeq` | 10,943 ms | 0 ms reported (skipped) |
10,943 ms |
| **All three helper callers** | **410,921 ms** | **7 ms** | **410,914
ms (~6m51s)** |

The reported slow pair's runtime fell by **99.998%**, measured on the
same ARM64 Debug CPU runner pool. Millisecond timings are rounded by
gtest; 0 ms does not mean literally zero elapsed time.

The whole provider-test CTest entry went from **2,112.21 s to 1,706.48
s**, an observed reduction of **405.73 s (19.21%)**. Treat that as
descriptive, not a controlled whole-suite attribution: the reference
selected **7,019** tests and the PR merge selected **7,024**, and these
are different CI runs/commits. The pair alone accounted for 18.94% of
the reference provider-test time; all three accounted for 19.45%.

The supplied cold-run reference pair is consistent (266,686 + 133,286
ms); the supplied ARM64 Release reference pair was 2,333 + 1,170 ms. The
additional ARM64 Release measurements are reported below; no GPU
performance timings are claimed.

Independent change based on `main`; does not modify or stack on microsoft#34163
or the ccache experiment.
#### Cross-platform impact

Combined gtest time for all three existing random-data tests (including
the large-sequence case):

| Configuration | Before | After | Saved |
| --- | ---: | ---: | ---: |
| Linux ARM64 Debug | 410,921 ms | 7 ms | 410,914 ms |
| Linux x64 Debug + ASan | 56,309 ms | 6 ms | 56,303 ms |
| macOS ARM64 Debug | 14,912 ms | 0 ms reported | 14,912 ms |
| Windows x64 Release (two executions) | 6,625 ms | 2 ms | 6,623 ms |
| Linux ARM64 Release | 3,598 ms | 1 ms | 3,597 ms |
| Linux x64 Release | 2,442 ms | 0 ms reported | 2,442 ms |
| Linux x64 Release / Python 3.14 | 2,451 ms | 0 ms reported | 2,451 ms
|

**Total measured aggregate test execution removed: 497,242 ms
(8m17.242s)** across these jobs, not an equivalent decrease in elapsed
PR/CI time. Every after-change occurrence explicitly reports skipped;
all compared jobs succeeded. Windows runs the provider tests twice
(regular and example-plugin executions), and both executions are
included. Gtest rounds timings to milliseconds.

Sources: Linux
[before](https://github.com/microsoft/onnxruntime/actions/runs/43458960142)
/
[after](https://github.com/microsoft/onnxruntime/actions/runs/43470505744);
macOS
[before](https://github.com/microsoft/onnxruntime/actions/runs/43467069151/job/132028944327)
/
[after](https://github.com/microsoft/onnxruntime/actions/runs/43470505763/job/132040830226);
Windows
[before](https://github.com/microsoft/onnxruntime/actions/runs/43467069133/job/132028943543)
/
[after](https://github.com/microsoft/onnxruntime/actions/runs/43470505843/job/132040829952).
Linux compares the earlier experiment reference with this PR;
macOS/Windows use successful main runs at this branch's base commit,
6080d7c. These are separate runs, not
controlled repeated benchmarks.

#### Total workflow elapsed time: estimate versus observation

**No net end-to-end workflow reduction was observed in these particular
run pairs.** Using the first job's `started_at` through the final job's
`completed_at` (excluding initial runner queue delay, but including
later job scheduling gaps), GitHub reports:

| Workflow | Before execution span | After execution span | Observed
change |
| --- | ---: | ---: | ---: |
| Linux CI | 46m31s | 51m06s | 4m35s longer |
| MacOS CI Pipeline | 86m42s | 94m44s | 8m02s longer |
| Windows x64 Release | 33m54s | 34m04s | 10s longer |

Including initial queue time, creation-to-final-job-completion was Linux
49m48s -> 54m33s, macOS 86m46s -> 94m49s, and Windows 43m14s -> 66m28s.
In particular, the Windows after-run waited about 32m24s before its job
started, versus 9m20s before; this is not test runtime.

The fixture savings are directly visible in individual test timings, but
build/configuration/cache state, scheduling, other tests, and different
commits confound whole-workflow comparisons. The ARM64 Debug
provider-test entry itself decreased by 405.73s (19.21%), while the
entire ARM64 Debug job increased from 43m38s to 50m22s; other work more
than offset the test savings in this pair.

**All-else-equal critical-path estimate:** ARM64 Debug was the
last-finishing Linux job in both runs. Removing its measured 410.914s of
fixture work would shorten the reference Linux workflow execution span
from 46m31s to about 39m40s: **approximately 6m51s, or 14.7%**, provided
other timings remain fixed and no other job becomes the bottleneck. This
is a modeled potential wall-clock saving, not an observed workflow
speedup. Savings in parallel Linux jobs do not add to that critical-path
reduction. The measured macOS CPU Debug job was not the final-finishing
job (the ARM64 iPhone simulator was), so its 14.912s saving alone does
not shorten that workflow's critical path. For the single-job Windows
workflow, the isolated all-else-equal saving is about 6.623s (0.33% of
baseline execution time).

Builds that do not execute these tests receive no benefit. Supported
CUDA paths still generate and exercise the original fixtures; no GPU
computation speedup is claimed.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…oft#33921)

### Description
- Add the missing `FLOAT16` case to tensor attribute serialization in
`OrtGraphToProto`.
- Add a `ConstantOfShape` regression test covering `raw_data` and
`int32_data`, verifying the serialized payload and inference with
optimizations disabled.
- All 19 EP graph tests pass.

### Motivation and Context
Valid FP16 tensor attributes were rejected with `Unexpected
ONNXTensorElementDataType with value 10`.

Fixes microsoft#33919.
…soft#34163)

### Description
<!-- Describe your changes. -->

Repair portable, rolling Linux ccache snapshots without adopting sccache
or changing compilers, PCH, build/security flags, or test coverage.
Retain shared snapshots where cold compilation takes at least five
minutes; leave shorter builds on their existing local ccache without
GitHub snapshot restore/save overhead.

- Archive workspace-relative `.cache/ccache` instead of the reusable
workflow's `~/.cache/cache` typo or home-relative paths that depend on
runner workspace depth.
- Share a setup action with a fresh `ccache-linux-v2` namespace. Scope
compatibility to build variant/dependency identity, architecture, and
actual local Docker image ID or host compiler/ccache versions. Publish
unique run-ID/attempt snapshots with only a compatibility-scoped restore
prefix; no broad fallback.
- Publish snapshots only after successful main builds. PRs can restore
but never publish; compatible restores no longer suppress publication of
updated entries. Historical archives are not deleted; normal GitHub
eviction applies.
- Explicitly route the pinned Docker build action to
`/onnxruntime_src/.cache/ccache` through its existing environment prefix
while preserving caller Python setup. Limit cross-UID permissions and
umask changes to compiler-cache contents.
- Apply the measured cost cutoff in
`655926d690efbc406ba4ce5c14a4fe381315cbb6`: remove both snapshot
setup/restore and save from six minimal variants whose **cold build
phase was under five minutes**: custom ops, type reduction, globally
allowed types, minimal without optional features, extended minimal
without optional features, and Android NNAPI. Keep snapshots for
exceptions-disabled minimal, extended minimal, regular without optional
features, and the unchanged reusable Linux callers. Existing local
ccache tools/flags, VCPKG policy, tests, and other settings remain
unchanged. The cutoff is a static policy based on cold measurements, not
warm timings or a runtime threshold.
- Add namespace, publication-policy and eligibility regression tests,
portable archive/cross-UID smoke tests, and cache-contract
documentation. Declare the tests' PyYAML dependency in
`requirements-dev.txt`.

**Real GitHub cache-service cold/warm validation — November 13**

Ran both existing workflows twice through normal branch-specific push
triggers, preserving all six Linux CPU variants, all nine previously
snapshot-enabled minimal variants, the full-build/test-data
prerequisite, original compiler/PCH/security options and tests. The
experiment was isolated on
`eserscor-2026/11/13-branch-ccache-experiment`, not added to this PR.

| Workflow | Cold run | Warm run | Created-to-last-job completion, cold
→ warm |
| --- | --- | --- | ---: |
| Linux CI |
[passed](https://github.com/microsoft/onnxruntime/actions/runs/43448889588)
|
[passed](https://github.com/microsoft/onnxruntime/actions/runs/43458960142)
| 59:02 → 49:48 |
| Linux CPU Minimal Build E2E |
[passed](https://github.com/microsoft/onnxruntime/actions/runs/43448889207)
|
[passed](https://github.com/microsoft/onnxruntime/actions/runs/43458959669)
| 27:17 → 28:47 |

**All 32 jobs passed.** All 15 cold compiler-cache restores missed.
Every cold snapshot save was confirmed in job logs and the GitHub caches
API before the second push. All 15 warm restores matched their
corresponding cold publication exactly, with no
toolchain/Docker-identity mismatch; all 15 warm saves were also
confirmed. This exercised real pinned `actions/cache` restore/save,
**not artifact-based compiler-cache transport**. The ordinary
`test_data` artifact remained unchanged.

Cold commit: `602870c80f0baac6e9c6bd1178dfd91a9f163dc6`. Warm commit:
`bf9737d205e44946522a7e7b3d085f4cd98b3bcb`, an intentionally empty
commit. Both have identical source tree
`571f761d828096a281d5be672f1834ea4c90dd42`. An experiment-only cache
prefix kept these snapshots separate from production main keys. No cache
deletion, custom maintenance, shared-image modification, `actions:write`
grant, manual rerun or GPU workflow expansion was used.

Times below are **cold → warm**, in minutes:seconds. Build means the
standalone Actions compilation-step wall time; starred native
composite/Android rows use `build.py` CMake-build command to
test-start/build-complete timestamps within a combined step. Whole job
includes setup, cache operations, tests and post steps, but excludes
queue/dependency waiting. Hit rates are among cacheable compiler calls,
not all tool invocations. Every measured variant restored
cold=miss/warm=hit, saved both times, and passed both times. The
measurements precede the final six-variant snapshot-policy reduction.

| Variant | Build time | Whole-job time | Warm hits / misses | Hit rate
| Final shared-snapshot policy |
| --- | ---: | ---: | ---: | ---: | --- |
| x64 Debug ASan | 17:05 → 2:37 | 41:46 → 27:22 | 1,364 / 1 | 99.93% |
Keep |
| x64 Release | 16:11 → 0:55 | 33:07 → 16:44 | 1,411 / 2 | 99.86% | Keep
|
| x64 Release Python 3.14 | 16:03 → 1:03 | 32:18 → 20:05 | 1,411 / 2 |
99.86% | Keep |
| x64 MinSizeRel, exceptions disabled | 7:20 → 1:06 | 9:30 → 4:05 | 638
/ 1 | 99.84% | Keep |
| ARM64 Debug | 17:54 → 3:54 | 57:14 → 43:38 | 1,570 / 1 | 99.94% | Keep
|
| ARM64 Release | 17:47 → 0:53 | 28:22 → 11:37 | 1,615 / 2 | 99.88% |
Keep |
| Minimal, exceptions disabled | 5:24 → 1:17 | 8:31 → 5:03 | 622 / 1 |
99.84% | Keep |
| Minimal, custom ops* | 4:17.2 → 0:44.6 | 6:46 → 3:27 | 694 / 1 |
99.86% | Omit: cold build <5m |
| Minimal, type reduction* | 4:17.0 → 0:34.4 | 7:16 → 3:15 | 686 / 1 |
99.85% | Omit: cold build <5m |
| Minimal, globally allowed types* | 4:27.3 → 0:55.0 | 7:14 → 4:18 | 686
/ 1 | 99.85% | Omit: cold build <5m |
| Extended minimal | 5:58 → 1:36 | 9:17 → 5:01 | 734 / 1 | 99.86% | Keep
|
| Regular, no optional features | 8:46 → 2:40 | 11:55 → 6:41 | 705 / 2 |
99.72% | Keep |
| Minimal, no optional features | 4:33 → 0:40 | 7:12 → 3:53 | 449 / 1 |
99.78% | Omit: cold build <5m |
| Extended minimal, no optional features | 4:37 → 0:42 | 6:49 → 4:02 |
470 / 1 | 99.79% | Omit: cold build <5m |
| Android NNAPI* | 3:57.3 → 0:13.2 | 6:36 → 3:09 | 1,100 / 1 | 99.91% |
Omit: cold build <5m |

The unchanged full-ORT prerequisite has no compiler snapshot: its build
step took 14:15 → 15:02 and whole job 16:11 → 17:27
([cold](https://github.com/microsoft/onnxruntime/actions/runs/43448889207/job/131965536019),
[warm](https://github.com/microsoft/onnxruntime/actions/runs/43458959669/job/132000462302)).
The minimal workflow was **90 seconds slower overall** despite faster
snapshot-enabled compilation: that prerequisite was 76 seconds slower,
and warm dependent jobs waited 3:53–4:43 for runners versus 8–12 seconds
cold. Compiler acceleration is not end-to-end workflow acceleration.
This is one sequential pair, not a statistical benchmark; runner,
Docker/setup, existing VCPKG-cache and test variability remain.

**Why ARM64 Debug remains the long tail**

[Warm ARM64 Debug
job](https://github.com/microsoft/onnxruntime/actions/runs/43458960142/job/132000464739):
compilation fell from **17:54 to 3:54**, but tests remained **35:18 cold
/ 35:17 warm**, about **81% of the warm job**. Ccache does not
accelerate test execution; cache restore/save took roughly ten seconds
each.

CTest already uses `--parallel 16`, but the **7,019 provider cases
execute inside one unsharded `onnxruntime_provider_test` process**. That
entry took 2,112.85 seconds cold / 2,112.21 seconds warm;
`onnxruntime_test_all` finished in 340.30 seconds warm. Eight provider
cases account for 1,417 seconds, approximately 67% of its wall time.

- `MatMulNBits` cases total about **14m13s**; `Float16_4b_Accuracy4`
alone takes **4m48s** and includes a large 369×6144×2048 regression
case.
- Two `PackedAttentionTest` random-data cases take **6m40s combined**,
despite this being CPU-only.
[`RunModelWithRandomInput`](https://github.com/microsoft/onnxruntime/blob/0acfa78a809f0719280f913861a53692252bb8ad/onnxruntime/test/contrib_ops/packed_attention_op_test.cc#L798-L925)
generates inputs, weights and biases **before** its `HasCudaEnvironment`
check. The two loops make 120 calls and generate approximately 212
million Gaussian weight values even when CUDA is unavailable. The same
two tests take about 3.5 seconds combined in the measured ARM64 Release
job.
- `ReduceSum_batch_by_seq_by_128` takes **3m24s** across 90 large-shape
cases; `Gather_overflow_check` takes **1m49s** and deliberately creates
an output just over 2 GiB plus reference/output copies.

This is reproducible Debug test/fixture cost, not a cache miss or a
demonstrated runner stall. Moving CUDA availability checks before unused
fixture generation and sharding the provider-test executable are
separate potential follow-ups; this cache PR does not skip tests or
change Debug optimization/coverage.

**Validation**

Final eligibility policy at `655926d690efbc406ba4ce5c14a4fe381315cbb6`:

- `wsl -d Ubuntu-24.04 --exec bash -c 'source
/tmp/ort-ccache-ci-305f4061-venv/bin/activate && python3 -m unittest
tools.ci_build.test_linux_ccache -v'` — **7 tests run: 6 passed, 1
optional Docker skip**.
- Normalized YAML comparison against the original main baseline —
**passed**: both workflows retain identical non-snapshot build/test
settings, compiler/PCH/security flags, tool setup, VCPKG policy and
coverage.
- `actionlint -shellcheck= -pyflakes=
.github/workflows/reusable_linux_build.yml
.github/workflows/linux_minimal_build.yml` with actionlint 1.7.12,
compared with the pre-cutoff baseline — **no new diagnostics**; the same
10 existing custom-runner-label diagnostics remain. Shellcheck and
pyflakes disabled for this comparison.
- `git diff --check` — **passed**. Final policy committed and pushed;
normal PR CI is triggered, not claimed complete here. The four
successful experiment runs above validate the repair before the final
eligibility-only reduction, not this new head's CI.

Earlier repair validation retained as supporting evidence:

- `python -m pip install -r requirements-dev.txt` — **passed in clean
Linux and Windows virtual environments**, including PyYAML. Both tooling
CI jobs and Python format passed after the dependency fix:
https://github.com/microsoft/onnxruntime/actions/runs/43354291711 .
- `python -m pytest -c .github/workflows/tooling_tests.pytest.ini
--rootdir=. -v` — **198 passed, 3 skipped, 206 subtests passed** on the
native Linux source copy before the eligibility reduction.
- `ORT_CCACHE_DOCKER_IMAGE=ort-ccache-smoke:305f4061 python3 -m unittest
tools.ci_build.test_linux_ccache -v` — original **6 tests passed, no
skips**, covering differing workspace depths,
external-action/direct-Docker environments, UIDs 1001/1002 and host
access to container-created entries.
- `python -m ruff check tools/ci_build/test_linux_ccache.py` and `python
-m ruff format --check tools/ci_build/test_linux_ccache.py` — **passed**
on the earlier repair, including repository-pinned ruff 0.12.12
validation.
- A prior [artifact-transfer Debug extended-minimal
experiment](https://github.com/microsoft/onnxruntime/actions/runs/43443808349)
achieved 605.728 seconds cold / 76.928 seconds warm, 1,402 direct hits /
zero misses; its temporary workflow/helper were removed. The
full-workflow cache-service measurements above supersede that narrower
experiment as the principal evidence.

Raw logs, exact per-job cache keys, compiler counters,
configure/build/test/cache timing JSON and CSV were retained with the
experiment report. The main-only publication policy is
regression-tested; the experiment validates branch-scoped cache-service
publication/consumption, not main-to-PR visibility after merge. No GPU
performance claim is made, and unmeasured reusable callers retain their
existing policy.

### 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. -->

The reusable workflow saves a path that does not contain its compiler
cache, while minimal builds can restore immutable historical archives
containing relative traversals to an obsolete runner home/workspace
layout. Static exact-match keys also prevent populated snapshots from
rolling forward. Fix these root causes while preserving build behavior,
and avoid spending shared snapshot resources on short builds that do not
determine the workflow's long tail.

Independent fix from main, not stacked on draft microsoft#34109; that PR and its
branch are unchanged. The app branch control only supported a dated
kebab-case name with its automatic prefix
(`eserscor-2026-11-12-linux-ccache-repair`), not the requested
slash-separated branch format.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ft#34127)

### Description
<!-- Describe your changes. -->

Adds a full (unreduced) native WebGPU EP Asyncify WebAssembly build,
`ort-wasm-simd-threaded-full.asyncify.{wasm,mjs}`.

### 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. -->

JSEP migration work.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…32 GDN kernels (microsoft#34200)

## Summary
This PR optimizes CUDA prefill and speculative-decode (`M = 8` verify)
kernels across `MatMulPacked`, `MoEPacked`, `DynamicSparseAttention`
(`fp16_kv`), `HyperConnectionLowRankMix`, `GatedDeltaNet` (`fp32`
state), and `QMoE` helper launches for Qwen3.8-Flash-Next GGUF
(`UD-IQ3_XXS`) and `QMoE` (`2b375_fp32`) models:

1. **`MatMulPacked` `Q6_K` Contiguous Half-Superblock (`kChunk = 128`) &
Aligned SWAR Unpack** (`gguf_quant_cuda.cuh`, `matmul_packed.cu`):
- Assigns contiguous 128-element `Q6_K` half-superblocks per warp
(`LoadQ6KHalf128Stage` + `DecodeQ6KHalf128GroupBf16x2` SWAR unpack) in
`MatMulPackedBf16TcWarpKSplitKernel` (`KW=10, MT=1` for `N<=1024`;
`KW=8` for `K=6144, N<=2560`; `KW=4, MT=2` for `N>2560`) and enables
`Q6_K` in `MatMulPackedBf16DequantFastKernel`.
- Cuts `MatMulPacked` decode time from `19.60 -> 13.48 ms/cycle` (`-6.12
ms/cyc`; `N=512` `Q6_K` latency drops `5.5x` from `33.8 us -> ~6.1 us`).
2. **`MoEPacked` Contiguous `kChunk = 128` (`IQ3_XXS`, `IQ2_S`,
`IQ4_XS`) FC1 Decode & Aligned 36B Pair (`IQ4_NL`) FC2 Decode**
(`gguf_quant_cuda.cuh`, `moe_packed.cu`):
- Hoists superblock scale/sign loads across 4 sub-blocks per warp in
`MoEPackedFc1DecodeWarpKSplitKernel` with 4-way bank-replicated
`iq3xxs_grid` (`s_lut[1024]`), and decodes 4-byte-aligned 36B (`2 x
block_iq4_nl`) pairs (`DecodeIq4NlPair64AlignedBf16x2`) in
`MoEPackedFc2Bf16TcKernel<1, kGgmlTypeIQ4_NL>` (`21.47 -> 19.76 ms/cyc`,
reaching `295 GB/s` vs `301 GB/s` peak on RTX Spark).
3. **FP16-KV Tensor-Core `DynamicSparseAttentionFp16TcKernel<kSplitK,
kCandTile>`** (`dynamic_sparse_attention_prefill.cuh`,
`dynamic_sparse_attention_impl.cu`):
- Replaces the scalar `GroupedDecodeDynamicSparseAttentionKernel`
fallback on `fp16_kv` with a split-K `cp.async` Tensor-Core `m16n8k16`
FP16-KV kernel (`kCandTile = 32` on 100 KB/SM GPUs, `P_hi + P_residual`
22-bit probability split) for decode and two-buffer `<false, 64>` for
prefill.
- Speeds up FP16-KV attention decode by **`5.4x` (`2.71 -> 0.50
ms/cyc`)** and 8K prefill by **`1.49x` (`486.0 -> 325.3 ms`)**.
4. **Single-Wave `m16n8k16` Tensor-Core `HcDownTc8Kernel` &
`HcUpPreTc8Kernel` (`rows = 8`) + `NormVec8H2560Kernel`**
(`hyper_connection_low_rank_mix_impl.cu`):
- Replaces 2-wave scalar `LaunchFusedRows<T, 4, 2>` (`3.81 GB/cyc`
weight reads) on `rows=8, branches=4, hidden=2560, rank=320` (BF16) with
single-wave BF16 Tensor-Core kernels (`grid=(6,8,1)` and
`grid=(80,1,1)`) with PDL weight prefetch (`1.27 GB/cyc` = **`3.0x` less
weight DRAM traffic**, saving **`~3.5–4.5 ms/cyc`**), plus 320-thread
`NormVec8H2560Kernel` for prefill.
5. **Fused Dual-A 3-Slice FP32-State `GatedDeltaNetChunkedKernel`**
(`gated_delta_net_mma.cuh`, `gated_delta_net_impl.cu`):
- Hoists `LoadFragA` across slices and fuses `(k @ S0, Qg @ S0, R
epilogue)` (`SmemGemmFp32StateDualS0Bf16`) and `(P @ U, Kd^T @ U)`
(`SmemGemmFp32StateDualUBf16`), reducing 3-slice FP32->BF16 passes per
chunk from `5 -> 3` (`35 -> 12` barriers) while preserving exact 24-bit
IEEE-754 precision (`427.0 -> 343.3 ms` at 8K prefill, `-19.6%`).
6. **Column-Matched CTA Widths in `QMoE` `expandInputRowsKernel` &
`doActivationKernel`** (`moe_kernels.cu`,
`moe_gemm_activation_kernels.cuh`):
- Matches CTA block widths to column vector counts (`320` for
`hidden_size=2560`; `64`/`96` for `inter_size=512/640`), eliminating
69%–75% idle tail threads (`-31 ms` at 8K prefill).

---

## End-to-End Performance & Accuracy (`2K–255K + 1K` on NVIDIA RTX Spark
`SM 12.1`)

### 1. ORT `gguf_ud_iq3_xxs_q8_engram` (`DFlash2 K=7`) vs. Baseline &
`llama.cpp + MTP` (`UD-IQ3_XXS + Q8_0`)

| Context (`Prompt + Gen`) | ORT Baseline TTFT / Decode (`ms/cyc`) |
**ORT Optimized TTFT / Decode (`ms/cyc`)** | `llama.cpp + MTP` TTFT /
Decode | **ORT Opt vs. `llama.cpp + MTP`** |
|---|---:|---:|---:|---:|
| **`2K + 1K`** | `1.509 s` / `52.71 tok/s` (`67.62 ms`) | **`1.468 s` /
`66.70 tok/s` (`52.53 ms`)** | `2.582 s` / `57.81 tok/s` | **`1.76x`
prefill / `+15.4%` decode** |
| **`8K + 1K`** | `5.468 s` / `46.42 tok/s` (`67.81 ms`) | **`5.231 s` /
`66.49 tok/s` (`53.80 ms`)** | `9.616 s` / `54.22 tok/s` | **`1.84x`
prefill / `+22.6%` decode** |
| **`16K + 1K`** | `10.822 s` / `51.75 tok/s` (`67.24 ms`) | **`10.425
s` / `61.24 tok/s` (`54.06 ms`)** | `19.331 s` / `58.48 tok/s` |
**`1.85x` prefill / `+4.7%` decode** |
| **`32K + 1K`** | `21.663 s` / `48.44 tok/s` (`68.34 ms`) | **`20.929
s` / `63.54 tok/s` (`54.76 ms`)** | `40.822 s` / `54.69 tok/s` |
**`1.95x` prefill / `+16.2%` decode** |
| **`64K + 1K`** | `44.858 s` / `53.26 tok/s` (`70.09 ms`) | **`42.684
s` / `58.04 tok/s` (`57.23 ms`)** | `81.592 s` / `50.67 tok/s` |
**`1.91x` prefill / `+14.5%` decode** |
| **`128K + 1K`** | `94.444 s` / `42.02 tok/s` (`72.02 ms`) | **`91.288
s` / `59.12 tok/s` (`58.06 ms`)** | `172.053 s` / `45.89 tok/s` |
**`1.88x` prefill / `+28.8%` decode** |
| **`255K + 1K`** | `206.564 s` / `42.15 tok/s` (`81.71 ms`) |
**`201.523 s` / `45.41 tok/s` (`67.65 ms`)** | `378.801 s` / `33.42
tok/s` | **`1.88x` prefill / `+35.9%` decode** |

### 2. ORT `rc6_2b375_fp32` (`DFlash2 K=7`, `fp16_kv + FP32 GDN`) Before
vs. After

| Context (`Prompt + Gen`) | Baseline TTFT (`Prefill tok/s`) |
**Optimized TTFT (`Prefill tok/s`)** | Baseline Decode (`ms/cyc`) |
**Optimized Decode (`ms/cyc`)** |
|---|---:|---:|---:|---:|
| **`2K + 1K`** | `1.232 s` (`1,661.9`) | **`1.204 s` (`1,700.5
tok/s`)** | `62.78 tok/s` (`54.68 ms`) | **`81.20 tok/s` (`47.91 ms`,
`-12.4%`)** |
| **`8K + 1K`** | `4.607 s` (`1,778.1`) | **`4.352 s` (`1,882.3
tok/s`)** | `63.91 tok/s` (`54.44 ms`) | **`76.47 tok/s` (`48.65 ms`,
`-10.6%`)** |
| **`32K + 1K`** | `18.642 s` (`1,757.8`) | **`17.589 s` (`1,862.9
tok/s`)** | `58.34 tok/s` (`56.02 ms`) | **`65.65 tok/s` (`50.11 ms`,
`-10.5%`)** |
| **`128K + 1K`** | `81.111 s` (`1,616.0`) | **`77.106 s` (`1,699.9
tok/s`)** | `48.82 tok/s` (`58.37 ms`) | **`51.38 tok/s` (`53.52 ms`,
`-8.3%`)** |
| **`255K + 1K`** | `179.976 s` (`1,450.9`) | **`172.099 s` (`1,517.3
tok/s`)** | `51.17 tok/s` (`68.93 ms`) | **`50.52 tok/s` (`63.08 ms`,
`-8.5%`)** |

## Validation
- Multi-arch CUDA compilation verified cleanly across `sm_75`, `sm_80`,
`sm_86`, `sm_90`, and `sm_120f` with `-Werror all-warnings --Werror
default-stream-launch`.
- Speculative (`M = 8`) vs. `--force-reject` (`M = 1`) greedy
equivalence verified `128/128` (`100%` bit-identical) on both
`rc6_2b375_fp32` and `gguf_ud_iq3_xxs_q8_engram`.
- MMLU-Pro shard `0/80` (`10` items): `9/10` (`90%`, matching baseline
item-for-item) on `rc6_2b375_fp32` and `10/10` (`100%`) on
`gguf_ud_iq3_xxs_q8_engram` with `0` truncations.
- Added unit tests in `matmul_packed_precision_test.cc`,
`gguf_quant_packed_test.cc`, and `dynamic_sparse_attention_op_test.cc`.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…icrosoft#34169)

### Description

Each QMoE/MoE kernel instance owns a MoeGemmProfiler with a private
(GemmId, M bucket) cache. A model whose MoE layers all have the same
shape therefore profiles the identical problem once per layer for every
new M bucket. Qwen3-30B-A3B has 48 such QMoE nodes.

This change shares successful profiling results process-wide. The key
holds everything a profiling run reads:
- the runner type;
- runner state that changes the candidate tactics (SM80 FP4 family) or
the profiled GEMM2 epilogue (deterministic Hopper reduce);
- the device;
- every GemmProfilerBackend::init parameter;
- the GemmId and the M bucket.

This is the in-process part of the QMoE cross-node dedup planned in
docs/contrib_ops/cuda/gemm_profiler_cache.md (section 8, phase 2). It
follows the process-wide profile map that MatMulNBits shares through
GemmPluginProfilerManager (matmul_nbits.cc), with two differences:
- Coordination is per key. A short map lock hands out the key's entry,
and only that entry's mutex is held while it is profiled. Concurrent
first uses of one key profile it once, while other problems, M buckets
and devices profile in parallel.
- Only successful results are shared, as the design doc requires for the
MatMulNBits cache. A run that returns no config (for example after a
transient allocation failure) is kept by that profiler instance as
before, and the next profiler retries instead of reusing the failure.

The cache is intentionally leaked, like the MatMulNBits tactic cache
registry, because a CUDA EP owned by another static can be destroyed
after this library's statics. ORT_DISABLE_MOE_SHARED_TACTIC_CACHE=1
restores per-instance profiling and is documented in
gemm_profiler_cache.md. MoeGemmProfiler::ProfilingRunCountForTesting()
is a read-only counter that only the tests use.

Tests (moe_gemm_profiler_shared_cache_test.cc):
- IdenticalProblemsAreProfiledOncePerProcess and
RunnerStateThatChangesProfilingIsPartOfTheKey: sharing works, and runner
state that changes tactics keeps results apart.
- FailedProfilingIsNotShared: a failed run is retried by the next
profiler.
- ConcurrentFirstUsesOfOneKeyProfileOnce: four threads that reach one
key profile it once.
- OtherKeysProfileWhileOneIsInFlight: a second problem profiles to
completion while the first is held inside its workspace allocation.

FailedProfilingIsNotShared and OtherKeysProfileWhileOneIsInFlight fail
against an earlier, unpublished draft of this change that held one
global lock while profiling and cached failed results. With sharing
forced off, the four sharing tests fail.

Measured on an A100 80GB, main (6596e0c) vs this change:
- Qwen3-30B-A3B-Instruct-2507 through ORT GenAI, 32,640-token prompt,
builds run in A-B-B-A order:
- Cold time to first token is 82,465 and 83,704 ms on main vs 5,524 and
5,630 ms with this change.
- Warm time to first token changes by -0.21% (95% CI -0.26% to -0.17%,
10 requests).
  - Generated tokens are identical, and peak memory is the same.
- Decode measured -0.65% (95% CI -1.12% to -0.18%). Decode at 8 expanded
rows runs the GEMV path, which uses no profiled tactic, so I read this
as run-to-run drift rather than an effect of the change.
- Multi-turn chat in one session, with prompts of 2,048, 8,192, 16,384
and 32,640 tokens. Time to first token for turns 1 and 2 is 798 and
2,347 ms instead of 22,922 and 79,956 ms. Turn 4 completes; on main it
runs out of memory, because each node's profiling request leaves a 1 GiB
arena region (fixed separately in
microsoft#34167).
- 48 same-shape QMoE nodes built from layer 0 of that model, first run
with profiling at 2,048 rows: 22,916 ms to 811 ms (10 interleaved
pairs), with identical outputs.

### Motivation and Context

On Qwen3-30B-A3B-Instruct-2507 at a 32,640-token prompt on an A100,
profiling dominated the first request: 82.5 s cold time to first token
versus about 3.4 s warm. Most of that was the same two GEMMs being
profiled 48 times.

Limits:
- Results are shared only inside one process, with no disk persistence.
That is still future work in the design doc.
- A key that never yields a config is profiled again by every node, as
each node did before.
- Tested on SM80 Linux. CI covers SM86, Windows and the plugin EP build.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Discovered when trying to use RandomNormal (opset 22) in a unit test:

RandomNormal, RandomNormalLike, RandomUniform, RandomUniformLike and
Multinomial were revised in ONNX opset 22, but their CPU kernels stayed
registered at their original start version with no end version, which
matches that version exactly. As a result these ops had no CPU kernel at
opset 22+. Cap the old registrations at 21 and add new ones at 22, the
same split EyeLike and the CUDA Random kernels already use.

Type constraints are unchanged (float and double).

### Description

Splits the CPU kernel registrations for `RandomNormal`,
`RandomNormalLike`, `RandomUniform`,
`RandomUniformLike` and `Multinomial` at opset 22: the existing
registrations are capped with an
end version of 21, and a new registration is added at 22 for each op.
`docs/OperatorKernels.md` is
regenerated to match, and each op gets an opset 22 test.

Type constraints are unchanged — the opset 22 registrations declare the
same `float`/`double`
constraints as the earlier ones.

### Motivation and Context

All five ops were revised in ONNX opset 22, but their CPU kernels stayed
registered at their
original start version (1, or 7 for `Multinomial`) with no end version.
A kernel registered that
way matches its start version *exactly*: `VerifyVersion` in
`kernel_registry.cc` only takes the
range branch when `kernel_end_version != INT_MAX`, on the reasoning that
without an end version ORT
cannot know whether a later op revision added something the kernel
mishandles. Since the version
that gets matched is the op's schema `since_version` — 1 for opsets 1-21
and 22 for opsets 22+ —
these ops had no CPU kernel at all at opset 22 and later.

Version matching happens before type matching, so this is not
type-specific: an opset 22
`RandomNormal` with `dtype=float`, squarely inside the registered type
constraints, still failed
with `Could not find an implementation for RandomNormal(22)`.

`EyeLike` was revised in the same opset and was updated at the time; it
shows the intended pattern
of capping the old registration and adding a new one. CUDA already has
that split for the four
Random ops, so this was CPU-side drift. This PR applies the same
treatment to all five ops.

Opset 22 also widened these schemas to the full set of float types by
adding `bfloat16`. That is
deliberately not implemented here — supporting a new dtype is a separate
feature, whereas this
change restores a working kernel lookup for the types already supported.

#### On the tests

`OpTester`'s default `Run()` pre-assigns every node to an EP and, when
no EP has a matching kernel,
logs a warning and returns without failing. The obvious version of these
tests therefore *passed*
against the unfixed code. The new tests run with an explicitly specified
CPU EP, which leaves node
assignment to the graph partitioner, so a missing registration surfaces
as a session initialization
failure. All five new tests were verified failing before this change and
passing after.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ll rows (microsoft#34168)

### Description

CutlassMoeFCRunner reserves an FP32 split-K partials buffer for the
fused SwiGLU MoE GEMV (FP16 activations, INT4 weights, swiglu_fusion ==
1, see MoeGemvSplitK2SwiGLUSupported) and sized it for every expanded
row of the call. Its only reader is the split-K two-pass GEMV. That path
runs only when is_moe_gemv_supported() accepts the problem, which needs
expanded_num_rows <= moe_gemv::kMaxProfiledExpandedRows (80), and only
with FP32 GEMV accumulation (ORT_MOE_GEMV_FP32_ACCUM=1). Above 80
expanded rows the grouped GEMM runs and the buffer is never read, so at
prefill sizes the workspace carried a buffer that grows with the prompt
and is never used.

This change caps the partials at 80 expanded rows. Calls with up to 80
expanded rows get exactly the same size as before; larger calls keep a
fixed 2 * 80 * 2 * inter_size * 4 bytes (0.94 MiB for inter_size 768).

Tests:
- QMoEWorkspaceTest.SplitKSwiGluPartialsDoNotScaleWithPrefillRows fails
on main (per-token growth at GEMV sizes 176,640 B, needs at least
225,857 B) and passes with this change.
- QMoEWorkspaceTest.SplitKSwiGluPartialsCoverGemvRows checks that
GEMV-sized calls still get the full buffer.

Validation on A100 80GB (SM80), using layer 0 of
Qwen3-30B-A3B-Instruct-2507 (INT4, block 128, top-8, 128 experts) as a
standalone QMoE model, main vs this branch:
- Outputs are bitwise identical at 8, 80, 88 and 1024 expanded rows,
both with ORT_MOE_GEMV_FP32_ACCUM=1 and with the default.
- With ORT_MOE_GEMV_FP32_ACCUM=1, Nsight Systems shows
moe_gemv_splitk_partials_kernel and moe_gemv_splitk_reduce_swiglu_kernel
launching at 8 and 80 expanded rows, and no GEMV kernels at 88 and 1024.
- compute-sanitizer memcheck reports 0 errors on those runs. memcheck
alone would not catch an undersized buffer, because the partials share
one workspace allocation with the other buffers. As a control, halving
the cap changes the output at 80 expanded rows while memcheck still
reports 0 errors, so the parity check is the meaningful one.
- End to end with the full model through ORT GenAI at a 32,640-token
prompt and ORT_MOE_GEMV_FP32_ACCUM=1 (one process per build): process
peak 47,248 MiB on main vs 43,152 MiB with this change, identical
generated tokens, decode 126.2-126.6 vs 126.3-126.6 tokens/s. The buffer
is reserved the same way with the default accumulation. An earlier run
of the same change on main at e4234e5 measured a peak of 47,254 vs
43,158 MiB in that mode (two processes per build, identical in each).

### Motivation and Context

For Qwen3-30B-A3B at a 32,640-token prompt the partials buffer was 2 *
261,120 * 1,536 * 4 B = 3,059 MiB of workspace that was never read.

Limits:
- Only the FP16 + INT4 + fused-SwiGLU runner allocates this buffer, so
other dtypes and activations are unaffected.
- The small capped buffer is still reserved when FP32 accumulation is
off. Dropping it entirely would tie the workspace layout to that
environment variable, so this PR leaves it.
- Tested on SM80 Linux only. CI covers SM86 and Windows.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
### Description
Replace the CUDA device-side `printf` used for INT3 QMoE compatibility
counters with a host-side device-to-host counter readback and flushed
stdout report. Update the test to require zero missed corrections in
both FC1 and FC2 reports.

### Motivation and Context
The Windows CUDA CI test selects the Tensor Core path but does not
capture the device-side `missed=0` report, causing
`test_cuda_int3_tensor_core_compatibility_shadow` to fail. Host-side
reporting makes the verification output capturable by the test while
preserving its checks.

Validation: Python syntax check and `git diff --check` passed. The CUDA
regression test was not run locally; the available T1000 does not
support the BF16 Tensor Core path required by this test.

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…#34167)

### Description

MoeGemmProfiler::runProfiling took its one-off profiling workspace from
the temp-space allocator with a stream-less Alloc(). With the default
CUDA EP that allocator is the BFC arena, which keeps every region it
grows. A stream-less request also cannot reuse a chunk that the compute
stream has used since (BFCArena::FindChunkPtr). So each MoE node that
profiles a new M bucket can leave another workspace-sized region in the
arena for the rest of the session.

This change reserves the scratch instead, the same way the fpA_intB GEMM
profiler already does (IAllocator::MakeUniquePtr with use_reserve = true
in contrib_ops/cuda/llm/gemm_profiler.h). BFCArena::Reserve takes the
memory straight from the device allocator and Free returns it.
Allocators without a Reserve override fall back to Alloc(), so they
behave as before. One example is the plain CUDAAllocator the CUDA plugin
EP uses for temp space.

Because reserved memory goes back to the device on Free, the workspace
guard now synchronizes the profiling stream before freeing. It is
declared after the stream guard, so a private stream outlives it on
every exit path, including exceptions from backend_.prepare() or a
failing tactic.

Test: MoeGemmProfilerTest.ProfilingScratchDoesNotGrowArena profiles
three nodes at two M buckets through a real BFC arena. On main the arena
grows by two extensions (3,145,728 bytes) with no reserves. With this
change it grows by 0 bytes and uses Reserve.

Measured on an A100 80GB, main (6596e0c) vs this change:
- Multi-turn chat with Qwen3-30B-A3B-Instruct-2507 through ORT GenAI,
with prompts of 2,048, 8,192, 16,384 and 32,640 tokens in one session.
After turn 2 the model arena is 17,642 MiB instead of 66,282 MiB. Turn 4
completes instead of failing with out-of-memory, and the arena after
turn 4 is 23,786 MiB.
- Single 32,640-token prompt, builds run in A-B-B-A order, 10 warm
requests per build. Time to first token changes by +0.04% (95% CI -0.01%
to +0.09%) and decode by -0.04%. Generated tokens are identical, and
process peak is 47,266 MiB on main vs 46,946 MiB with this change.
- Profiling cost, on 48 same-shape QMoE nodes built from layer 0 of that
model: the first run, which includes all 96 profiling runs, takes 96 ms
longer (22,916 to 23,012 ms; 95% CI of the difference 64 to 129 ms; 10
interleaved pairs). Arena growth during that run drops from
1,610,612,736 to 536,870,912 bytes in every pair, and outputs are
identical.

### Motivation and Context

In a multi-turn chat with Qwen3-30B-A3B (48 QMoE layers) on an A100
80GB, each new prompt-length bucket made all 48 nodes profile. Each
node's roughly 770 MiB profiling request at the largest bucket left a 1
GiB arena region behind, so the arena grew by about 48 GiB in one turn
and the fourth turn ran out of memory.

Limits:
- Reserve() bypasses BFCArena binning and its gpu_mem_limit check. The
memory is still counted in the arena's total while profiling and
released right after, and the CUDA device memory budget, when
configured, still applies through CUDAAllocator.
- Each profiling run now does one cudaMalloc/cudaFree pair. Profiling
happens once per node and M bucket, and never during CUDA graph capture.
- Tested on SM80 Linux. CI covers SM86, Windows and the plugin EP build.

---------

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

This branch has not been deployed

No deployments
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.