Pull requests / #2584

#2584 sycl: pair FP16 experts and generalize bounded IQ2 decoding on Battlemage

open · @xiangyuT · 0 comments · View on GitHub

Multi-GPUNVIDIA / CUDAModels & quantsWindowsLinux

Description

## Summary

Small FP16 expert groups submit gate/up and down work separately for each expert. Pair two eligible experts and reuse IQ2_XXS metadata; bound IQ2_S gate/up decoding without repeating its lane permutation.

Dispatch reuses upstream `intel_gpu_gen` / `IntelGpuGen::Battlemage`. Hardware measurements below are from B70.

IQ2_XXS/IQ2_S gate/up decoding accepts positive matrix dimensions, input channels divisible by 256, and a combined gate/up FP16 extent below 4 GiB. There is no fixed matrix-shape whitelist. Eight subgroups per work-group may cross rows; a rounded reciprocal and exact correction compute the row index for arbitrary widths. Unsupported formats and larger extents retain the original decoder. Pairing keeps its separate IQ2_XXS/IQ2_S gate/up, Q2_0 down, geometry and 1–16-row guards. Pending paired work is flushed before staging-slot reuse.

The bounded GU launcher no longer requests root-group synchronization, allowing native recording on its tested optimized paths.

## What changed

`sycl/include/strata/prefill/f16_expert_pair.hpp`, `sycl/src/kernels/cuda/iq_kernels.dp.cpp`, `sycl/src/prefill/prefill.cpp`.

## Dispatch controls

| Control | Unset (default) or `1` | `0` |
|---|---|---|
| `STRATA_SYCL_F16_EXPERT_PAIR` | Pair eligible FP16 expert groups. | Use the original per-expert execution path; bounded gate/up decoding remains independently selectable. |
| `STRATA_SYCL_DEQUANT_GU_BOUNDED` | Enable bounded IQ2_XXS/IQ2_S gate/up decoding and allow its metadata-sharing subpath. | Use the original gate/up decoder, bypassing the metadata-sharing subpath; expert pairing remains independently selectable. |
| **Child of bounded decoding:** `STRATA_SYCL_GU16_METADATA_QUARTET` | Reuse IQ2_XXS (type 16) metadata within the bounded decoder. | Use the generic bounded type-16 decoder; IQ2_S (type 22) and expert pairing are unaffected. |

There is no single master switch for this PR. For full fallback, set both `STRATA_SYCL_F16_EXPERT_PAIR=0` and `STRATA_SYCL_DEQUANT_GU_BOUNDED=0`. The metadata control has no effect when bounded decoding is disabled.

All controls retain the device, format and shape guards described above. Set them before starting the engine and restart it when changing them: their values are cached on first use. They support diagnosis and fallback; normal operation needs no environment-variable setting.

## End-to-end performance: current head versus upstream

PR head: `faab685c2c0c57c24448754873e5ed0b5d931c4c`. Pure upstream comparator: `296b59d2f73c8f04a805df29c2fa97655adace78`. Common frontend: `296b59d2f73c8f04a805df29c2fa97655adace78`. The candidate contains this PR's changes; these same-day measurements compare the complete current PR against upstream.

At each input length, collection order is **upstream before / PR head / upstream after**. Every block starts a fresh engine, excludes one short warmup and three full-input warmups, then measures the same three requests. Each reported comparison uses six upstream and three PR-head measured requests.

Both builds use identical model and runtime settings. This PR's dispatch controls listed above were explicitly set to `1` on both builds, equivalent to the default-enabled candidate dispatch within its guards; pure upstream does not read those controls.

| Input / output tokens | TTFT upstream → PR (s) | Change | TPOT upstream → PR (ms/token) | Change |
| --- | ---: | ---: | ---: | ---: |
| 4096 / 128 | 3.459426 → 3.191718 | -7.738% | 14.312121 → 14.324605 | +0.087% |
| 8192 / 256 | 7.001080 → 6.503171 | -7.112% | 13.608065 → 13.605458 | -0.020% |
| 32768 / 256 | 29.594230 → 27.548379 | -6.913% | 14.085174 → 14.087024 | +0.015% |

TTFT is request-to-first-nonempty-SSE latency. TPOT is first-to-last nonempty SSE arrival divided by actual output tokens minus one (127 or 255). Changes average the three request-wise ratios against the corresponding before/after upstream means. Displayed upstream times average the two baseline blocks; negative changes mean lower latency.

At every input length, token IDs and text matched across both upstream blocks and the PR block for all seven corresponding requests per arm, including the four excluded warmups.
Speculation settings are fixed; suffix window selection is time-adaptive, so actual work counts may differ. Here, windows/offered/accepted matched request by request at all three lengths; per-request means are reported below.
Actual cache capacity: 18609 resident expert slots and 5967 mirrored experts (8.02 GiB); the mirror setting of 16384 MiB is a budget.

