MX量化矩阵乘算子性能优化指南
概述
本文档系统阐述MX量化矩阵乘算子的实现原理、性能建模方法及优化实践,覆盖MXFP4与MXFP8场景。通过系统性的优化策略,帮助开发者快速掌握算子性能调优的核心技术,提升算子在昇腾平台上的执行效率。
算子实现原理
算子功能说明
-
算子功能:
对比项 MXFP8 MXFP4 a/b数据类型 float8_e4m3fnfloat4_e2m1量化方式 GroupSize=32的pergroup量化 GroupSize=32的pergroup量化 scaleA/B数据类型 float8_e8m0float8_e8m0显存压缩比 相比 FP16/BF16 内存占用减少约 50% 相比 FP16/BF16 内存占用减少约 75% 典型应用场景 模型训推,兼顾速度与精度的平衡 模型推理,侧重极致显存效率与推理速度 -
计算公式:
ci,j=∑g=0ceil(K/G)−1(scaleAi,g⋅scaleBg,j⋅∑k′=0G−1(ai,gG+k′⋅bgG+k′,j))c_{i, j} = \sum^{ceil(K/G)-1}_{g=0}\left(scaleA_{i, g} \cdot scaleB_{g, j} \cdot \sum^{G-1}_{k'=0} (a_{i, gG+k'} \cdot b_{gG + k', j}) \right)
MXFP4参数说明
| 变量名 | 描述 | Dtype | Layout | Shape |
|---|---|---|---|---|
| a | 输入左矩阵 | float4_e2m1 |
ND | (m, k) |
| b | 输入右矩阵 | float4_e2m1 |
ND | (n, k) |
| scaleA | 左矩阵量化参数 | float8_e8m0 |
ND | (m, ceil(k/64), 2) |
| scaleB | 右矩阵量化参数 | float8_e8m0 |
ND | (n, ceil(k/64), 2) |
| c | 输出矩阵 | bfloat16 |
ND | (m, n) |
MXFP8参数说明
| 变量名 | 描述 | Dtype | Layout | Shape |
|---|---|---|---|---|
| a | 输入左矩阵 | float8_e4m3fn |
ND | (m, k) |
| b | 输入右矩阵 | float8_e4m3fn |
ND | (n, k) |
| scaleA | 左矩阵量化参数 | float8_e8m0 |
ND | (m, ceil(k/64), 2) |
| scaleB | 右矩阵量化参数 | float8_e8m0 |
ND | (n, ceil(k/64), 2) |
| c | 输出矩阵 | bfloat16 |
ND | (m, n) |
算子实现说明
与传统非量化Matmul算子相比,MX量化场景新增了输入变量scaleA和scaleB,需要将其搬运至L1缓冲区,再搬运至L0A_MX和L0B_MX独立缓冲区。
通过约束L0A、L0B、L0A_MX、L0B_MX中Tensor的地址映射关系,芯片的MMAD指令支持自动计算MXFP4/MXFP8矩阵乘,并将Float32结果写入L0C缓冲区。通过设置Fixpipe指令的量化模式,输出预期的数据类型结果。因此算子实现仅依赖CUBE核,不涉及MIX场景。
MX量化场景矩阵乘执行时的完整数据搬运流程如下图所示:
关于每个输入在各个缓冲区上的Shape关系和排布要求,可以参考下面的详细介绍。
关键参数说明:
m, k, n:矩阵输入大小mL1, kL1, nL1:L1缓冲区的切分大小baseM, baseK, baseN:L0缓冲区的切分大小m0, k0, n0:当前缓冲区最小分型大小
Tensor a 的搬运说明
输入Layout说明:标准输入(m, k)、(k, n)对应ND排布。转置输入(k, m)、(n, k)对应DN排布
| 缓冲区变化 | Shape排布变化 | Layout变化 | 所属流水 | 所用指令 |
|---|---|---|---|---|
| GM -> L1 | (m, k) -> (ceil(kL1/k0), ceil(mL1/m0), m0, k0) | ND -> Nz | MTE2 | DataCopy with ND2NZ |
| L1 -> L0A | (ceil(kL1/k0), ceil(mL1/m0), m0, k0) -> (ceil(baseK/k0), ceil(baseM/m0), m0, k0) | Nz -> Nz | MTE1 | LoadData with Load2D |
图示以MXFP4为例,图片中标注的
K0 = 64表示在该示例中沿K轴按64对齐后的最小分块进行组织,对于MXFP8场景K0 = 32。
Tensor b 的搬运说明
| 缓冲区变化 | Shape排布变化 | Layout变化 | 所属流水 | 所用指令 |
|---|---|---|---|---|
| GM -> L1 | (n, k) -> (ceil(kL1/k0), ceil(nL1/n0), n0, k0) | DN -> Zn | MTE2 | DataCopy with ND2NZ |
| L1 -> L0B | (ceil(kL1/k0), ceil(nL1/n0), n0, k0) -> (ceil(baseK/k0), ceil(baseN/n0), n0, k0) | Zn -> Zn | MTE1 | LoadData with Load2D |
图示同样以MXFP4为例,
K0 = 64仅用于说明分形排布与指令搬运的最小K轴粒度,对于MXFP8场景K0 = 32。
Tensor scaleA 的搬运说明
因为MX量化GroupSize=32的pergroup量化,因此K方向的大小是输入矩阵的1/32。这里描述的是Scale张量的分组与存储布局,输入侧仅要求MXFP4场景下
k为偶数。
| 缓冲区变化 | Shape排布变化 | Layout变化 | 所属流水 | 所用指令 |
|---|---|---|---|---|
| GM -> L1 | (m, ceil(k/64), 2) -> (ceil(mL1/m0), ceil(ceil(kL1/32)/k0), m0, k0) | ND -> Zz | MTE2 | DataCopy with DN2NZ |
| L1 -> L0A_MX | (ceil(mL1/m0), ceil(ceil(kL1/32)/k0), m0, k0) -> (ceil(baseM/m0), ceil(ceil(baseK/32)/k0), m0, k0) | Zz -> Zz | MTE1 | LoadData with Load2D_MX |
Tensor scaleB 的搬运说明
因为MX量化GroupSize=32的pergroup量化,因此K方向的大小是输入矩阵的1/32。这里描述的是Scale张量的分组与存储布局,输入侧仅要求MXFP4场景下
k为偶数。
| 缓冲区变化 | Shape排布变化 | Layout变化 | 所属流水 | 所用指令 |
|---|---|---|---|---|
| GM -> L1 | (n, ceil(k/64), 2) -> (ceil(nL1/n0), ceil(ceil(kL1/32)/k0), n0, k0) | DN -> Nn | MTE2 | DataCopy with DN2NZ |
| L1 -> L0B_MX | (ceil(nL1/n0), ceil(ceil(kL1/32)/k0), n0, k0) -> (ceil(baseN/n0), ceil(ceil(baseK/32)/k0), n0, k0) | Nn -> Nn | MTE1 | LoadData with Load2D_MX |
算子实现约束
MX量化场景共性约束
-
K维度对齐约束:由于MX量化场景下MMAD指令限制输入矩阵在K方向长度为64的倍数,要求baseK是64的整数倍。
-
指令约束:
MMAD指令需关闭gemv功能。 -
K维度补零处理:基于共性约束1,当K轴非64对齐时,存在两类场景:
-
当输入矩阵的K维度在内轴,即输入排布为
(m, k)或(n, k)时,ND2NZ指令可自动完成K方向补零;仅在MXFP8且Ceil(k/32)是奇数时,需手动处理K方向补零。 -
当输入矩阵的K维度在外轴,即输入排布为
(k, m)或(k, n)时,ND2NZ指令无法完成K方向补零,需在k对齐16后依然非64对齐时手动处理K方向补零。推荐补零方法:使用
SET2D对L1缓冲区目标地址清零 +ND2NZ跳写目标地址。
MXFP4场景特性约束
-
数据类型处理:对于MXFP4量化场景,由于
ND2NZ指令不支持B4数据类型,需将输入按B8数据类型进行搬运,相应指令的stride和shape配置均需除以2。 -
内轴对齐约束:对于MXFP4量化场景,基于约束3,要求输入矩阵内轴为偶数,否则无法用2个
B4拼成一个B8类型。
算子性能建模
性能瓶颈分析
MX量化矩阵乘算子的性能瓶颈主要分为以下两类:
-
Cube Bound:算子性能受限于硬件的算力规格,本身已经实现连续的MMAD计算。这种场景通常意味着算子性能已经最优,但需要重点关注多核计算负载是否均衡,避免出现单核Cube Bound,但整体Cube利用率偏低的情况。
-
Memory Bound:算子性能受限于数据搬运能力,主要的性能优化手段是减少搬运量、提高带宽利用率或者将低带宽的搬运转换成高带宽的搬运,进而发挥算子极致性能。因Bound在不同的流水上而区分出MTE2 Bound、MTE1 Bound以及FIXPIPE Bound。
性能建模公式
基本原理
理论计算时间 = max(MMAD时间, MTE2搬运时间, MTE1搬运时间, FIXPIPE搬出时间)
通过评估不同流水的理论耗时并加以对比,可以得到影响耗时的决定性因素,从而选择对应的优化策略。
流水理论耗时评估
说明:以下公式统一采用
16 × C0 × 16表示Cube核每拍计算量。其中,MXFP8场景下C0 = 32,MXFP4场景下C0 = 64。
1. MMAD计算时间
Tcube=M×K×N16×C0×16×核数×频率T_{cube} = \frac{M \times K \times N}{16 \times C0 \times 16 \times 核数 \times 频率}
其中16 × C0 × 16表示MX量化在Cube核上每拍的计算量。
2. MTE2搬运时间
MTE2的搬运量包含了因切分带来的重复搬运,以及对应Scale的重复搬运:
Tmte2=(M×NbaseN+N×MbaseM)×K×(1×sizeof(dtype)+132)BandWidthmte2T_{mte2} = \frac{(M \times \frac{N}{baseN} + N \times \frac{M}{baseM}) \times K \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{mte2}}
MTE2的综合带宽包含DDR带宽和L2带宽的共同作用,可简化为:
Tmte2≈SizeDDRBandWidthDDR+SizeL2BandWidthL2T_{mte2} \approx \frac{Size_{DDR}}{BandWidth_{DDR}} + \frac{Size_{L2}}{BandWidth_{L2}}
其中:
- SizeDDR=(M+N)×K×(1×sizeof(dtype)+132)Size_{DDR} = (M + N) \times K \times (1 \times sizeof(dtype) + \frac{1}{32}) (首次搬运量)
- SizeL2=(M×NbaseN+N×MbaseM)×K×(1×sizeof(dtype)+132)−SizeDDRSize_{L2} = (M \times \frac{N}{baseN} + N \times \frac{M}{baseM}) \times K \times (1 \times sizeof(dtype) + \frac{1}{32}) - Size_{DDR} (重复搬运量)
3. MTE1搬运时间
MTE1作为Cube核内的流水,以单核内的计算和搬运量进行评估:
Tmte1=baseM×baseK×(1×sizeof(dtype)+132)BandWidthL0A+baseN×baseK×(1×sizeof(dtype)+132)BandWidthL0BT_{mte1} = \frac{baseM \times baseK \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{L{0}A}} + \frac{baseN \times baseK \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{L{0}B}}
4. FIXPIPE搬出时间
Tfixp=M×N×sizeof(dtype)BandWidthfixpT_{fixp} = \frac{M \times N \times sizeof(dtype)}{BandWidth_{fixp}}
流水理论耗时对比
算子期望最终变成CubeBound,因此可以将不同的搬运流水和计算流水展开对比,分析影响CubeBound的决定性因素。在理论无法达成CubeBound的背景下,选择优化策略优化各条搬运流水。
1. MTE2 VS MMAD
M×K×N16×C0×16×核数×频率≥(M×NbaseN+N×MbaseM)×K×(1×sizeof(dtype)+132)BandWidthmte2\frac{M \times K \times N}{16 \times C0 \times 16 \times 核数 \times 频率} \geq \frac{(M \times \frac{N}{baseN} + N \times \frac{M}{baseM}) \times K \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{mte2}}
化简后得到MTE2 Bound条件:
BandWidthmte2≥(1baseN+1baseM)×(1×sizeof(dtype)+132)×16×C0×16×核数×频率BandWidth_{mte2} \geq (\frac{1}{baseN} + \frac{1}{baseM}) \times (1 \times sizeof(dtype) + \frac{1}{32}) \times 16 \times C0 \times 16 \times 核数 \times 频率
特征分析:
- 当MTE2带宽满足上述条件时,算子性能受限于计算单元(Cube Bound)
- 不满足条件时,算子性能受限于MTE2数据搬运(MTE2 Bound)
- 右侧表达式主要受tiling参数(baseM, baseN)和硬件配置(核数、频率)影响
- 增大baseM和baseN可以降低右侧数值,更容易满足Cube Bound条件(主要受限于L0C缓冲区大小)
2. MTE1 VS MMAD
由于MTE1和MMAD均为Cube核内部流水,因此可以将公式化简到单核内对比:
baseM×baseK×baseN16×C0×16×频率≥baseM×baseK×(1×sizeof(dtype)+132)BandWidthL0A+baseN×baseK×(1×sizeof(dtype)+132)BandWidthL0B\frac{baseM \times baseK \times baseN}{16 \times C0 \times 16 \times 频率} \geq \frac{baseM \times baseK \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{L{0}A}} + \frac{baseN \times baseK \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{L{0}B}}
化简后得到MTE1 Bound条件:
baseM×baseN16×C0×16×频率≥baseM×(1×sizeof(dtype)+132)BandWidthL0A+baseN×(1×sizeof(dtype)+132)BandWidthL0B\frac{baseM \times baseN}{16 \times C0 \times 16 \times 频率} \geq \frac{baseM \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{L{0}A}} + \frac{baseN \times (1 \times sizeof(dtype) + \frac{1}{32})}{BandWidth_{L{0}B}}
当L0A和L0B的带宽一致时,可进一步化简:
BandWidthmte1≥(1baseN+1baseM)×(1×sizeof(dtype)+132)×16×C0×16×频率BandWidth_{mte1} \geq (\frac{1}{baseN} + \frac{1}{baseM}) \times (1 \times sizeof(dtype) + \frac{1}{32}) \times 16 \times C0 \times 16 \times 频率
特征分析:
- 当满足上述条件时,L1到L0的数据搬运不成为性能瓶颈
- 不满足条件时,算子性能受限于MTE1数据搬运(MTE1 Bound)
- 右侧表达式主要受tiling参数(baseM, baseN)和L0缓冲区带宽影响
- 增大baseM和baseN可以降低右侧数值,更容易满足Cube Bound条件
3. FIXPIPE VS MMAD
M×K×N16×C0×16×核数×频率≥M×N×sizeof(dtype)BandWidthfixp\frac{M \times K \times N}{16 \times C0 \times 16 \times 核数 \times 频率} \geq \frac{M \times N \times sizeof(dtype)}{BandWidth_{fixp}}
化简后得到FIXPIPE Bound条件:
BandWidthfixp≥16×C0×16×核数×频率×sizeof(dtype)KBandWidth_{fixp} \geq \frac{16 \times C0 \times 16 \times 核数 \times 频率 \times sizeof(dtype)}{K}
特征分析:
- 当满足上述条件时,L0C到GM的数据搬出不成为性能瓶颈
- 不满足条件时,算子性能受限于FIXPIPE数据搬出(FIXPIPE Bound)
- 右侧表达式与K维度成反比;对于大K场景,通常不会出现FIXPIPE Bound;对于小K场景,FIXPIPE Bound更容易成为瓶颈
建模说明:
- 该模型基于流水线理论,整体性能受限于最慢的流水阶段
- 通过分析比较各阶段的时间,从而准确识别性能瓶颈类型
- 优化目标是令算子在预期的流水上进行Bound,并将对应流水优化到极致
- 实际应用中还需考虑指令发射延迟、流水线并行度等额外开销
优化目标
基于理论公式对比,识别当前的Bound类型,应用相应的优化策略,使各流水阶段的时间尽可能接近,从而最大化整体算子性能。
算子优化实践
本章介绍MXFP4中应用的优化措施,针对不同的Bound类型场景分别提供搬运效率优化、计算效率优化方法,以及针对因流水阻塞导致Bound类型不明确的场景提供指令并行度优化实践。
指令并行度优化
Double Buffer(双缓冲)
-
原理介绍
Double Buffer使用两个缓冲区交替工作:一个缓冲区用于当前计算,另一个并行准备下一轮数据。通过计算与数据加载/准备的重叠,隐藏内存访问延迟,减少流水线停顿,提高算子吞吐量。
在本算子实践中,Double Buffer通常首先用于L1侧(配合后文的Bank冲突规避),在缓冲区资源允许时也可扩展为
4-Buffer以进一步提升并行度。 -
Double Buffer(2-Buffer) vs 4-Buffer
- 2-Buffer:两份buffer交替,覆盖“当前计算/下一轮准备”的基本重叠关系,资源开销更小,适用于多数场景。
- 4-Buffer:在buffer空间足够时,将准备阶段进一步细分(例如同时覆盖更多轮次或更多输入/scale的准备),以减少因搬运抖动、带宽瞬时不足造成的断流风险。
- 使能4-Buffer条件:当Profiling显示存在明显的流水停顿(计算等待搬运),且L1/L0空间评估后仍能保持目标
base块大小、不引入新的MTE1/FIXPIPE瓶颈时,可考虑使能4-Buffer。
-
效果对比
下图展示了使能Double Buffer后流水图的预期变化,从而有效提升不同流水间的并行度。
-
适用场景
- 存在流水停顿的场景
- 内存访问延迟成为瓶颈的场景
- L1或L0缓冲区空间充足的场景
UnitFlag(单元标志)
-
原理介绍
UnitFlag为
MMAD计算指令和FIXPIPE数据搬运指令提供基于内存访问的细粒度同步(512B粒度)。未开启时,FIXPIPE需等MMAD指令完全执行完才开始搬出;开启后,MMAD每计算完512B数据,FIXPIPE立即搬出该数据块,提高计算与搬出流水的并行度。 -
效果对比
-
适用场景
- MMAD和FIXPIPE流水部分或全部串行执行的场景
- 需要提高计算与搬出并行度的场景
K-Tail Stepwise Copyout(K尾轮分步搬出)
-
原理介绍
UnitFlag可以让FIXPIPE在当前Tile最终累加期间提前搬出已完成的部分结果,但当FIXPIPE的搬出尾部延续到下一Tile时,下一Tile立即复用相同L0C地址仍可能产生读写冲突,造成MMAD流水空洞。
K-Tail Stepwise Copyout在完整输出基本块无法放入半个L0C时保持M不变,并沿N方向将MMAD近似对半拆成两个子块。首个KL1轮次采用相同的N切分,分别初始化两个子块对应的累加区域;中间KL1轮次按完整N累加;最后一个KL1轮次再次按N切分,形成K尾轮的分步搬出。
K尾轮采用
KL1 -> N Split -> KL0循环顺序。每个N子块先连续完成全部KL0累加,在最终累加完成后立即通过FIXPIPE搬出到GM,再切换到下一个N子块。无需拆分的输出Tile仍按完整N执行。 -
效果对比
原
KL1 -> KL0 -> N Split顺序会在每个KL0轮次中切换N子块。第一个N子块触发FIXPIPE后,只间隔第二个N子块的一轮MMAD就可能进入下一Tile,较短的间隔无法稳定覆盖搬出尾部。K-Tail Stepwise Copyout采用
KL1 -> N Split -> KL0顺序,使第一个N子块完成全部K尾轮计算并触发搬出后,再执行第二个N子块的整段KL0计算。同一L0C子区域被下一Tile复用前获得更长的计算间隔,从而减少FIXPIPE读取与MMAD写入冲突,并提高K尾轮计算与结果搬出的并行度。 -
适用场景
- Cube-bound,且MMAD连续性对Kernel总耗时有明显影响的场景
- 完整输出基本块无法放入半个L0C,需要在K尾轮沿N方向分步搬出的场景
- K较大或单核计算轮数较多,FIXPIPE引入的流水空洞会在连续Tile之间累积的场景
- A/B为MXFP4,或二者均为支持的MXFP8类型,Scale为FP8 E8M0,输出为FP16/BF16的场景
- 输入内轴满足硬件对齐要求的场景,其中MXFP4对齐256 B,MXFP8对齐128 B
搬运效率优化
SWAT(自适应滑动窗口模板)
-
原理介绍
SWAT(Slide Window Adaptive Template)通过提升多核单次访问的L2命中率来提高
MTE2搬运效率,从而实现首轮搬运即可做到MMAD指令不断流,使算子在Cube Bound场景下计算单元利用率达到95%+。核心逻辑是使每一轮多核计算的输出排布尽量方正,具体方法是在M轴上设定固定窗口,根据M轴方向尾块大小灵活调整,再沿N方向进行"Z"型滑动,从而最大程度提高L2命中率。
-
效果对比
下图对比了传统的列优先分配和SWAT的理论效果。
-
适用场景
- 大规模矩阵乘法场景
- 多核并行计算场景
- Cube Bound为主要瓶颈的场景
L1 Bank冲突优化
-
原理介绍
L1缓冲区以256KB粒度分为两个Bank,当同时对同一Bank进行读写操作时,会触发Bank冲突,导致
MTE1带宽效率降低,进而打断MMAD指令连续性。因此在开启L1 Double Buffer时,需将两份缓存的数据放置于不同Bank中,从而避免读写冲突导致的Bank冲突。
-
效果对比
-
适用场景
- 开启了L1 Double Buffer的场景
- MTE1带宽利用率不足的场景
- 存在Bank冲突导致
MMAD断流的场景
Scale缓存优化
-
原理介绍
Scale部分的数据量仅为输入矩阵的1/32,当输入矩阵较小时,所需Scale数据量急剧减小,无法充分发挥带宽性能,导致Scale搬运带宽利用率显著降低。
可利用L1剩余空间,提前载入后续所需Scale并在L1上缓存,从而减少Scale搬运次数,缓解因单次所需Scale数据量过小导致的带宽速率降低问题。
-
效果对比
-
适用场景
- 输入矩阵较小,Scale数据量不足的场景
- MTE2带宽利用率受Scale搬运限制的场景
- L1缓冲区有充足剩余空间的场景
全载优化
-
原理介绍
在MTE2 Bound场景中,可通过减少
MTE2部分的整体搬运量来提高算子性能。对于输入可完整缓存在L1中的场景,可使用全载模板,在不同轮询中使输入始终驻留在L1中,从而减少整体搬运耗时。当前样例实现仅支持A全载(左矩阵a及其scaleA常驻L1),暂不支持B全载(右矩阵b及其scaleB常驻L1)。
-
效果对比
-
适用场景
- MTE2 Bound为主要瓶颈的场景
- 输入矩阵较小,可以完全载入L1的场景
- Decode等小批量计算场景
计算效率优化
尾轮负载均衡
-
原理介绍
当前Matmul算子普遍使用基本块策略进行多核分配。但在处理不同规格输入时,划分的基本块无法均匀分配到所有核上,导致分核不均,尤其是最后一轮计算存在算力浪费,使整体算力利用率无法达到最优。
为兼顾双边负载均衡与尾块浪费问题,会在分核阶段综合考虑M/N两个方向的分配结果:不仅对最后一轮未完全分配的基本块做二次切分,也可能根据整体负载分布对非尾轮的
baseM/baseN(base块大小)做自适应调整,从而使各核工作量更均衡、整体算力利用率更高。 -
效果对比
-
适用场景
- 多核并行计算场景
- 输入形状不规则,无法均匀分配的场景
- 最后一轮计算存在算力浪费的场景
算子模板归纳
SWAT模板
-
模板特点:
- 作为基础模板用于处理非特化模板的所有场景,具有广泛的适用性
- 适用于大规模矩阵乘法场景,在Cube Bound场景下表现优异
- 支持灵活的形状配置,可适应不同维度的矩阵输入
- 综合性能最优,是大多数应用场景的首选模板
-
涉及优化手段:
- SWAT(自适应滑动窗口):提升L2命中率,优化多核并行效率
- L1 Bank冲突优化:消除Bank冲突,提升MTE1带宽利用率
- Scale缓存:优化Scale数据搬运,减少传输开销
- 尾轮负载均衡:均衡多核负载,消除算力浪费
- Double Buffer:隐藏内存访问延迟,提升流水线并行度
- UnitFlag:提升计算与搬出流水并行度
-
模板实现(非A全载):
- MXFP4: quant_matmul_mxfp4_swat.asc
- MXFP8: quant_matmul_mxfp8_swat.asc
-
模板实现(A全载):
FullLoad模板
-
模板特点:
- 全载模板,主要应用于Decode等MTE2 Bound场景
- 适用的Shape特征为m较小,满足左矩阵A全载L1缓冲区(当前样例仅实现A全载,暂不支持B全载)
- 减少MTE2搬运次数,显著降低数据传输开销
- 适用于小批量、高频率的计算场景
-
涉及优化手段:
- 全载优化:减少GM到L1搬运次数,降低传输开销
- L1 Bank冲突优化:消除Bank冲突,提升MTE1带宽利用率
- Scale缓存:优化Scale数据搬运,减少传输开销
- Double Buffer:隐藏内存访问延迟,提升流水线并行度
- UnitFlag:提升计算与搬出流水并行度
-
模板实现:待补充
优化策略选择指南
根据Bound类型选择优化策略
| Bound类型 | 推荐优化策略 | 优先级 |
|---|---|---|
| Cube Bound | SWAT + 尾轮负载均衡 | 高 |
| MTE2 Bound | 全载优化 + Scale缓存 | 高 |
| MTE1 Bound | L1 Bank冲突优化 | 中 |
| FIXPIPE Bound | UnitFlag | 中 |
| 流水停顿 | Double Buffer | 高 |
根据输入特征选择模板
| 输入特征 | 推荐模板 | 原因 |
|---|---|---|
| 大规模矩阵 | SWAT模板 | 提高L2命中率,提升计算单元利用率 |
| 小规模矩阵(满足A全载) | FullLoad模板 | A常驻L1,减少MTE2搬运,降低搬运开销 |
| 不规则形状/分核不均 | SWAT模板 + 负载均衡 | 均衡多核负载,避免算力浪费 |
性能调优实践步骤
- 性能分析:使用Profiling工具结合性能建模分析当前算子的Bound类型
- 瓶颈识别:确定主要的性能瓶颈所在
- 策略选择:根据Bound类型选择合适的优化策略
- 模板选择:根据输入特征选择合适的算子模板
- 参数调优:调整tiling参数,优化缓冲区使用
- 效果验证:对比优化前后的性能数据
- 迭代优化:根据结果进一步调整优化策略
总结
MX量化矩阵乘算子的性能优化是一个系统性的工程,需要根据具体的场景和瓶颈选择合适的优化策略。通过合理应用SWAT、Double Buffer、UnitFlag等优化技术,可以显著提升算子在昇腾平台上的执行效率。