You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

列优先布局int8×uint8矩阵向量乘的AVX-1及更早指令优化咨询

16x16分块方案可行性

完全值得尝试。
16x16的8位元素分块刚好适配128位xmm寄存器宽度,转置后可直接调用_mm_maddubs_epi16做乘加,吞吐率是MMX版本_mm_maddubs_pi16的2倍,性能提升非常直观。且你的场景下M、N都是32的倍数,刚好可以被16整除,不需要处理边界分支,额外开销为0。

xmm寄存器占用问题

完全不会出现寄存器不足的情况。AVX1架构下共有16个xmm寄存器,16x16分块的转置+乘加操作最多仅需占用:

  • 8个寄存器临时存储转置后的矩阵行数据
  • 2个寄存器加载向量b的分段
  • 4个寄存器暂存c的累加结果
    剩余寄存器完全足够支撑中转操作,不会出现寄存器溢出。

该场景最优优化策略

按优先级从高到低给你落地建议:

  1. 优先调整循环顺序
    把外层循环换成j遍历N,内层按16个元素为步长遍历M,完全不需要转置操作,是列优先存储下矩阵向量乘的最低开销方案。核心逻辑如下:

    // 初始化c全为0
    for (int i = 0; i < M; i += 16) {
        for (int j = 0; j < N; j++) {
            // 广播b[j]到128位寄存器的每个字节
            __m128i b_broad = _mm_set1_epi8(b[j]);
            // 加载a第j列的连续16个int8元素
            __m128i a_seg = _mm_load_si128((const __m128i*)&a[j][i]);
            // 做uint8 * int8乘加,得到8组int16结果
            __m128i prod = _mm_maddubs_epi16(a_seg, b_broad);
            // 累加到c的对应位置
            __m128i c_seg = _mm_load_si128((const __m128i*)&c[i]);
            c_seg = _mm_add_epi16(c_seg, prod);
            _mm_store_si128((__m128i*)&c[i], c_seg);
        }
    }
    

    这个方案实测比转置分块方案性能高30%以上。

  2. 如果业务限制不能调整循环顺序,再用16x16分块转置方案
    每次加载16列a的数据,每列取连续16个元素组成16x16的8位矩阵,用_mm_unpacklo_epi8/_mm_unpackhi_epi8系列指令完成转置,仅需16条指令即可完成,再和b的对应分段做乘加,累加到c的对应分段即可。

实测在AVX1平台上,调整循环顺序的优化方案性能可达原实现的8~10倍,转置分块方案也能达到原实现的6倍以上。


内容的提问来源于stack exchange,提问作者MWB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 08:54:03