<details>
<summary>Paired changes, upstream drift and actual speculative work</summary>

| Input tokens | Three TTFT pair changes | Three TPOT pair changes | Upstream TTFT drift | Upstream TPOT drift |
| --- | --- | --- | ---: | ---: |
| 4096 | -7.669% / -7.708% / -7.839% | +0.073% / +0.084% / +0.104% | -0.021184% | -0.000268% |
| 8192 | -7.107% / -7.153% / -7.076% | -0.042% / -0.035% / +0.018% | +0.048125% | -0.017007% |
| 32768 | -6.894% / -6.933% / -6.912% | -0.015% / +0.056% / +0.003% | +0.019743% | -0.022709% |


Mean windows / offered / accepted per measured request:

| Input tokens | Upstream before | PR head | Upstream after |
| --- | --- | --- | --- |
| 4096 | 54.000 / 111.000 / 74.000 | 54.000 / 111.000 / 74.000 | 54.000 / 111.000 / 74.000 |
| 8192 | 102.667 / 209.000 / 153.667 | 102.667 / 209.000 / 153.667 | 102.667 / 209.000 / 153.667 |
| 32768 | 103.333 / 202.333 / 154.000 | 103.333 / 202.333 / 154.000 | 103.333 / 202.333 / 154.000 |

</details>

## Correctness and native recording

The current code was checked against its pre-correction parent `9d113cfc9bdc17fcc36c0ba3a6e3c3b4cc82f62b` in direct execution and ordinary graph replay: 90 GU cases covering legal dimensions, tails, input offsets and format fallback, plus 14 rejected-argument checks. Complete outputs and sentinels matched the original flat-F16 decoder exactly within each run. The expanded matrix's cross-build comparison used matching output-hash lists.

Five targeted bounded-GU cases failed native graph instantiation before the correction and passed at the current head. Full exported output bytes matched the parent's direct execution in 20 nontrivial cross-build/mode comparisons over those five cases. This native result covers those tested bounded-GU paths; the whole engine and unchanged fallback paths are not validated for native recording.

## Model-shape kernel measurements

Measured earlier at `9d113cfc9bdc17fcc36c0ba3a6e3c3b4cc82f62b`, using synthetic inputs at the model's 640×2560 gate/up geometry. These values were not remeasured at the current head. The standalone comparator selected the original decoder in the same binary; the candidate used the generalized decoder at that measured revision.

| Format | Original → generalized (µs) | Change | Baseline drift |
|---|---:|---:|---:|
| IQ2_XXS | 36.414 → 7.279 | -80.010% | +0.005% |
| IQ2_S | 7.272 → 5.948 | -18.204% | -0.045% |

Each microbenchmark arm used three measured samples, a ≥2-second/1000-call warmup and ≥3 seconds/2000 calls per sample. Times include host submission and final queue wait. These component measurements are separate from the current-head endpoint comparison; kernel percentages are not added to endpoint percentages.

## Test configuration

Intel Arc Pro B70 32 GB; Intel Xeon w5-3435X; Linux/xe; omix 0.4.0 and oneAPI DPC++ 2026.1.1. Container limits: 16 CPUs / 96 GiB RAM. Builds and device execution ran inside the container.

Model: Qwen3.8-Flash-Next-GSQ-RCO IQ2_XS, revision `ed59f92082b1e93c0e96d60a8b11aab089b52f09`. Greedy seed42, thinking off; INT8 KV; max context131072 / resident32768; `--expert-cache 17772` experts; reserve1536 MiB; expert streaming (`--stream-experts`) with `--pcie-frac 0.30`; mirror budget16384 MiB; no prefill borrowing; auto prefill; spec4 / min-p0.5 / suffix3; adapt-every8 / decay1; prompt cache off.

Both builds kept existing settings equal: `STRATA_VERIFY_DEVICE_PLAN=1`, `STRATA_VERIFY_NO_HOST=1`, `STRATA_STAGER_THREADS=12`, `STRATA_MIRROR_MIB=16384`, `STRATA_DECODE_TIMING=1`; `ONEAPI_DEVICE_SELECTOR=level_zero:gpu`, `SYCL_CACHE_PERSISTENT=0`.

The endpoint results are warmed and post-readiness; the host page cache was retained. Profiled requests and warmups are excluded. Runtime and performance validation are limited to B70; other GPUs, Windows and multi-GPU operation remain unvalidated. Changes are confined to the SYCL implementation files listed above; the public documentation diff is empty.

Related on this site

Quick links to related pages.