Repository navigation
Conversation
…gs on pinned-host <-> pageable copies A queue memcpy/memset with neither end in device memory (USM host pinned <-> pageable host) runs on the Arc's copy engine, which hangs on it on a B70: dmesg "Engine reset: engine_class=bcs", and after repeated runs the device is declared wedged (needs a reboot). conversation_snapshot_test's fill() into its pinned KV pools hit it on every run (the urEventWait "hang" was the driver resetting the engine under the copy), and so would the engine's conversation_kv_save / restore of a --kv-resident session, whose pools are pinned host memory. transfer() and the test's fill / fill_after now memcpy / memset on the CPU when sycl::get_pointer_type says both ends are host or pageable; copies with a device end stay on the queue.
…nsposed grouped kernels The transposed grouped kernels (gu/down_grouped_t_kernel) write `acc += dw * dx * v` in one expression, which -fp-model=precise contracts to an FMA; the previous kernels compute the product in chunk_dot and add it in the caller, which it does not. nvcc contracts both, so they are bitwise equal on CUDA; on the B70 the last bit differed and s2_expert_grouped_parity reported 4 failures (moe_grouped_s2 / moe_group_resident, both within 1e-7 of the host reference). `#pragma clang fp contract(off)` in the two kernels, kept by fixups.py (9d) across re-migrations; 9c (the snapshot test's sycl::free) is back in fixups.py for the same reason.
…GR read does not write q8_1 fused_gr_read_multi on SYCL never writes the q8_1 image of `mixed` (fused_gr.dp.cpp returns false: the caller quantizes), so gr_parity's S26 check failed on every SYCL device with "QFUSE: T=1 rep 0: not written". The engine's path is fine (verify.cpp quantizes when the read returns false); the test now says "skipped" when the read writes nothing at T=1, and a read that writes different bytes still fails.
…distrobox (STRATA_SYCL_RUNNER) The serve wrapper hard-coded `docker`. Hosts that keep the toolchain in containers (Fedora Silverblue: rootless Podman, toolbox/distrobox with oneAPI) could not serve the SYCL engine without a Docker daemon. STRATA_SYCL_RUNNER=docker (default, unchanged) | podman (the same image and flags, plus label=disable for a data disk without SELinux labels) | native (already inside a toolbox with oneAPI, data root at /work) | distrobox:<name> (enters that distrobox from the host). The settings the wrapper forwards (STRATA_*, ONEAPI_*, ...) reach the engine the same way in every mode.
With two Intel cards every process that opens both lists both in its fdinfo, so the sampler added the other card's clients: busy read 163% of one card and vram_used_mb was both cards' sum (server_intel's VRAM pill and setup's free-memory reading use this file). Clients are filtered by drm-pdev to the sampled card and keyed by (card, client id), since client ids count per card. Also the Arc Pro B65 (e222) by name, and the lspci fallback reads `-vmm`'s Device line (`-mm`'s quoted fields do not split when an unquoted -p00 sits among them).
With several cards, --check judged each model by the first card only: on two 32 GB cards the IQ2_XS, IQ3_XXS and IQ3_S read "fits with part of its experts mirrored in RAM (slower)" although a --layer-split holds them in VRAM. A model that does not fit one card but fits the cards together (each less the same 1.5 GB of room) now reads "fits in VRAM across the N cards (--layer-split)"; one card and the A-series wording are unchanged.
…rp kernel, prompt +10% at 2K) On a B70 the QSA prompt attention is 15% of a 2K prompt and 28% of a 40K one (STRATA_PREFILL_TIMING). The warp kernel splits each cell's 256 dimensions over a sub-group and reduces them with a 5-step shuffle tree per query head, 60 shuffles a cell. qsa_prompt_attn_percell gives work-item c cell c's key row (16-byte loads) and all 12 heads' dot products, reading the query heads from local memory, in 128-cell chunks; the value pass and the merge are the warp kernel's. Each 16-dimension block is summed in four short chains before it joins the cell's sum, so its FP32 error stays near the warp kernel's. Prompt path only (prefill.cpp); decode and the draft layer keep qsa_decode_attn_batch. STRATA_ATTN_PERCELL=0 brings the warp kernel back. Not bitwise: FP32 in another summation order (as the XMX prompt kernel). qsa_prompt_attn_parity now checks it too (against FP64 and the warp kernel, int8 / FP16 / Q4_0 pools, 0 failures on a B70: error vs FP64 1.3-1.6x the warp kernel's, 1.2-2.2x faster) and is registered with ctest; the XMX kernel's refusal of Q4_0 pools no longer ends the test. Arc Pro B70, Coder IQ1_M, 256K config, `--pcie-frac 0 --adapt-every 0 STRATA_PREFILL_MMQ=1`, 256 greedy tokens: 2,185-token prompt 1,330 -> 1,481 tok/s (+11%, 2 rounds each). First-token logits against the warp kernel at 8K: KL 3.9e-10 nats, top-1 equal (upstream's int8 vs FP16 prompt experts on the same prompt: KL 8.4e-10).
…3x faster at 40K, prompt +21% at 40K, +35% at 128K) The prompt path scores every pooled key block against every query's indexer heads; on SYCL that is the warp kernel (the CUDA build's tensor-core path is not ported), 8% of a 40K prompt on a B70 and growing with the context. As a dense product it is one oneMKL FP32 GEMM per tile (pooled keys x the batch's 4 x 256 indexer queries) and a small kernel that applies the relu per head, sums in head order, and gives block n_bid the dead key and its +1e9 rule (qsa_block_scores_reduce, the warp kernel's semantics). The tile is carved from the attention scratch, free until that layer's attention on the same queue, so no VRAM is added. Below ~8K cells oneMKL's launch cost loses (-2% at 2K, even at 8K), so by default only a batch reaching 2,048 blocks takes it; STRATA_SELECT_GEMM=0 never, =1 always. FP32-level, not bitwise (as the CUDA 3xTF32 path). Arc Pro B70, `--pcie-frac 0 --adapt-every 0 STRATA_PREFILL_MMQ=1`, with the per-cell attention, old kernels -> new: Coder IQ1_M 40K 1,562 -> 1,885 tok/s, 128K 1,336 -> 1,798 (the 256 greedy tokens identical); IQ2_XS 40K 1,373 -> 1,613. First-token KL against the old kernels at 40K 1.3e-11 nats, top-1 equal. docs/INTEL.md has the table.
…he int8 crossover was re-measured at every start STRATA_PREFILL_MMQ=auto (the Battlemage default) times the int8 and FP16 expert chains at the first prompt of each expert format and caches the result in ~/.cache/strata/i8-crossover.txt. strata-sycl.sh runs the engine in a `--rm` container, so that home - and the cache - is gone after every run: each server start paid the measurement again inside its first prompt. Arc Pro B70, Coder IQ1_M (six format pairs), 2,185-token prompt: 761 tok/s on the first run without the cache against 1,450 once it is read back (int8 forced: 1,465-1,469); the same choice is made either way (500 of 500 groups int8). The wrapper now sets STRATA_CACHE_DIR=/work/.strata-cache (the mounted data root) unless the environment names another.
On a B70 + B65 host setup listed the second card as "Intel Intel GPU e222 (xe)": the id was missing from the name table (lspci knows it as Battlemage G31 [Arc Pro B65], 32 GB). setup --check now reads "GPU 1: Intel Arc Pro B65, 32 GB VRAM - can be used".
|
Tested on 2x Arc Pro B70 (CachyOS, kernel 7.2.11, xe) with Swift 1.5 Flash-Next IQ2_XS: layer split 26, every expert in VRAM, int8 KV, MTP spec 4, prefill 8192, 262144 context. The image is v0.2.0-beta (3d1fb48) plus our SYCL patches, including #2808 (
The ~148.8K read went from 66 s to 56 s. The needle was found in every read. Decode didn't change (123.1 against 123.0 tok/s mean over 5 greedy prompts), and the greedy text was identical on all 5 prompts in both rounds. Kernel suite: on the same image without this PR, Together with #2802 and #2810, the ~148.8K read stays at 2,724 tok/s. We carry this as a local patch until it merges. 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. |
|
This is impressive, great work! Eager to see this merged into the project! |
…gine hang fix, int8 crossover cache) — integ batch 19 [gpustat: integ's multi-card design + PR's B65 name; CMake registers PR's args-form parity test beside integ's union test]
|
Thanks @maxfridbe for this PR, and @hotschmoe and @Niko1221 for the work it builds on. I cherry-picked d95a9c4 and 8cc654f (authorship kept) onto hotschmoe’s 1c36052 and published the result, with our launch settings: https://github.com/Mouzon1775/Strata/tree/f3-4xb70 Hardware: 4× Intel Arc Pro B70 32 GB, Qwen3.8-Flash-Next UD-Q4_K_XL, layer split across all four cards. No GPU faults (xe fault/reset/wedge) in about 4.75 hours of testing. One request from the 4-card side: on SYCL, --pipeline-windows currently works only with a two-stage layer split. Multi-stage support, as the CUDA/HIP engine has, would help 4×B70 setups a lot, and I’m happy to test branches on this machine. |
): host-only copies on the CPU, s2 grouped kernels without FMA contraction, gr_parity QFUSE skip, crossover cache dir Ported from maxfridbe's pull request Niko1221#3248 (commits d95a9c4, 5fbef34, 344e43e, c44fb63 of that branch), cherry-picked without the prompt-kernel commits. - conversation_snapshot: a copy with neither end in device memory (pinned host <-> pageable host) is a memcpy on the CPU; through the queue it runs on the Arc's copy engine, which the PR reports hanging (Engine reset: engine_class=bcs). - s2_expert_grouped: #pragma clang fp contract(off) in the two transposed grouped kernels (fixups.py 9d keeps it across re-migrations; 9c the snapshot test's sycl::free). - gr_parity: the STRATA_QFUSE read check is skipped when the SYCL fused GR read writes no q8_1. - strata-sycl.sh: STRATA_CACHE_DIR defaults to the mounted data root so the int8 crossover cache survives the --rm container.
…: per-cell prompt attention fallback, QSA block scores as oneMKL GEMM tiles Ported from maxfridbe's pull request Niko1221#3248 (commits e55a11c and 8cc654f of that branch). - STRATA_ATTN_PERCELL (default on): qsa_prompt_attn_percell scores one work-item per cell in the prompt path's fallback attention (reached when the Battlemage ESIMD kernel refuses the pools, e.g. FP16 or Q4_0 KV, or STRATA_PROMPT_ATTN_ESIMD=0). =0 keeps the warp kernel. Not bitwise: FP32 in another summation order. - STRATA_SELECT_GEMM (default: from 2048 blocks): QSA block scores as oneMKL FP32 GEMM tiles plus qsa_block_scores_reduce; =0 the warp kernel, =1 always. Not bitwise. - qsa_prompt_attn_parity also checks the per-cell kernel and is registered with ctest. Conflict resolution against the tree: qsa_select.dp.cpp keeps qsa_block_scores_rows beside the new reduce kernel; docs/INTEL.md keeps this tree's text (the PR's table is not copied; measurements are in the Intel notes).
…RATA_<name>=0 turns each off), STRATA_SYCL_IQ_DECODE_FAST default ON in CMake and passed by the SYCL build scripts; STRATA_SELECT_GEMM_MIN sets the block threshold of the Niko1221#3248 GEMM block scores Controls of glorysdj's pull request Niko1221#4185: unset means on for a Battlemage device and off for every other device (strata::bm_default_on); a set value still decides. Measured results are in phaseA-tests/pr-priorities/RESULTS-INTEL.md.
…RATA_<name>=0 turns each off), STRATA_SYCL_IQ_DECODE_FAST default ON in CMake and passed by the SYCL build scripts; STRATA_SELECT_GEMM_MIN sets the block threshold of the Niko1221#3248 GEMM block scores Controls of glorysdj's pull request Niko1221#4185: unset means on for a Battlemage device and off for every other device (strata::bm_default_on); a set value still decides. Measured results are in phaseA-tests/pr-priorities/RESULTS-INTEL.md. (cherry picked from commit 8fffe81) b70 port: the controls read through strata::bm_default_on next to apply_b70_defaults in sycl_queue.hpp. Where this tree has its own kernel for the same call, its order from the Niko1221#4185 port stays: STRATA_IQ_DECODE_FAST before the row-reuse / SLM expert kernels, attn_merge_v2 before the active merge (attn_merge_mode now takes the queue), KREG before the Q6_K shape GRF. STRATA_GR_REDUCE_ILP keeps this tree's 8-loads-in-flight default (=0 off), as the plain reduce has it. STRATA_RESIDENT_PLAN_COMPACT stays unwired (see the Niko1221#4185 port).
Sorry it took so long i have been working on nextsycl i had forgotten to bring in the enhancements here, hopefully this will get approved, Improvements all around!
Branch: maxfridbe/Strata_B70 intel-arc-0.2.0 (head d119210), based on main f57c0ad; merges cleanly into main e88ee39. Replaces #1111 (closed in the 0.2.0 tracker reset), cut down to what main does not have yet. Only sycl/ and docs/INTEL*.md change.
Problem and result
On Arc Pro B70 and B65 (Battlemage, 32 GB), main’s SYCL engine has one hang, two failing tests and a slow first prompt, and its long prompts are slower than they need to be:
Also included, as small tooling fixes for multi-card and Podman hosts:
Related discussion
#1111 (closed by the 0.2.0 reset; this is its rebase), #423, #809. The hang fix, the cache and the test fixes need no scope agreement. The two prompt kernels change a SYCL-only prompt-path default; both have off switches. Happy to split this into three PRs (hang and test fixes / prompt kernels / tooling) if you prefer.
Approach
Validation
Environment: Arc Pro B70 (bmg-g31) + Arc Pro B65, 32 GB each, xe driver, PCIe Gen5 x8, Ryzen 9 9950X, 61 GiB RAM, Fedora Silverblue 44 (kernel 7.1.5), strata-sycl-dev image under rootless Podman (oneAPI 2026.1), AOT=bmg-g31. Revision: intel-arc-0.2.0 c44fb63 (d119210 only adds the B65 name), against main f57c0ad built the same way.
Passed:
card model prompt main f57c0ad intel-arc-0.2.0
B70 Coder IQ1_M 2,185 1,312 / 87.6 1,449 / 88.1
B70 Coder IQ1_M 8,000 1,620 / 84.9 1,826 / 88.5
B70 Coder IQ1_M 40,000 1,580 / 77.6 1,909 / 78.7
B70 Coder IQ1_M 128,000 1,351 / 78.5 1,821 / 76.4
B70 IQ2_XS 2,185 1,053 / 80.1 1,355 / 77.4
B70 IQ2_XS 40,000 1,376 / 74.1 1,603 / 77.3
B65 Coder IQ1_M 2,185 948 / 60.1 1,018 / 62.0
B65 Coder IQ1_M 40,000 1,039 / 54.7 1,315 / 54.8
B65 Coder IQ1_M 128,000 861 / 53.6 1,246 / 54.4
B65 IQ2_XS 40,000 942 / 53.2 1,162 / 50.1
Decode moves with the text: the prompt kernels change the greedy output after a few dozen tokens, and MTP acceptance changes with it. With identical tokens, decode is unchanged.
Interleaved A/B on the B70 (same binary, --pcie-frac 0 --adapt-every 0 STRATA_PREFILL_MMQ=1, 2 rounds, prefill tok/s, old kernels → new):
Failed:
Not run:
Limits