mudler / mudler/vllm.cpp

The block-decoding gather arms for METAL, VULKAN, ROCM and TENSTORRENT

Open
#2,394 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
423
Forks
53
Avg merge
20h 26m
Merged PRs (30d)
310

Description

Row: MODEL-MM-QWEN4-EXP

KGATHER (.agents/specs/cuda-quant-gather.md) gave the CPU and CUDA backends a block-decoding gather and made the capability a registry fact: vt::Embedding routes a block-quantized table to OpId::kEmbeddingQuant, and the GGUF residency gate is OpRegistered(kEmbeddingQuant, dev).

Four backends do not register it, so they keep expand-bf16 residency for any gather table. Each refuses a block table by name in its own kEmbedding kernel today, for example src/vt/tenstorrent/tenstorrent_ops.cpp: "tenstorrent kEmbedding: float table, f32/bf16 out".

  • src/vt/metal/metal_ops.mm
  • src/vt/vulkan/vulkan_ops.cpp
  • src/vt/rocm/rocm_ops.hip
  • src/vt/tenstorrent/tenstorrent_ops.cpp

Why it matters. On a device that cannot gather quantized, a table expands. For the released unsloth/Qwen3.8-Flash-Next-GGUF UD-IQ1_S the n-gram table goes from 26.822 GiB of IQ4_NL to 95.368 GiB of bf16, which fits nothing in this fleet — so on those four devices qwen4_exp is refused by name at load, ahead of any tensor I/O.

What a port needs. src/vt/cuda/cuda_quant_dequant.cuh is the reference shape: one codec per block dtype transliterated from src/vt/cpu/cpu_quant_dequant.cpp (itself the byte-for-byte port of ggml-quants.c's dequantize_row_*), plus a gather kernel. Two things are not optional and are learned rather than obvious:

  1. Unaligned reads. A block base is not 4-byte aligned in general (66-byte IQ2_XXS, 110-byte Q3_K, 210-byte Q6_K), and a misaligned multi-byte device load faults rather than being slow.
  2. The gate must be an EXACT comparison against the CPU arm, not a tolerance. A tolerance hides a decode that produces plausible numbers and no crash. tests/vt/test_cuda_embedding_quant.cpp is the pattern, including a build guard that refuses to run a stale binary when a mutation fails to compile.

Registering kEmbeddingQuant without writing the decoder would convert a clean load-time refusal into a forward-time throw with the whole model resident — the #523 failure — so the registration and the kernel must land together, and only after the arm has executed on that device.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the four backend files named in the issue and compare their kEmbedding paths with src/vt/cuda/cuda_quant_dequant.cuh and src/vt/cpu/cpu_quant_dequant.cpp. Read tests/vt/test_cuda_embedding_quant.cpp for the exact CPU-arm comparison and stale-build guard. Done means each backend has a tested decoder and gather path, with kEmbeddingQuant registered only after that arm executes successfully on the device.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend, performance, testing-qa
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.