Repository navigation
Conversation
Signed-off-by: Xiangyu Tian <109123695+xiangyuT@users.noreply.github.com>
Signed-off-by: Xiangyu Tian <109123695+xiangyuT@users.noreply.github.com>
Signed-off-by: Xiangyu Tian <109123695+xiangyuT@users.noreply.github.com>
|
Tested on two Arc Pro B70s: layer split 26,
We investigated (myself and Claude Opus 5.5 in Claude Code) and I reviewed the findings and ran every test on my two Arc Pro B70s on my CachyOS machine. |
|
Thanks for the pull request. We're resetting the tracker for 0.2.0-beta. There are more than 1,300 open issues and pull requests, too many for us to review properly, so we're closing everything that isn't being worked on right now. Closed here does not mean rejected. To reopen it takes about two minutes:
The rules are in CONTRIBUTING.md. |
|
/reopen |
|
The check passed, but GitHub would not reopen it (Validation Failed: ). If the branch was deleted, restore it or open a new pull request and link this one. |
Problem and result
IQ4_XS × Q8_1 decode repeatedly loads headers, packed weights and adjacent activation blocks. This patch shares those loads across quantization groups/token columns and uses an exact bit-select lookup.
2026-10-20 retest on a single Arc Pro B70, 32 GiB container RAM limit, upstream 0.2.0-beta:
upstream/common frontend
e88ee39d1d6be6e3364183af3b39b62a7ed6f211; independent candidate635ebb20c13255250a5b9fc79f2592a8256e5268.All three lengths are complete.
These are standalone-PR results; no other preview optimizations are enabled.
Positive improvement means lower latency: mean of three request-wise
100 × (1 − candidate / mean(upstream-before, upstream-after))values.The displayed upstream time averages both bracketing blocks. TTFT is request-to-first nonempty SSE text;
TPOT is first-to-last nonempty SSE text arrival divided by engine-generated tokens minus one.
Tiny changes near baseline variation do not establish a meaningful improvement.
Related discussion
Source status (2026-10-20): source branch
feat/sycl-iq4-mmvqnow points to the tested candidate635ebb20c13255250a5b9fc79f2592a8256e5268. This PR remains closed; GitHub still reports PR heade5c0c9c69d38c9469c185ba67c0f7d61e0ecc564. All new measurements and validation in this description apply to the tested candidate. Reopening remains for maintainer review.This updates the existing PR after the 0.2.0-beta reset and current contribution requirements; it is not a competing submission.
Scope and reopening remain for maintainer review in this thread. Historical pre-beta evidence is folded below.
Related MMVQ implementation: #2804 / #2803 select KREG kernels at the same entry points. Coordinate shared dispatch hooks with this pair-reuse/lookup path.
Approach
Battlemage only, K=2560/6144 and T=1–6, with alignment/row/shape guards; pair reuse and its Q8-split child require T≤4. The single-column K=2560/N=640 case retains its existing dispatch. Q8 splitting is further limited to selected shapes.
New paths are now opt-in. Every control below is disabled when unset or
0.Set controls before starting the engine and restart after changes because values are cached/read during initialization.
Only the controls for this PR are set to
1in the measured candidate; pure upstream and the candidate-default check leave them unset.1STRATA_SYCL_IQ4_PAIR_REUSESTRATA_SYCL_IQ4_Q8_SPLITSTRATA_SYCL_IQ4_LOOKUPTo disable the complete change, leave all three unset or set both PAIR_REUSE and LOOKUP to 0. Q8_SPLIT has no effect without PAIR_REUSE.
Validation
Passed
bmg-g31engine build. No non-SYCL backend files are changed.Sanitized operator output:
Failed
The initial upstream/default 4K warmup comparison stopped on different output between a first-time calibrating upstream process and subsequent cached processes. All three measured requests matched, but the warmup mismatch was preserved. Restarting the same unmodified upstream binary with the persisted cache matched all seven candidate-default requests. The current comparison excludes that attempt and uses restarted, cached processes throughout. The upstream cache stores a rounded crossover; the controlled result establishes the initialization-state difference, without isolating every numerical cause.
Not run
Runtime scope for this retest is the single B70/Linux/AOT setup below. Other GPUs, Windows, multi-GPU serving, JIT and whole-engine native recording were not revalidated.
Old cross-target compilation, broad prompt/logit corpora and historical microbenchmarks are not new-head evidence.
CUDA/HIP/Metal were not built: this patch touches only the separate SYCL implementation.
Environment, exact build settings and complete launch example
6.17.0-1007-intel, Intel xe; Xeon w5-3435X, host MemTotal 503.36 GiB.0000:cc:00.0; only that card is visible to the test container (logical GPU0).intel/omix:0.4.0-devel-ubuntu24.04, image IDsha256:53f0003fa66044935d69065836ba8ac40fab289b94655667fdeac0bdfa7e75c6.2026.1.1; compute runtime26.31.39395.13, device driver1.17.39395+13.--memory 34359738368 --memory-swap -1 --cpus 16 --shm-size 1g; one client, no batching. This is a cgroup limit on a larger host, not validation of a physically 32 GiB machine.llama.cppdependency3cf03257f219afbe7334045ff7c6a06ac68c627d; TLA disabled.ed59f92082b1e93c0e96d60a8b11aab089b52f09.de4b8e4d43b917e7706784d8bb445c9af86a3540; observed draft vocabulary106299(137.9 MiB head).Build the candidate with the following commands in the oneAPI environment. Build the upstream comparator identically,
substituting
/sources/baselineand/task/build-baseline. Sources are pinned to the full commits above.The following is a complete candidate configuration sample, not an unexplained environment-variable name.
Save it as
/task/pr2555-candidate.json./sources/baselineis the pinned upstream checkout used for the common Python frontend;/sources/pr2555is the candidate checkout;/taskis the writable test directory./opt/strata-venvis the serving Python environment mounted into the container. The/models/Strata/...paths are mountsfor the already-prepared pack/tokenizer, the two original GGUF shards and MTP runtime. Adjust those paths to the local files.
{ "backend": "sycl", "exe": "/task/build-pr2555/strata", "cwd": "/sources/baseline", "args": [ "--pack", "/models/Strata/ed59f92082b1e93c0e96d60a8b11aab089b52f09/pack", "--native", "/models/Strata/ed59f92082b1e93c0e96d60a8b11aab089b52f09/IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00001-of-00002.gguf", "--ple-gguf", "/models/Strata/ed59f92082b1e93c0e96d60a8b11aab089b52f09/IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00002-of-00002.gguf", "--expert-profile", "/sources/baseline/data/expert-profile.bin", "--expert-cache", "auto", "--stream-experts", "--vram-reserve-mib", "1536", "--no-prefill-borrow", "--prefill", "auto", "--spec", "4", "--spec-min-p", "0.5", "--mtp", "/models/Strata/mtp-Qwen3.8-Flash-Next-de4b8e4d43b917e7706784d8bb445c9af86a3540/rt", "--max-context", "131072", "--kv", "int8", "--adapt-every", "8", "--prompt-cache", "0", "--kv-resident", "32768", "--pcie-frac", "0.30", "--adapt-decay", "1", "--suffix-draft", "3", "--host-core", "last" ], "env": { "ONEAPI_DEVICE_SELECTOR": "level_zero:gpu", "SYCL_CACHE_PERSISTENT": "0", "ZES_ENABLE_SYSMAN": "1", "STRATA_VERIFY_DEVICE_PLAN": "1", "STRATA_VERIFY_NO_HOST": "1", "STRATA_STAGER_THREADS": "12", "STRATA_MIRROR_MIB": "16384", "STRATA_DECODE_TIMING": "1", "ZE_AFFINITY_MASK": "0", "STRATA_CACHE_DIR": "/task/shared-calibration", "STRATA_SYCL_IQ4_PAIR_REUSE": "1", "STRATA_SYCL_IQ4_Q8_SPLIT": "1", "STRATA_SYCL_IQ4_LOOKUP": "1" }, "tokenizer": "/models/Strata/ed59f92082b1e93c0e96d60a8b11aab089b52f09/pack/tokenizer", "model_name": "qwen3.8-flash-next-iq2_xs", "log": "/task/pr2555-candidate.log", "host": "127.0.0.1", "port": 8080, "gpu": 0, "open_browser": false, "parallel": 1, "sampling": { "temperature": 0.0, "seed": 42, "top_p": 1.0, "top_k": 64, "min_p": 0.0, "repetition_penalty": 1.0, "presence_penalty": 0.0, "frequency_penalty": 0.0, "penalty_last_n": 64 } }Direct launch with the same frontend/configuration (the collection harness additionally records engine IPC/output identity):
For the upstream arm, use
/task/build-baseline/strata, another log file, and remove only this PR'sSTRATA_SYCL_*entries.For the candidate-default correctness arm, keep the candidate executable and remove those same entries.
Leave every common setting, frontend and model unchanged. Clear inherited
STRATA_SYCL_*/STRATA_PRIVATE_*variables before launch.Initialize
/task/shared-calibrationin an excluded upstream process, issue a full-length warmup, stop it and restart for timing;all timed processes must read the same unchanged cache rather than calibrating during timing.
Startup checks for the retained run: context
131072, KVint8, resident KV32768, MTP maximum4, suffix lookup3,spec_min_p=0.50,pool_workers=15,pcie_frac=0.30. INFOspec=6is the verifier window with MTP maximum4and suffix drafting enabled.Observed initial resident / mirrored expert counts and mirror GiB: [(17756, 6820, 9.17)]. The
16384MiB setting is the mirror budget, not allocation.Sampled cgroup memory.current maximum across arms: 1.239–1.260 GiB; sampled swap maximum: 0 bytes. OOM / OOM-kill event deltas: [(0, 0)]. Driver allocations and shared host page cache are not established by these cgroup readings.
Request contents and standalone SSE reproduction example
The small Python example below reconstructs the same request objects used by the retained campaign (21 objects checked against
the three seven-request sequences), and sends one block to the already-running server. Save it as
/task/reproduce_requests.py.It is a portable reproduction client, not the IPC/cgroup collection harness used to produce the table.
The synthetic module may end in a truncated function; that is part of the fixed prompt.
For each of
4096,8192,32768, restart the engine for upstream-before, candidate and upstream-after,and run this client once per arm with a distinct output filename, for example:
For the 4K default-path check, restart the candidate with all new controls unset and use another output filename; exclude it from timing comparisons.
Exclude the first four requests; compare the final three. For full-length requests, check usage input counts
4096/8192/32768, actual output counts128/256/256,zero reused prompt tokens and matching output text. The retained campaign additionally checks engine token IDs.
Greedy sampling, seed
42, thinking off, sampler defaults and runtime settings are explicit in the configuration above.Host page cache is not flushed; no disk-cold TTFT is claimed. Suffix drafting is time-adaptive, so actual work counts are retained below.
Individual measured samples, baseline variation and actual draft work
Every block is one fresh engine, one excluded short warmup plus three excluded full-length warmups, then three measured requests.
Order is upstream-before / enabled candidate / upstream-after. There are six upstream and three candidate samples per length.
Limits
Development comparison on this single B70/model/configuration. Performance is not established for other hardware, workloads or contexts.
Default behavior is preserved by opt-in dispatch; no default change or formal benchmark approval is claimed.
The older measurements below use different source/defaults and RAM limits and are not the current comparison.
Historical pre-beta description and measurements — superseded by the 2026-10-20 retest above
The following original text is retained as historical evidence. In particular its default-on control descriptions and old tables
do not describe the rebased opt-in source or current 32 GiB measurements.
Summary
Reduce IQ4_XS × Q8_1 decode work on Intel Battlemage by sharing loads across adjacent quantization groups and token columns, and replacing per-value codebook lookups with a bit-select tree.
What changed
sycl/src/kernels/cuda/native_mmvq.dp.cpp: add ESIMD INT8 XMX kernels that reuse IQ4 headers and packed weights across two Q8_1 blocks and up to four token columns. Selected shapes also load the adjacent Q8_1 blocks and their scales together.sycl/include/strata/kernels/iq4_lut.hpp: add an exact packed IQ4 bit-select lookup, used by the remaining eligible wide-kernel shapes.intel_gpu_gen/IntelGpuGen::Battlemage. The optimized defaults cover K=2560/6144 and T=1–6, subject to alignment, row-count and shape guards; pair reuse and Q8 splitting cover T≤4. Other devices and unsupported shapes retain the original dispatch. CUDA/HIP implementations and public documentation are unchanged.Dispatch controls
10STRATA_SYCL_IQ4_PAIR_REUSESTRATA_SYCL_IQ4_Q8_SPLITSTRATA_SYCL_IQ4_LOOKUPThere is no single master switch for this PR. To select the original dispatch, set both
STRATA_SYCL_IQ4_PAIR_REUSE=0andSTRATA_SYCL_IQ4_LOOKUP=0. The Q8-split control has no effect when pair reuse is disabled.All controls retain the device, alignment 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.
Validation
One Arc Pro B70 32 GB, Linux/xe, Xeon w5-3435X;
intel/omix:0.4.0-devel-ubuntu24.04, oneAPI DPC++ 2026.1.1, compute runtime 26.31.39395.13, Level Zero loader 1.32.0. Container limit: 96 GiB RAM / 16 CPU quota. Builds and GPU tests ran inside this container.Build:
At submitted revision
e5c0c9c69d38c9469c185ba67c0f7d61e0ecc564:Additional checks at measured revision
9683cda6c60139976058d0f2abe90c10c1aff426: ten locally defined requests produce identical upstream token IDs at each max-context setting, 32768 and 131072 (20/20). They cover arithmetic, Python, prose, Chinese, JSON, Unicode and 4096/8192-token synthetic code-review inputs. A frozen 4096-token CLI input with--pcie-frac 0also produces all 248320 first-token logits byte-identically to upstream, with all values finite.End-to-end performance
Timing comparison: candidate
9683cda6c601versus upstream296b59d2f73c, on the B70 environment described above. The current head (e5c0c9c69d38) has been checked for correctness but has not been remeasured for endpoint latency.TTFT is the time from the request to the first nonempty SSE token. TPOT is the time between the first and last nonempty SSE tokens divided by generated tokens minus one. Negative changes mean lower latency.
Test configuration and sampling
296b59d2f73c8f04a805df29c2fa97655adace789683cda6c60139976058d0f2abe90c10c1aff426; this PR onlyed59f92082b1e93c0e96d60a8b11aab089b52f09--expert-cache 17772experts; reserve 1536 MiB; mirror budget 16384 MiBObserved capacity in every arm: 18609 resident expert slots and 5967 mirrored experts (8.02 GiB). The 16384 MiB setting is a budget, not the actual mirror allocation.
Existing upstream settings held equal in both arms:
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.Each arm starts a fresh process. One short request and three full-input requests are excluded as warmups; three requests are then measured.
The 4K percentage averages the five pair-mean ratios. The 8K/32K percentage averages the three request-wise ratios against the matching before/after baseline means.
Baseline variability and actual speculative work
4K
Pair changes, TTFT: -0.075%, +0.000%, +0.054%, +0.042%, -0.009%; TPOT: -5.762%, -5.829%, -5.812%, -5.819%, -5.787%.
Baseline first-to-last change: TTFT -0.003%, TPOT +0.009%; block-mean spans 0.081% / 0.052%.
Output token IDs match across all arms, including warmups. Mean windows/offered/accepted per measured request: baseline 54.000/111.000/74.000 (15 requests); candidate 54.000/111.000/74.000 (15 requests).
8K
Baseline drift: TTFT -0.053%, TPOT -0.017%.
Output token IDs match across all arms, including warmups. Mean windows/offered/accepted per measured request: baseline 102.667/209.000/153.667 (6 requests); candidate 102.667/209.000/153.667 (3 requests).
32K
Baseline drift: TTFT +0.009%, TPOT -0.002%.
Output token IDs match across all arms, including warmups. Mean windows/offered/accepted per measured request: baseline 103.333/202.333/154.000 (6 requests); candidate 103.333/201.667/154.000 (3 requests).
Speculation settings are fixed; offered counts include suffix drafts and actual work may differ because suffix selection is time-adaptive. The measurements are warmed and post-readiness; the host page cache was not flushed, so no disk-cold TTFT result is claimed.
Kernel measurements
Independent microbenchmarks use synthetic weights and activations at matrix dimensions used by the model. K and N are the input and output dimensions; T is the tested number of token columns. Timings were collected at
9683cda6c60139976058d0f2abe90c10c1aff426.The baseline selects the original dispatch in the same binary with the IQ4 optimizations disabled; the candidate uses default dispatch. Each baseline/candidate/baseline arm has three measured samples after a ≥2-second/1000-call warmup; samples last ≥3 seconds/2000 calls. Times include host submission and the final queue wait. These are isolated kernel-call timings; model-level results are reported in the E2E table above.
Limitations
Runtime and performance validation is limited to B70. Other GPUs, Windows and multi-GPU operation were not runtime-tested. The patch changes only the two SYCL implementation files listed above; no test-source changes are included.