Repository navigation
Conversation
Signed-off-by: Dong, Bo1 <bo1.dong@intel.com>
Signed-off-by: Dong, Bo1 <bo1.dong@intel.com>
Merge ec61621 accidentally widened the dpas_w8a16_policy_m_32 bucket in the fp8 per-tensor (per-expert) prefill dispatch from A_avg_M <= 32 to <= 512, routing large-M prefill through the small 32x64 tile instead of the large-M 128x128 default tile and regressing performance. Restore the <= 32 threshold.
Merge ec61621 also widened the dpas_w8a16_policy_m_32 bucket in the fp8 per-group prefill dispatch from A_avg_M <= 32 to <= 512, regressing large-M group-size prefill for the same reason as the per-tensor path. Restore the <= 32 threshold so large-M prefill uses the 128x128 default tile.
Migrate the auto-dispatch logic from branch copilot/update-phase-auto-dispatch-logic (commit 9605fe4): phase="auto" now dispatches to decode when activations.shape[0] <= threshold (total tokens) instead of inspecting num_tokens_per_expert.max(), avoiding a host-device sync. Adds ARK_MOE_AUTO_DECODE_MAX_TOKENS env override (default 256) and updates test_moe_unified.py accordingly.
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
The shared S4 DPAS grouped-GEMM (prefill path) already beats the scalar GEMV decode kernel by ~2x at 256 tokens (bs32) and only loses at the single-stream bs1 (8-token) extreme. Routing 256-token batches to decode was leaving ~2x on the table, so lower the auto-dispatch default and update coupled unified-dispatch tests and perf-test notes. Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
…reshold tuning Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
… GEMV Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
…mangled names Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
…atch regression Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
|
/azp run Unit-Test-CUDA-AutoRound |
|
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command. |
|
@copilot resolve the merge conflicts in this pull request |
…ze-int4-moe-performance # Conflicts: # auto_round_extension/ark/auto_round_kernel/wrapper/include/utils.hpp Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Merged in Only three files actually overlapped with The conflict: two kernels claimed the same scratch slot. Resolved by leaving The two auto-merges were verified, not assumed — CI on the merge commit is green so far — 18 checks passed (DCO, CodeQL, all 12 compatibility matrix jobs, both ark-change detectors), 0 failures. The ARK wheel build and the unit-test/XPU jobs are still running; the wheel build is the one that would catch a compile regression from this resolution, since there's no SYCL compiler in my environment. |
|
/azp run Unit-Test-CUDA-AutoRound |
|
Azure Pipelines could not run because the pipeline triggers exclude this branch/path. |
There was a problem hiding this comment.
🟡 Changes recommended
One or more issues must be addressed before approval.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds an XPU ARK W4A8 MoE path with int4→int8 prepacking, dynamic activation quantization, prefill DPAS GEMM, decode GEMV, caching, and fused reduction.
Changes:
- Added W4A8 kernels, scratch management, and generated translation units.
- Added C++/Python APIs and prepack caching.
- Added performance/accuracy tests and bilingual documentation.
File summaries
| File | Description |
|---|---|
| auto_round_extension/ark/auto_round_kernel/wrapper/include/utils.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/wrapper/include/sycl_tla_moe_w4a8.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/wrapper/include/sycl_tla_moe_w4a8_scratch.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/wrapper/include/sycl_tla_moe_w4a8_kernels.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/wrapper/include/sycl_tla_moe_w4a8_helpers.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/wrapper/include/sycl_tla_moe_prefill_fp8_dpas.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/wrapper/include/sycl_tla_common.hpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/sycl_tla_moe.cpp.in | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/sycl_tla_moe_w4a8_scratch.cpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/sycl_tla_generation.cmake | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/ark.cpp | Updated as part of this pull request. |
| auto_round_extension/ark/auto_round_kernel/init.py | Updated as part of this pull request. |
Review details
Suppressed comments (3)
auto_round_extension/ark/auto_round_kernel/init.py:3918
- This cache key uses the storage addresses and shape but not tensor versions or strides (and not the effective block after
ARK_MOE_W4A8_AUTO_S8is applied). If packed weights/scales are updated in place, or a different view reuses the same address/shape, the cache silently returns an old int8 prepack and produces results for stale weights. Track mutation/layout/effective-block identity or invalidate the entry when inputs change.
key = (
device.type,
device.index,
weights.data_ptr(),
scales.data_ptr(),
tuple(weights.shape),
int(group_size),
int(rescale_group_size),
str(scales.dtype),
)
auto_round_extension/ark/auto_round_kernel/init.py:3580
- The public API returns three values here—
weights_s8,wscales, and the resolved block size—but the PR's usage example unpacks only two (w_s8, w_scale = ...). That example will raiseValueError: too many values to unpack; update the example to includeblock(which is required bymoe_gemm_w4a8) or change the API consistently.
Returns:
``(weights_s8, wscales, rescale_block_size)`` where ``weights_s8`` is
``[E, N, K]`` ``torch.int8``, ``wscales`` is
``[E, N, K // rescale_block_size]`` ``torch.float32``, and
``rescale_block_size`` is the resolved block size (pass it to
:func:`moe_gemm_w4a8`).
auto_round_extension/ark/auto_round_kernel/sycl_tla_moe_w4a8_scratch.cpp:55
DeviceMemoryPool::get_scratch_ptrexplicitly avoidsq->wait()during XPU graph capture because that host wait is illegal (utils.hpp:186-200), but this new growth path performs the wait itself. A captured W4A8 call that grows the activation or expert-map slab will therefore fail; use the pool's nonblocking growth/lifetime mechanism or explicitly reject capture before reaching this path.
void* acquire_w4a8_slab(sycl::queue* q, size_t bytes, size_t buf_loc) {
auto* pool = DeviceMemoryPool::Instance();
const size_t held = pool->get_scratch_size(buf_loc, q);
if (held != 0 && held < bytes) {
q->wait();
}
void* ptr = pool->get_scratch_mem(bytes, buf_loc, q);
- Files reviewed: 12/15 changed files
- Comments generated: 5
- Review effort level: Lite
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
/azp run Unit-Test-CUDA-AutoRound |
|
Azure Pipelines could not run because the pipeline triggers exclude this branch/path. |
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
Co-authored-by: a32543254 <53296245+a32543254@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
|
/azp run Unit-Test-CUDA-AutoRound |
|
Azure Pipelines could not run because the pipeline triggers exclude this branch/path. |
|
@copilot resolve the merge conflicts in this pull request |
for more information, see https://pre-commit.ci
Signed-off-by: Dong, Bo1 <bo1.dong@intel.com>
|
/azp run Unit-Test-CUDA-AutoRound |
|
Azure Pipelines could not run because the pipeline triggers exclude this branch/path. |
|
/azp run Unit-Test-CUDA-AutoRound |
|
Azure Pipelines could not run because the pipeline triggers exclude this branch/path. |
Description
Adds a W4A8 MoE kernel to the ARK XPU backend covering both prefill and decode: int4 symmetric weights, int8 compute dtype, activations dynamically quantized per token to int8. Follows the W4A8 weight-only GEMM in
zhenzhong/woqgemm_s8_update, and uses ARK'sAUTO_S8trick — re-scaling int4 group=32 weights into int8 group=-1 so the K loop needs a single full-width int32 accumulation instead of per-group folding.Built on top of
copilot/optimize-int4-moe-performance.Numerics
AUTO_S8 re-scale, ported from
packscale/unpackqinxpu_wrapper.hpp:Default block = K (
group=-1) →blks == 1. Since_pack_int4_symdivides by 7.0,max|w8| = 7 * 127/8 ≈ 111 ≤ 127, so the conversion never clips. Epilogue isout = acc_s32 * scale_b[col] * scale_a[row].Kernel —
wrapper/include/sycl_tla_moe_w4a8.hpp(new)moe_w4a8_prepack:[E,N,K/2]int4 →[E,N,K]int8 +[E,N,blks]fp32 scales. CostsE*N*Kbytes (2× the packed int4).x_s8andscale_a.XE_DPAS_TT<8, int32_t, int8_t, int8_t>, tile ladder mirroring the reference (m<16 → 8x128,m<128 → 64x128,m<=1024 → 128x128, else256x128).num_tokens_per_expertis a device tensor, so it reuses the existing persistent work-stealing scheduler.SG_SIZE=16/N_TILE=16, one output column per lane.ARK_MOE_W4A8_AUTO_S8overrides the rescale block size; invalid values fall back to K. Shape gate:N % 16 == 0,K % 64 == 0,group_size % 8 == 0,K % group_size == 0.Plumbing
sycl_tla_common.hpp: 4 public declarations.ark.cpp: include, 2 wrappers, 4m.defregistrations.auto_round_kernel/__init__.py: Python API plus a prepack cache. The cache key includes device type/index and the entry pins the source tensors, so a freed-and-reallocated weight buffer can't alias another layer's int8 weights.Benchmark —
test/test_moe_w4a8_perf.py(new)Standalone perf + accuracy harness, runnable under pytest or directly. Qwen3-MoE shapes (
E=128, hidden=2048, inter=768, top_k=8, group_size=32). Reports SNR/cosine/max-rel-err against a torch bf16 baseline and latency/TFLOPS/speedup against the W4A16 kernel, for prefill across batch×seq and decode across batch.Type of Change
New feature (Performance)
Checklist Before Submitting
/azp run Unit-Test-CUDA-AutoRound.Docs:
test/README_MOE_W4A8.md+README_MOE_W4A8_CN.md.