Skip to content

HIP decode: the 4-bit stream tile for MTP verify rows (scale/bias layout, lanes at K=640, row reuse) #1604

Closed

Description

@gilby

On AMD Ryzen AI MAX+ 395, Radeon 8060S gfx1151 (40 CUs, 128 GB unified memory, measured 225.6 GB/s read), Ubuntu 26.04, archive HIP 7.1 (clang 21), TensorFold 7c068895, TensorFold/Qwen3.8-Flash-Next-MLX-4bit-MTP.

The 4-bit affine_dot2_stream decode tiles carry 77% of an MTP verify round. Measured: double-buffering the multi-row loop is 9% slower (the existing choice to give registers to the rows' activations is right). Open candidates, each to be A/B'd on served decode: scale and bias read column-major (scale[col * groups + g]) as two separate arrays; lanes idle at K=640 (routed down) under the 32-lane rule; a 2-row x 8-column variant for 4 verify rows; rows of a routed item that hold one token computing all four.

Proposal

Land only the candidates that improve served decode with byte-identical tokens; report the rejected ones with numbers.

Activity

  1. gilby commented on Oct 29, 2026

    @gilby
    ContributorAuthor

    Measured on AMD Ryzen AI MAX+ 395 (Radeon 8060S gfx1151), TensorFold 7c068895, TensorFold/Qwen3.8-Flash-Next-MLX-4bit-MTP, MTP 3 drafts, --parallel 1 --context 131072, tools/bench_openai.py medians (code / chat tok/s). Stock: 49.98 / 43.95.

    candidate code / chat tokens vs stock verdict
    double-buffer the R>1 stream loop like R=1 46.7 / 38.9 equal rejected, -9% (the registers the comment gives to the rows' activations matter more)
    R=2 x CB=8 for 3-4 verify rows 49.23 / 43.27 equal rejected, about -1.5%
    16 lanes instead of 32 at K=640 (routed down) 50.85 / 43.51 2 of 3 differ rejected: the lane count sets the shuffle-sum order, and +1.7% code is inside run noise

    Not pursued, from reading the code: scale and bias are already read contiguously per column (sb[c] + (q >> gshift)), so an interleaved layout needs a load-time repack for little expected gain; take_item already sets a.m to an item's token count and the stream loop stops at it, so dead rows only remain inside one 4-row group (ALU on a memory-bound kernel). A trace of a 442-token reply puts all affine_dot2_stream variants at 47.2 ms of a 61.5 ms verify round, 170-182 GB/s against 225.6 GB/s measured, so these tiles are near the bandwidth limit; the rest of the round is about 850 small launches (#1603, router part in #1614). Nothing to land here for now.

  2. ashhart commented on Oct 30, 2026

    @ashhart
    Owner

    Thank you, @gilby, for measuring the three affine_dot2_stream candidates on gfx1151 and writing up why each was rejected. With the tiles near the bandwidth limit, we agree there is nothing to land here. The remaining cost is the roughly 850 small launches, which #1603 and the router work in #1614 pick up, so we're closing this one. Please reopen if a candidate turns up that beats the current tile.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions