edge: measure cpu_gemm_wna16 instead of asserting it away (I2)
The review caught weight_path.py claiming tinygemm is "the only option" for an
x86 core without AMX. That was false -- vLLM 0.28 selects ops.cpu_gemm_wna16
whenever layer.use_w4a8 is off -- and the honest response was to measure the
kernel, not to reword the claim.
Same GPTQ checkpoint, only VLLM_CPU_INT4_W4A8 differing, isolated compile
caches, 3 interleaved passes on 24 pinned node-local cores:
int4_scaled_mm_cpu (W4A8, AMX) 74.4 tok/s spread 1.1%
tinygemm W4A16 (same cores) 71.6 tok/s
cpu_gemm_wna16 32.3 tok/s spread 1.5%
The fallback is real but 2.2x slower than tinygemm, so the selector's routing
was right for a reason nobody had checked. It stays as it is; what changes is
that the module now cites a measurement rather than an assumption.
Recorded with the caveat that matters for reading it off-x86: _get_isa_hint
returns "amx" whenever AMX is present and activations are bf16, regardless of
the W4A8 flag, so this measured cpu_gemm_wna16 on its AMX path -- its best case
on this host. The "vec" path a genuinely AMX-less machine takes is untested and
presumably no faster, which only strengthens the conclusion, but no number is
claimed for it.
Also adds VLLM_OMNI_CPU_INT4_REPACK_ROWS so the blocked repack can be A/B'd
against whole-matrix packing in identical code. Unlike the prefill-path switch
this is load-time only and yields identical tensors, so it does not perturb the
compiled graph or its cache key.
tests/edge: 8 passed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
6d7b2bfc1c
commit
bc865385a8
2 files changed
+33
-7
No files matched your search
@@ -168,13 +168,27 @@ one chunk at a time: verified byte-identical to packing the whole matrix at
|
||||
13312x2048, 2048x6656, 3072x2048 and 131072x2048.
|
||||
|
||||
A multiple of ``TINYGEMM_N_BLOCK``; the loop rounds down to one.
|
||||
``VLLM_OMNI_CPU_INT4_REPACK_ROWS`` overrides it, and 0 means "the whole matrix
|
||||
at once", which restores the old behaviour for an A/B. Unlike the prefill-path
|
||||
switch this only affects load time and produces identical tensors, so it does
|
||||
not perturb the compiled graph or its cache key.
|
||||
"""
|
||||
|
||||
|
||||
def _repack_rows() -> int:
|
||||
raw = os.environ.get("VLLM_OMNI_CPU_INT4_REPACK_ROWS")
|
||||
return REPACK_ROWS if raw is None else int(raw)
|
||||
|
||||
|
||||
def _pack_blocked(packed: torch.Tensor) -> torch.Tensor:
|
||||
"""Kernel layout, without ever expanding the whole matrix to int32."""
|
||||
n = packed.shape[0]
|
||||
step = max(REPACK_ROWS - REPACK_ROWS % TINYGEMM_N_BLOCK, TINYGEMM_N_BLOCK)
|
||||
rows = _repack_rows()
|
||||
if rows <= 0: # explicit opt-out: old behaviour
|
||||
return torch.ops.aten._convert_weight_to_int4pack_for_cpu(
|
||||
unpack_nibbles(packed), INNER_K_TILES
|
||||
)
|
||||
step = max(rows - rows % TINYGEMM_N_BLOCK, TINYGEMM_N_BLOCK)
|
||||
if n <= step:
|
||||
return torch.ops.aten._convert_weight_to_int4pack_for_cpu(
|
||||
unpack_nibbles(packed), INNER_K_TILES
|
||||
@@ -206,7 +220,8 @@ def to_split_halves(packed: torch.Tensor) -> torch.Tensor:
|
||||
lane shuffle: measured 3.1 ms per layer instead of 4.5.
|
||||
"""
|
||||
n = packed.shape[0]
|
||||
step = max(REPACK_ROWS - REPACK_ROWS % TINYGEMM_N_BLOCK, TINYGEMM_N_BLOCK)
|
||||
rows = _repack_rows()
|
||||
step = n if rows <= 0 else max(rows - rows % TINYGEMM_N_BLOCK, TINYGEMM_N_BLOCK)
|
||||
out = []
|
||||
for i in range(0, n, step): # bounded transient, as above
|
||||
codes = unpack_nibbles(packed[i : i + step].contiguous())
|
||||
|
||||
Reference in new issue
Block a user