mirror of
https://github.com/Comfy-Org/comfy-kitchen.git
synced 2026-11-04 23:37:42 +00:00
[PR #235] [CLOSED] Move int8 attention conversions off the XU pipe on Ampere #244
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-kitchen#244
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/comfy-kitchen/pull/235
Author: @Many0therFunctions
Created: 10/9/2026
Status: ❌ Closed
Base:
main← Head:int8-attention-xu-pipe📝 Commits (1)
4f6ed43Move int8 attention conversions off the XU pipe on Ampere📊 Changes
3 files changed (+68 additions, -8 deletions)
View changed files
📝
comfy_kitchen/backends/cuda/sage_attention/attn_utils.cuh(+15 -8)📝
comfy_kitchen/backends/cuda/sage_attention/math.cuh(+22 -0)📝
comfy_kitchen/backends/cuda/sage_attention/mma.cuh(+31 -0)📄 Description
What
In the fused softmax of
qk_int_sv_i8_attn_kernel, every score goes through anI2F(int32 score → fp32), anex2and a pairedF2I+cvt.pack.sat.u8(fp32 probability → u8), plus a__uint2float_rnon each row sum. On Ampere all of those issue on the XU pipe (16/clk/SM). Nsight Compute on an A6000 (GA102) at a MiniMax-H3 shape (B1 H56 S53730 D128) shows that pipe as the kernel's busiest, with the tensor pipe stalling behind it:This PR replaces the two conversions with FP32/integer arithmetic on the FMA/ALU pipes, which were nearly idle:
math::i32_to_f32_exact(x)=__int_as_float(x + 0x4B400000) - 1.5 * 2^23. Inside [2^23, 2^24) the FP32 ulp is exactly 1, so the integer add lands exactly on float(x) and the subtraction is exact (Sterbenz). Valid for |x| ≤ 2^22; the S8×S8 dot over ≤ 256 products is bounded by 2^22, and the dp4a row sum by 1020.mma::pack_u8x4_bounded(a, b, c, d)=__float_as_uint(p + 2^23)per value, then threePRMTs to gather the low mantissa bytes. The+2^23FADD rounds to nearest with ties to even, same ascvt.rni, and leaves the integer in the low byte. Valid for 0 ≤ p ≤ 255, which holds at both call sites because the tile max carriesS_U8_OFFSET = log2(255). Masked scores (−inf bias) giveexp2(−inf) = 0under both forms; a row masked across a whole tile has a NaN exponent thatcvtpacks as 0 and this form as 0xFF, butupdate_mdomultiplies that tile's contribution bytile_scale = 0either way, so the output is unchanged.After the change the XU pipe carries only the
ex2itself: static SASS of the D128 instantiation goes I2F 421 → 261, F2I 193 → 65, I2IP 96 → 32 (the rest is the once-per-CTA partial-tile tail), with +288 FADD, +160 IADD3, +96 PRMT.Architecture gate
Both helpers switch on
__CUDA_ARCH__ < 890. From sm_89 on, ptxas already emits the packedI2FP.F32/F2IP.U8.F32forms, which issue on the FMA pipe two values at a time, so the arithmetic form only adds instructions there: measured +4% slower on an RTX 5000 Ada (668 → 695 ms at the same shape) when ungated. With the gate, Ada compiles to the original code (bit-identical, 661 ms = before). Hopper/Blackwell are unmeasured and keep the original conversions as well.Results (A6000, sm_80 cubin from the default arch manifest)
tests/test_int8_attention.py: 419 passed; the twotest_int8_attention_long_sequence_and_partial_tile[0.0 / -0.088]failures are pre-existing (the torch 2.13 flash reference returns NaN forscale <= 0;ck.int8_attentionis finite there and within 0.017 nrmse of the MATH reference).Three files, no API or Python changes. Orthogonal to #234 (tile selection / launch bounds on Ampere): the two apply cleanly on top of each other since this only touches the per-score math inside the kernel.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.