From e99f0b96aea9c941fd2267367d706e0274fbeecd Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 27 Aug 2026 14:17:36 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=203.1=20=E6=BA=90=E7=A0=81?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=EF=BC=9A=E5=B1=95=E5=BC=80=E5=90=84=E5=88=86?= =?UTF-8?q?=E6=94=AF=E5=8E=9F=E7=90=86/=E5=85=AC=E5=BC=8F/=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=B5=81=EF=BC=8C=E8=A1=A5=E5=85=85=E7=AB=A0=E8=8A=82?= =?UTF-8?q?=E5=85=B3=E7=B3=BB=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Matmul/3_源码对比/3.1_mat_mul_v3源码解析.html | 500 +++++++++++------- 1 file changed, 319 insertions(+), 181 deletions(-) diff --git a/Matmul/3_源码对比/3.1_mat_mul_v3源码解析.html b/Matmul/3_源码对比/3.1_mat_mul_v3源码解析.html index e77756f..e03676d 100644 --- a/Matmul/3_源码对比/3.1_mat_mul_v3源码解析.html +++ b/Matmul/3_源码对比/3.1_mat_mul_v3源码解析.html @@ -19,236 +19,373 @@

0. 源码结构总览

-

mat_mul_v3 采用 Host Tiling(CPU)+ Device Kernel(NPU) 两层结构,中间通过 tiling key(位域编码) 传递决策结果:

-
┌─────────────────────────── Host(CPU 侧,算子启动前)───────────────────────────┐
-│  MatMulV3Tiling::DoTiling()                                                    │
-│    └─ MMTilingRegistry 按 priority 顺序尝试各 tiling 类(策略模式)             │
-│         ├─ MatMulV3KEqZeroTiling      (priority 0)                             │
-│         ├─ MatMulV3ToMulTiling        (priority 1)                             │
-│         ├─ MatMulV3ToVectorTiling     (priority 2)                             │
-│         ├─ MatMulV3BasicStreamKTiling (priority 3)                             │
-│         ├─ MatMulV3BasicAswtTiling    (priority 4)                             │
-│         └─ MatMulV3AswTiling          (priority 999, 兜底)                     │
-│    每个类的 IsCapable() 判定是否满足条件,满足则 DoOpTiling() 计算 tiling 参数,│
-│    编码成 tiling key + tiling data 下发给 device。                              │
-└─────────────────────────────────────────────────────────────────────────────────┘
-                                    │ tiling key + tiling data
+

mat_mul_v3 采用 Host Tiling(CPU)+ Device Kernel(NPU) 两层结构,中间以 tiling key(位域编码)+ tiling data(参数结构体) 传递决策:

+
┌─────────────────────────── Host(CPU 侧,算子启动前执行一次)───────────────────────────┐
+│  MatMulV3Tiling::DoTiling()                                                             │
+│    └─ MMTilingRegistry::DoTilingImpl()  按 priority 依次尝试各 tiling 类(策略模式)    │
+│         ├─ MatMulV3KEqZeroTiling        (priority 0)                                    │
+│         ├─ MatMulV3ToMulTiling          (priority 1)                                    │
+│         ├─ MatMulV3ToVectorTiling       (priority 2)                                    │
+│         ├─ MatMulV3BasicStreamKTiling   (priority 3)                                    │
+│         ├─ MatMulV3BasicAswtTiling      (priority 4)                                    │
+│         └─ MatMulV3AswTiling            (priority 999, 兜底)                            │
+│    每个类:IsCapable() 判条件 → DoOpTiling() 算参数 → 编码 tiling key + tiling data     │
+└─────────────────────────────────────────────────────────────────────────────────────────┘
+                                    │ tiling key(分支选择结果)+ tiling data(参数)
                                     ▼
-┌─────────────────────────── Device(NPU 侧,每核执行)───────────────────────────┐
-│  mat_mul_v3() 入口:if constexpr 按 (ApiLevel, FullLoad, Model, L0C2Out) 分发  │
-│    ├─ MatMulInputKEqZeroClearOutput   K==0 清零                                │
-│    ├─ MatMulToMulActKernel / MatMulToVectorActKernel  退化向量乘                │
-│    ├─ MatMulStreamKKernel / MatMulStreamKSplitKKernel  StreamK 切 K            │
-│    ├─ MatMulBasicKernel / MatMulBasicSplitKKernel     ASWT 基础模板            │
-│    ├─ MatMulAL1FullLoadKernel / MatMulBL1FullLoadKernel  A/B 全载             │
-│    └─ MatMulFixpipeOptiTensorKernel   Fixpipe 随路搬出优化                     │
-└─────────────────────────────────────────────────────────────────────────────────┘
+┌─────────────────────────── Device(NPU 侧,每个核独立执行)────────────────────────────┐ +│ mat_mul_v3() 入口:if constexpr 按 (ApiLevel, FullLoad, Model, L0C2Out) 四元组分发 │ +│ ├─ MatMulInputKEqZeroClearOutput K==0 清零 │ +│ ├─ MatMulToMulActKernel / MatMulToVectorActKernel 退化向量乘 │ +│ ├─ MatMulStreamKKernel / MatMulStreamKSplitKKernel StreamK 切 K │ +│ ├─ MatMulBasicKernel / MatMulBasicSplitKKernel ASWT 基础模板 │ +│ ├─ MatMulAL1FullLoadKernel / MatMulBL1FullLoadKernel A/B 全载 │ +│ └─ MatMulFixpipeOptiTensorKernel Fixpipe 随路搬出优化 │ +└─────────────────────────────────────────────────────────────────────────────────────────┘

关键枚举mat_mul_v3_tiling_key_public.h):

- + +
维度枚举值含义
MatMulV3ModelBASIC=0 / STREAM_K=1 / K_EQUAL_ZERO=2 / TO_MUL=3 / TO_MULTI_MUL=4 / SLICE=5 / BASIC_SPLIT_K=6 / SK_SPLIT_K=7主计算模型
MatMulV3FullLoadNONE=0 / A_FULL_LOAD=1 / B_FULL_LOAD=2 / AB_FULL_LOAD=3L1 全载模式
MatMulV3L0C2OutON_THE_FLY=0 / ND_FIXPIPE_1_1=1 / ND_FIXPIPE_1_2=2L0C 输出方式
MatMulV3ApiLevelHIGH=0 / BASIC=1 / TENSOR=2编程接口层级(kernel 用 BASIC/TENSOR)
MatMulV3ApiLevelHIGH=0 / BASIC=1 / TENSOR=2编程接口层级(kernel 实际用 BASIC/TENSOR)
+

贯穿全文的符号约定(维度标注)

+ + + + + + + + + + +
符号维度含义
M, N, K元素个数矩阵 C[M,N] = A[M,K] · B[K,N] 的三维
dtypeA, dtypeB字节/元素A、B 的 dtype 字节数(FP16/BF16=2,FP32=4)
baseM, baseN, baseK元素个数L0 分块尺寸(L0A/L0B 一次装的数据块),对齐 16
singleCoreM/N/K元素个数单核负责的 M/N/K 范围(= base 或更大)
mL1, nL1, kL1元素个数L1 中的分块尺寸(= singleCore 或 base,见各分支)
stepKa, stepKb无量纲(个数)K 方向 L1 分片步数(K 在 L1 中切几段)
depthA1, depthB1无量纲(个数)L1 流水深度(A/B 在 L1 中缓存的 tile 层数)
mCnt, nCnt无量纲(个数)M/N 方向 base 块个数 mCnt=⌈M/baseM⌉
aicNum, aivNumAIC 核数=32、AIV 核数=64
+

关键硬件规格(原理性推导的输入,来自 950PR 架构解读)

+ + + + + +
规格数值推导用途
Cube 每拍 MAC 数16×16×16 = 4096 MAC = 8192 FLOP单 AIC BF16 算力 = 1.65GHz × 8192 ≈ 13.5 TFLOPS
L0A / L0B / L0C / L1 / UB64KB / 64KB / 256KB / 512KB / 512KB分块尺寸上限(baseM·baseN·4B ≤ L0C → baseM=baseN=256 上限)
MTE1 / MTE3256 BPC ≈ 422.4 GB/s(单 AIC)核内 L1→L0、L0C→GM 搬移耗时
GM / L2 带宽1.6 TB/s / 5.2 TB/sMTE2 综合带宽(重复读走 L2 才喂饱 Cube)
单 AIC 分摊 HBM1.6TB/s ÷ 32 ≈ 50 GB/s算术强度要求 = 13.5T/50G ≈ 270 FLOP/Byte(带宽极紧张)

1. 分支决策总表(DAV_3510 = 950PR)

策略优先级定义在 matmul_v3_tiling_strategy.h

{ NpuArch::DAV_3510, {K_EQUAL_ZERO, TO_MUL, TO_MULTI_MUL, BASIC_STREAM_K, BASIC_ASWT} }
-

各 tiling 类按 priority 注册(MM_REGISTER_TILING_TEMPLATE),MMTilingRegistry::DoTilingImpl 按优先级逐个 IsCapable() + DoTiling()第一个成功者胜出

- - - - - - - +

MMTilingRegistry::DoTilingImpl 按 priority 顺序逐个 IsCapable() + DoTiling()第一个成功者胜出(每个 tiling 类的 DoTiling 返回失败则尝试下一优先级)。

+
Priority分支触发条件(IsCapable)Device Kernel
0K_EQUAL_ZERO无 bias 且 K == 0MatMulInputKEqZeroClearOutput
1TO_MUL高精度FP32(isForceGrpAccForFp32) ∧ 非slice ∧ (M==1 ∨ N==1) ∧ A/B 均 FP32MatMulToMulActKernel
2TO_MULTI_MUL高精度FP32 ∧ 非slice ∧ !ATrans ∧ BTrans ∧ 无bias ∧ A/B 均 FP32MatMulToVectorActKernel
3BASIC_STREAM_Kdeterministic≤1 ∧ A为ND ∧ 非slice ∧ aivNum==2·aicNum ∧ (SK 或 DPSK 条件)MatMulStreamKKernel / StreamKSplitK / StreamKActKernel
4BASIC_ASWT无条件(主分支)MatMulBasicKernel 等(含 fullLoad/fixpipe 子分支)
999BASE(ASW)无条件(最终兜底,老 Cmct 接口)MatMulActKernel
+ + + + + +
Priority分支Model 枚举触发条件(IsCapable)Device Kernel
0K_EQUAL_ZEROK_EQUAL_ZERO(2)无 bias 且 K==0MatMulInputKEqZeroClearOutput
1TO_MULTO_MUL(3)高精度FP32 ∧ 非slice ∧ (M==1 ∨ N==1) ∧ A/B 均 FP32MatMulToMulActKernel
2TO_MULTI_MULTO_MULTI_MUL(4)高精度FP32 ∧ 非slice ∧ !ATrans∧BTrans ∧ 无bias ∧ FP32MatMulToVectorActKernel
3BASIC_STREAM_KSTREAM_K(1)/SK_SPLIT_K(7)deterministic≤1 ∧ A为ND ∧ 非slice ∧ aivNum==2·aicNum ∧ (SK∨DPSK)MatMulStreamKKernel 等
4BASIC_ASWTBASIC(0)/SLICE(5)/BASIC_SPLIT_K(6)无条件(主分支)MatMulBasicKernel 等(含全载/fixpipe 子分支)
999BASE(ASW)BASIC(0)无条件(最终兜底,老 Cmct 接口)MatMulActKernel

2. 各分支详细分析

+ +

2.1 K_EQUAL_ZERO(priority 0)

-

条件!hasBias && kValue == 0

+

触发条件!hasBias && K == 0

+

原理:K=0 时 C[i,j] = 0,输出恒为全零矩阵。若走 Cube,MMAD 对空 K 做无效计算;而 64 个 AIV 是天然的并行批量写单元,直接对 CM×N 个元素清零即可。

实现matmul_v3_k_equal_zero_tiling.cpp + mat_mul_input_k_eq_zero_clear_output.h):

+
totalDataAmount = M · N            // 需清零的元素总数(元素个数)
+usedCoreNum = aivNum               // 64 个 AIV 并行
+

Device 侧 MatMulInputKEqZeroClearOutput(biasGM, cGM, tilingData):每个 AIV 负责一段连续的 C 地址,一次搬移清零。数据流极简:

+
AIV ──(写0)──► GM(C)     // 无 GM 读、无 Cube 参与
+

评价:正确且高效(不浪费 Cube、不产生 GM 读流量)。适用面窄(仅 K==0 且无 bias)。

+
+

2.2 TO_MUL(priority 1)—— M==1 或 N==1 的 FP32 退化向量乘

+

触发条件isForceGrpAccForFp32(op_impl_mode_enum==0x4 高精度 FP32)∧ 非 slice ∧ (M==1 ∨ N==1) ∧ dtypeA==dtypeB==FP32。

+

原理(结合硬件):Cube 的 MMAD 指令最小分形是 16×16×16。当 M==1 时,MMAD 的 M 维 16 个 lane 只能用 1 个 → Cube 算力利用率仅 1/16 ≈ 6%。此时 [1,K]·[K,N] 本质是一个 K 维向量与 N 个 K 维向量的点积,用 AIV 的向量乘加(Mul+ReduceSum)天然适合,且 64 个 AIV 的 FP32 算力 27 TFLOPS 足够覆盖。

+

实现matmul_v3_to_mul_tiling.cpp + mat_mul_to_mul_cmct.h):数据流为「GM→UB→AIV 向量乘→UB→GM」,全程不走 Cube:

+
GM(A[M=1,K]) ──MTE2──► UB ──AIV向量乘加──► UB ──MTE3──► GM(C[N])
+GM(B[K,N])   ──MTE2──► UB
+

tiling 参数由 UB 容量ubSize/4 个 float)反推:

+
tmpMN  = ⌈(M·N) / aivNum⌉                        // 每核摊到的 MN 元素数(元素个数)
+baseMN = min(Align(tmpMN, 对齐), BASE_MN)        // MN 方向分块(元素个数)
+baseK  = (ubCount - baseMN - biasCount)/5/baseMN // K 方向分块,受 UB 容量约束(元素个数)
+loopK  = ⌈K / baseK⌉                             // K 循环次数(无量纲)
+usedCoreNum = min(⌈M·N/baseMN⌉, aivNum)          // 实际核数
+

dataCopyMode 区分「K 内轴连续((K,N)/(K,M) 布局)」还是「MN 内轴连续」,决定 baseK/baseMN 的取舍顺序。

+

评价:对退化场景绕开 Cube 走 AIV 正确。局限:① 仅覆盖高精度 FP32,FP16/BF16 的 M==1/N==1 无退化分支、仍走 Cube(§6 改进点);② TO_MULTI_MUL 不支持 bias。

+
+

2.3 TO_MULTI_MUL(priority 2)—— 特定转置组合的 FP32 退化向量乘

+

触发条件:高精度FP32 ∧ 非slice ∧ !ATrans ∧ BTrans ∧ 无bias ∧ FP32。

+

原理:与 TO_MUL 同(退化向量乘),但锁定 !ATrans∧BTrans:A 行主序(K 连续)、B 列主序(K 连续),内积方向 K 两侧都连续,向量乘访存顺序、无需 gather。

+

实现matmul_v3_to_multi_mul_tiling.cpp + mat_mul_to_multi_mul_cmct.h):同样「GM→UB→AIV 向量乘→UB→GM」。核数分配用 CalcBasicBlock() 启发式均衡:

+
mCore = ⌈M/baseM⌉, nCore = ⌈N/baseN⌉
+if (mCore·nCore < aivNum)  CalcBasicBlock()    // 块数不足分满核时重调 baseM/baseN
+while (baseN ≥ 2·baseM ∧ nCore < aivNum/2):    // N 侧块太多 → nCore·=2, baseN=⌈N/nCore⌉
+while (baseM ≥ 2·baseN ∧ mCore < aivNum/2):    // M 侧块太多 → mCore·=2, baseM=⌈M/mCore⌉
+usedCoreNum = min(mCore·nCore, aivNum)
+

评价:与 TO_MUL 同族但更窄(限转置、无 bias)。共同原则:矩阵乘退化到 M==1 或 N==1 时,绕开 Cube 走 AIV,规避 Cube 16 对齐分形浪费。

+
+

2.4 BASIC_STREAM_K(priority 3)—— 切 K 满核

+

2.4.0 解决的问题(硬件原理)

+

核心矛盾:baseM=baseN=256 时,若 M、N 较小(如 M=N=256),则 mCnt·nCnt = 1×1 = 1 个 MN 块,但 aicNum=32只有 1 个核工作、31 核空闲,算力利用率 1/32。950PR「算力/带宽比极高」架构下,大 K 瘦高形状(如 [256, 8192]×[8192, 256])是典型 case:MN 方向分不满核,但 K 很大、总计算量足够喂饱 32 核。

+

解法:把 K 轴切成 kCnt 份分给多个核,每个核算 M×N×singleCoreK部分和,最后跨核累加。有效并行度变为 mCnt·nCnt·kCnt

+
普通 ASWT(M=N=256, K=8192,kCnt=1):
+  ┌────────────────────────────────────────────┐
+  │ 核0: [256×256] × [256×8192]   (算完整 K)    │ ← 只有 1 核,31 核空闲
+  └────────────────────────────────────────────┘
+
+StreamK(切 K,kCnt=32):
+  ┌───────────────┐  ┌───────────────┐        ┌───────────────┐
+  │ 核0: K[0:256]  │  │ 核1: K[256:512]│  ...   │ 核31: K[...]   │  ← 32 核各算一段 K
+  └───────┬───────┘  └───────┬───────┘        └───────┬───────┘
+          └──────────────────┴──────────────────────────┘
+                          ▼ 核间累加(workspace,AIV 顺序累加)
+                    C[M,N] = Σ_k 部分和
+

2.4.1 分支结构(含 3 个子模式)

+

IsCapable 前置条件MatMulV3BasicStreamKTiling::IsCapable):

+
deterministicLevel ≤ 1        // 切 K 核间累加顺序不确定,强一致性场景禁用整分支
+∧ aFormat == ND               // 左矩阵必须 ND
+∧ 非 slice                    // 不支持非连续视图
+∧ aivNum == 2·aicNum          // 必须 AIC:AIV = 1:2
+∧ (CheckStreamKSKTiling() ∨ CheckStreamKDPSKTiling())
+

子模式 ①:SK(纯切 K) —— CheckStreamKSKTilingDav3510

+
align(K, 256) >= max(8192, aicNum·256B) / dtypeA      // K 足够大
+mCnt · nCnt <= aicNum / 2                              // MN 块数不超过核数一半
+

语义:M/N 小到「MN 块数 ≤ 核数一半」,K 大 → 全 K 切分,每核算一段 K。

+

注:FP32 且非 hf32 时,alignValue 从 256 退化为 32(BLOCK_BYTE_SIZE)。

+

子模式 ②:DPSK(数据并行 StreamK) —— CheckStreamKDPSKTilingDav3510

+
M % 256 == 0 且 N % 256 == 0                           // MN 严格 256 对齐
+K >= max(8192, aicNum·128B) / dtypeA                   // K 足够大
+totalMNCnt >= aicNum                                   // MN 块数能分满核(主轮)
+totalMNCnt % aicNum != 0                               // 但有尾轮余数
+(totalMNCnt % aicNum) <= aicNum/2                      // 余数不超过核数一半
+

语义:主轮 MN 块数 ≥ 核数(DP 满核、K 不分片),尾轮剩余 MN 块 < 核数 → 尾轮把 K 切开分给空闲核,且提前执行让 AIV 累加与 AIC 下一轮计算重叠(数据并行)。

+

子模式 ③:SK_SPLIT_K:SK/DPSK 基础上,若 FP32 ∧ singleCoreK ≥ FP32_SPLIT_K_THRESHOLD,则单核内再切 K(splitSingleK,保 FP32 累加精度),model 由 STREAM_K 升级为 SK_SPLIT_K

+

2.4.2 tiling 参数推导(DoOpTiling

+
baseM, baseN        // 由 ResetBase + 后续逻辑给出(§3.2),通常 256
+mCnt = ⌈M/baseM⌉, nCnt = ⌈N/baseN⌉
+totalMNCnt = mCnt · nCnt
+
+if (totalMNCnt <= aicNum/2):                        // 纯 SK 模式
+    调整 mCnt/nCnt 到 [aicNum/3, aicNum/2] 区间     // 避免切得过碎
+    baseM = Align(⌈M/mCnt⌉, 16); baseN = Align(⌈N/nCnt⌉, 16)
+    kCnt = ⌊aicNum / totalMNCnt⌋                     // 每个 MN 块分配多少核切 K
+    singleCoreK = ⌈K / kCnt⌉                         // 单核 K 分片(元素个数)
+else:                                               // DPSK 模式(尾轮切 K)
+    kCnt = aicNum / (totalMNCnt % aicNum)
+    singleCoreK = ⌈K / kCnt⌉
+    kCnt = ⌈K / singleCoreK⌉                         // 回算实际切分数
+
+// baseK:受 L0A 容量约束(§3.3)
+kValueMax = ⌊L0A/DB/dtypeA / max(baseM, baseN)⌋   (按 128B/dtype 或 16 对齐)
+baseK = min(singleCoreK, kValueMax)
+
+CalL1Tiling(...)                                     // 复用 §3.4 计算 stepKa/stepKb
+workspace = aicNum·256·256·4B + 20·MB               // 核间累加工作区(字节)
+

L0C2Out:N 大且 N 不对齐(N>64 ∧ N%16≠0 ∧ M>2 ∧ M·N≥256)→ ND_FIXPIPE_1_2,否则 ON_THE_FLY(同 §2.5.4 的 fixpipe 逻辑)。

+

2.4.3 Device 数据流(block_scheduler_streamk.h + StreamK kernel)

+

StreamK 的 L1 只装一个 base 块(mL1=baseM, nL1=baseN),核间通过 workspace 累加:

+
DP 主轮(每核一个 MN 块,算完整 K):
+  GM(A块) ─MTE2─► L1 ─MTE1─► L0A ─┐
+                                   ├─MMAD─► L0C ─Fixpipe─► GM(C块)   // 直接写结果
+  GM(B块) ─MTE2─► L1 ─MTE1─► L0B ─┘
+
+SK 尾轮(每核一个 MN 块的一段 K):
+  GM(A块) ─► L1 ─► L0A ─┐
+                        ├─MMAD─► L0C ─Fixpipe─► workspace(部分和)     // 写部分和
+  GM(B块) ─► L1 ─► L0B ─┘
+  然后 AIV 从 workspace 顺序累加(Atomic/确定性累加)─► GM(C块)
+

CheckIsSkScene(tileIdx) 判定当前核索引属于 DP 轮还是 SK 轮:ceil((tileIdx+1)/usedCoreNum) == ceil(tileNum/usedCoreNum)(最后一轮是 SK)。

+

2.4.4 评价

-

评价:K=0 是退化空矩阵乘,输出恒为 0。用 AIV 批量清零、不浪费 Cube 计算单元,实现正确且高效。适用面窄(仅 K==0 且无 bias)。

-

2.2 TO_MUL(priority 1)

-

条件isForceGrpAccForFp32(op_impl_mode_enum == 0x4 高精度)∧ 非 slice ∧ (M==1 ∨ N==1) ∧ A/B 均 FP32。

-

实现matmul_v3_to_mul_tiling.cpp + mat_mul_to_mul_cmct.h):

- -

评价:M==1 或 N==1 时 Cube 的 16×16×16 分形利用率极低,改用 AIV 向量乘是正确决策。局限:仅覆盖高精度 FP32 模式(isForceGrpAccForFp32),FP16/BF16 的 M==1/N==1 场景走不到这里。

-

2.3 TO_MULTI_MUL(priority 2)

-

条件:高精度FP32 ∧ 非slice ∧ !ATrans && BTrans ∧ 无 bias ∧ A/B 均 FP32。

-

实现matmul_v3_to_multi_mul_tiling.cpp + mat_mul_to_multi_mul_cmct.h):

- -

评价:与 TO_MUL 同类,但更窄(限定转置组合、不支持 bias)。两个分支共同说明:当矩阵乘退化到 M==1 或 N==1 时,源码选择绕开 Cube 走 AIV,规避 Cube 16 对齐分形粒度的浪费。

-

2.4 BASIC_STREAM_K(priority 3)—— StreamK / DPSK

-

IsCapable 前置条件deterministicLevel ≤ 1(切 K 核间累加顺序不确定,强一致性场景禁用)∧ A 为 ND ∧ 非 slice ∧ aivNum == 2·aicNum

-

SK 模式条件CheckStreamKSKTilingDav3510):

-
align(K, 256) >= max(8192, aicNum·256B) / dtypeSize
-mCnt · nCnt <= aicNum / 2        // MN 用 base 块切的份数不超过核数一半
- -

DPSK 模式条件CheckStreamKDPSKTilingDav3510):

-
M % 256 == 0 且 N % 256 == 0
-K >= max(8192, aicNum·128B) / dtypeSize
-totalMNCnt >= aicNum 且 totalMNCnt % aicNum != 0 且 余数 <= aicNum/2
- -

tiling 核心DoOpTiling):

- -

Device swizzleblock_scheduler_streamk.h):

- -

评价

- -

2.5 BASIC_ASWT(priority 4)—— 主分支

-

IsCapable:无条件返回 true。其 DoOpTiling 先调用父类 MatMulV3AswTiling::DoOpTiling() 完成基础 tiling(baseM/baseN/baseK/singleCore),再按顺序做子决策:

+
+

2.5 BASIC_ASWT(priority 4)—— 主分支(含 4 个子分支)

+

IsCapable:无条件返回 true(除命中 StreamK 场景外的绝大多数 case 都落在这里)。

+

DoOpTiling 先调用父类 MatMulV3AswTiling::DoOpTiling() 完成基础 tiling(ResetBase→GetRebalanceBlock→CalcTailBasicBlock→CalL1Tiling,即 §3 的完整流程),得到 baseM/baseN/baseK 后,再按顺序做子分支决策

DoOpTiling():
-  isSlice_ = IsSelfNonContiguous()                     // 非连续 3D slice
-  l0C2Out_ = GetL0C2Out()                              // 是否走 fixpipe 优化
-  if (!isSlice_ && CheckAL1FullLoad())  → DoAL1FullLoad()   // A 全载 L1
-  elif (!isSlice_ && CheckBL1FullLoad()) → DoBL1FullLoad()  // B 全载 L1
-  elif (l0C2Out_ == ON_THE_FLY)         → 普通场景,按 L1 剩余容量均分 stepK
+  isSlice_ = IsSelfNonContiguous()                  // 子分支④:非连续 3D slice
+  l0C2Out_ = GetL0C2Out()                           // 子分支③:fixpipe 优化判定
+  if (!isSlice_ && CheckAL1FullLoad())  → DoAL1FullLoad()   // 子分支①:A 全载
+  elif (!isSlice_ && CheckBL1FullLoad()) → DoBL1FullLoad()  // 子分支②:B 全载
+  elif (l0C2Out_ == ON_THE_FLY)         → 普通场景,L1 剩余容量均分 stepK
   else                                  → fixpipe 优化场景
-  CheckFp32SplitK()                                     // FP32 大 K → BASIC_SPLIT_K
-  CheckApiLevelAndModel()                               // tensor/basic api
-

A 全载条件CheckAL1FullLoad):

+ CheckFp32SplitK() // FP32 大 K → BASIC_SPLIT_K + CheckApiLevelAndModel() // BASIC / TENSOR api +

ASWT 的标准数据流(所有子分支共享的骨架,mat_mul_asw_kernel.hmm_.Iterate()):

+
GM(A块) ─MTE2─► L1(A) ─MTE1─► L0A ─┐
+                                    ├─ MMAD(16×16×16) ─► L0C ─Fixpipe─► GM(C块)
+GM(B块) ─MTE2─► L1(B) ─MTE1─► L0B ─┘
+   (MTE2 重复读可命中 L2,5.2TB/s;L1 用 Double Buffer 掩盖搬移延迟)
+
+

2.5.1 子分支①:A 全载 L1(A_FULL_LOAD)

+

触发条件CheckAL1FullLoad):

+
l0C2Out == ON_THE_FLY                 // 不与 fixpipe 叠加
+∧ cubeBoundParam > cubeBoundEdge      // 非 CubeBound(MTE2 是瓶颈,重复读代价高)
+∧ nCnt > aicNum                       // N 方向块数多于核数 → 同一 A 块被跨 N 的核重复读
+∧ !(K <= 128 && mCnt != 1)            // 排除 Fixp Bound 多轮
+∧ (M·K·dtypeA + bias) <= 3/4·L1       // 整个 A + bias 能装进 3/4 L1(384KB)
+

原理(结合硬件):当 nCnt > aicNum,同一列(固定 m)的 A 块会被 nCnt 个核重复读。若 A 的 M×K 整个能装进 L1,则把它常驻 L1,只流式搬 B → A 的重复读从 GM/L2 级别降为 0,只剩 B 的单次读 + A 的单次读。对 950PR 的 1.6TB/s 带宽是直接省流。

+
A 全载数据流(A 常驻 L1,B 按 baseN 流式):
+  GM(A[M×K]) ─MTE2─► L1(A, 常驻, 不再搬出)
+                     │每次只搬 B 块:
+  GM(B[K×baseN]) ─MTE2─► L1(B) ─MTE1─► L0B ─┐
+  L1(A) ─MTE1─► L0A ────────────────────────┼─MMAD─► L0C ─Fixpipe─► GM(C)
+

tilingDoAL1FullLoad):

+
singleCoreM = M                       // M 不再分核(A 常驻,M 方向一块)
+singleCoreN = baseN                   // N 方向按 baseN 分
+aL1Size = M·K·dtypeA                 // A 全载字节数
+remainL1 = L1 - (aL1Size + bias)      // L1 剩余容量
+maxBaseN = min(remainL1/(baseK·dtypeB·DB),  L0C/(baseM·4B·DB))   // 受 L1 剩余 + L0C 双缓冲约束
+baseN = min(baseN, maxBaseN, ⌈N/aicNum⌉对齐16)                    // 三者取小
+stepKa = ⌈K/baseK⌉, stepM = ⌈M/baseM⌉    // K、M 方向 L1 分片
+stepKb = 由 B 的 L1 搬移量 + 256B 对齐确定  // B 侧 K 分片
+l1BufferNum = (4·B搬移量 + aL1Size + bias > L1) ? 2 : 4    // 能否 4-buffer
+dbL0C = (baseM·baseN·4B·2 <= L0C) ? 2 : 1                 // L0C 双缓冲
+usedCoreNum = min(nCore·batchNum, aicNum)
+
+

2.5.2 子分支②:B 全载 L1(B_FULL_LOAD)

+

与 A 全载完全对称:!CubeBound ∧ mCnt > aicNum ∧ (K·N·dtypeB + bias) <= 3/4·L1 时,整个 B 常驻 L1,A 按 baseM 流式。

+
B 全载数据流(B 常驻 L1,A 按 baseM 流式):
+  GM(B[K×N]) ─MTE2─► L1(B, 常驻)
+  GM(A[baseM×K]) ─MTE2─► L1(A) ─MTE1─► L0A ─┐
+  L1(B) ─MTE1─► L0B ────────────────────────┼─MMAD─► L0C ─Fixpipe─► GM(C)
+

tiling 对称:singleCoreN=NsingleCoreM=baseMbaseM = min(baseM, 剩余容量上限, L0C上限, ⌈M/aicNum⌉)

+
+

2.5.3 子分支③:Fixpipe 随路搬出优化(ND_FIXPIPE_1_1 / 1_2)

+

触发条件GetL0C2OutDav3510):

+
isValidMKN   = (K <= 256) ∧ (M >= 256)                // 计算量小、M 大
+isMultiRound = (mCnt·nCnt > aicNum)                   // 多轮(搬出流水与计算重叠才有意义)
+isUnalignedN = (N·cDtypeSize % 128 != 0) ∧ (N·cDtypeSize > 256)   // N 不对齐 128B
+fixpipeBound = isValidMKN ∧ isMultiRound ∧ isUnalignedN
+→ 满足且 aivNum == 2·aicNum:
+    FP16/BF16 → ND_FIXPIPE_1_1      FP32 → ND_FIXPIPE_1_2
+

原理(结合硬件):小 K 大 M 场景,MMAD 计算时间短,T_FIXPIPE = M·N·dtypeC / BW_fixp 可能超过 T_MMAD,成为 Fixpipe Bound。950PR 的 Fixpipe 随路硬化(L0C→GM 直接量化/排布转换)但对 N 不对齐(非 128B 对齐)的搬出效率低ND_FIXPIPE_1_1/1_2 用 AIV 辅助做搬出对齐(1V1 或 1V2 的 AIC:AIV 配比),配合 SetMMLayoutTransform(true)(fixp 用 N 搬出)+ UnitFlag(512B 粒度同步),让 Fixpipe 与 Cube 并行、搬出对齐。

+
普通(ON_THE_FLY):   MMAD ──────► 等算完 ──Fixpipe──► GM    (串行)
+Fixpipe 优化:         MMAD(512B) ─► 立即随路 Fixpipe ─► GM   (并行,粒度 512B)
+
+

2.5.4 子分支④:非连续 Slice(SLICE model)

+

触发条件IsSelfNonContiguous(context) —— self 是 view 且 storageShape 为 1D、self 3D / mat2 2D(createView with TensorV2 场景)。此时 model=SLICE,MatMulBasicKernelsliceM/srcNdStride 做非连续搬移(NDDMA 多维重排),GetBlockShape 对 sliceM 对齐。

+
+

2.5.5 评价

-

B 全载条件CheckBL1FullLoad):对称(非 CubeBound ∧ mCnt > aicNum ∧ B+bias ≤ 3/4 L1)。

-

A 全载实现DoAL1FullLoad):整个 A 常驻 L1,B 按 baseN 分块流式搬入;singleCoreM = M(不再分 M)、singleCoreN = baseNbaseN 取 min(原值, L1剩余容量上限, L0C双缓冲上限, 负载均衡值);stepKb 由 B 的 L1 搬移量 + 256B 对齐约束确定;l1BufferNum 判断能否 4-buffer。

-

B 全载实现DoBL1FullLoad):对称(整个 B 常驻 L1,A 流式)。

-

L0C2Out(fixpipe 优化)条件GetL0C2OutDav3510):

-
isValidMKN    = K<=256 && M>=256
-isMultiRound  = mCnt·nCnt > aicNum
-isUnalignedN  = (N·cDtypeSize % 128 != 0) && (N·cDtypeSize > 256)
-fixpipeBound  = isValidMKN && isMultiRound && isUnalignedN
-

满足且 aivNum == 2·aicNum → FP16/BF16 选 ND_FIXPIPE_1_1,FP32 选 ND_FIXPIPE_1_2

-

Device kernel 分发mat_mul_v3.cppif constexpr):按 (ApiLevel, FullLoad, Model, L0C2Out) 组合映射到 MatMulBasicKernel / MatMulAL1FullLoadKernel / MatMulBL1FullLoadKernel / MatMulFixpipeOptiTensorKernel / MatMulBasicSplitKKernel(均基于 Blaze::Gemm 模板库)。

-

评价

- +

2.6 BASE(priority 999)—— 老 Cmct 接口兜底

实现matmul_v3_asw_tiling.cpp + mat_mul_asw_kernel.h / mat_mul_asw_block.h):

-

评价:作为最终兜底保证正确性,逻辑与 BASIC_ASWT 基础 tiling 一致,但没有全载 / fixpipe / StreamK 等新优化,性能上限低于主分支。

+

与 BASIC_ASWT 的区别:两者共用同一套 tiling 引擎和 swizzle,区别只在 Device 接口代际——BASE 走老 Cmct 接口(无全载/fixpipe/StreamK 的 kernel 模板),BASIC_ASWT 走新 Blaze 接口(支持全载/fixpipe/SplitK)。实际运行时 BASIC_ASWT(priority 4)几乎总是先命中,BASE 仅在注册表异常时兜底。

+

评价:保证正确性;性能上限低于主分支(缺全载/fixpipe/SplitK 等新优化)。


-

3. 核心 tiling 算法(决定 baseM/baseN/baseK 与单核形状)

-

3.1 ResetBase(初始值,matmul_v3_tiling_helper.cpp

-
// ResetBaseDefault(DAV_3510 在此基础上改 baseM)
-usedCoreNum = aicNum;                     // 32
-baseM = 256;  baseN = 256;                // 950PR 的 base 块
-baseK = 128B / dtypeSize;                 // FP16=64, FP32=32
-iterateOrder = ITER_COL_FIRST;            // 列优先
-singleCoreK = K; singleCoreM/N = baseM/N;
+

3. 核心 tiling 算法(ASW 系分支共用的参数计算引擎)

+ +

3.1 ResetBase(初始值)

+
// ResetBaseDav3510(950PR)
+usedCoreNum = aicNum = 32
+baseM = 256;  baseN = 256                // 950PR 的 base 块(上代为 128)
+baseK = 128B / dtypeA                    // FP16/BF16=64 元素,FP32=32 元素
+iterateOrder = ITER_COL_FIRST            // 列优先遍历
+singleCoreK = K; singleCoreM/N = baseM/N
+

为什么 baseM=baseN=256:L0C=256KB,FP32 累加 256×256×4B = 256KB 恰好填满 L0C。baseM=baseN=256 是"L0C 能容纳的最大方块",也是重复读最少的配置(重复读 ∝ 1/baseM + 1/baseN,见 §3.2 的 cubeBoundParam)。950PR 的 L0C 比上代(128KB)大一倍,所以 baseM 从 128 升到 256。

+

为什么 baseK = 128B/dtype:GM→L1 高效搬移要求单次 dValue ≥ 128B(连续列数据量)。K 方向对齐 128B 保证 MTE2 搬移效率。

3.2 GetRebalanceBlock(baseM/baseN 最优搜索,核心)

-

这是整个 tiling 最关键的函数,分两步:

-

① Roofline 判 CubeBound

-
hbmBW  = freq · 32核 · 31B/拍 / 1024      // ≈ 1.6TB/s
-l2BW   = freq · 32核 · 100B/拍 / 1024     // ≈ 5.2TB/s
-singleCoreComputePower = freq · 8         // ≈ 13.2 TFLOPS(单核 BF16)
+

分两步:

+

① Roofline 判 CubeBoundcubeBoundEdge 计算):

+
hbmBW = freq · 32核 · 31B/拍 / 1024            ≈ 1.6 TB/s
+l2BW  = freq · 32核 · 100B/拍 / 1024           ≈ 5.2 TB/s
+singleCoreComputePower = freq · 8              ≈ 13.2 TFLOPS(单核 BF16)
 computePower = singleCoreComputePower · aicNum
 
-cmr = (M+N)/(M·N)                          // 临界算术强度相关量
-cubeBoundEdge = (l2BW/computePower) + l2CacheUsage·(1 - l2BW/hbmBW)·cmr
-                - (1 + l2BW/hbmBW)/K
-cubeBoundParam = 1/baseM + 1/baseN
+cmr = (M+N) / (M·N)                            // 临界算术强度相关量(1/元素)
+l2CacheUsage = max(batch·(M+N)·K·dtypeA / L2, 1)   // L2 占用倍率(无量纲)
+cubeBoundEdge = (l2BW/computePower)
+              + l2CacheUsage·(1 - l2BW/hbmBW)·cmr
+              - (1 + l2BW/hbmBW)/K
+cubeBoundParam = 1/baseM + 1/baseN             // 重复读因子(1/元素)
 // Cube Bound 条件:cubeBoundParam <= cubeBoundEdge
-

② 搜索最优 (baseM, baseN):在 maxBaseM × maxBaseN 解空间内双重循环,对每个候选算:

-
    -
  • curCubeBoundParam = 1/curBaseM + 1/curBaseN
  • -
  • curBalanceRate(尾轮负载均衡率,GetBalanceRateWithTail
  • -
  • 目标:优先满足 CubeBound 且 balanceRate 更高;否则综合 cubeBoundParam/balanceRate 评选。
  • -
-

maxBaseM/maxBaseNGetMaxBaseWithLimit 计算,受 L0A/L0C/L1/bias table/K 对齐多重约束。

-

3.3 GetBaseK

-
maxBaseK = L0A_SIZE / DB_SIZE / dtypeSize / max(baseM, baseN)
-// 优先 K 全载进 L0A;否则按 256B 对齐;再退 128/64/32/16
-

3.4 CalL1Tiling(K 方向 L1 分片,CalL1TilingDefault

-
isKInner = !ATrans || BTrans
-maxStepK = min(ceil(K/baseK), 8)          // K 方向 L1 分片数上限 8
-// 遍历 stepK:满足 (aL1+bL1)·DB <= L1 且 K 256B 对齐 且 单次搬移量约束
-stepKa = stepKb = resKL1 / baseK
-depthA1 = stepKa · DB; depthB1 = stepKb · DB
+

物理含义:cubeBoundParam 是当前 tiling 的 MTE2 重复搬移强度,cubeBoundEdge 是"恰好 Cube Bound"的临界强度。cubeBoundParam ≤ cubeBoundEdge ⇔ MTE2 不成为瓶颈。这与官方 matmul_performance.md 的 MTE2 Bound 条件 BW_mte2 ≥ (1/baseN + 1/baseM)·dtype·16·16·16·核数·频率 等价。

+

② 搜索最优 (baseM, baseN):在 maxBaseM × maxBaseN 解空间双重循环,每个候选算:

+
curCubeBoundParam = 1/curBaseM + 1/curBaseN
+curBalanceRate     = GetBalanceRateWithTail(...)   // 尾轮负载均衡率(无量纲 0~1)
+目标:优先满足 CubeBound 且 balanceRate 更高;
+     否则综合 (curCubeBoundParam/curBalanceRate) 评选(值小者优)
+

maxBaseM/maxBaseNGetMaxBaseWithLimit 计算,受 L0A/L0C/L1/bias table/K 对齐多重约束。搜索步长 baseMAlignUnit/baseNAlignUnit 与转置、fixp bound 相关(16 / 32 / 64 / 128B 对齐)。

+

3.3 GetBaseK(baseK 约束)

+
maxBaseK = L0A_SIZE/DB_SIZE/dtypeA / max(baseM, baseN)   // 受 L0A 容量约束(元素个数)
+// K 能全载进 L0A 则取 K 对齐值;否则按 256B 对齐;再退候选 {128,64,32,16}
+

3.4 CalL1Tiling(K 方向 L1 分片)

+
isKInner = !ATrans || BTrans                  // K 是否内轴
+maxStepK = min(⌈K/baseK⌉, 8)                 // K 方向 L1 分片数上限 8
+遍历 stepK(1..maxStepK):
+    满足 (aL1+bL1)·DB <= L1 且 K 256B 对齐 且 单次搬移量约束
+stepKa = stepKb = resKL1 / baseK              // K 方向 L1 分片步数(无量纲)
+depthA1 = stepKa·DB;  depthB1 = stepKb·DB     // L1 流水深度(tile 层数)
+singleCoreM = baseM;  singleCoreN = baseN

3.5 CalcTailBasicBlock(尾轮重切)

tailCnt = (mCnt·nCnt > aicNum) ? (mCnt·nCnt % aicNum) : 0
 // 尾轮把 base 块在 M/N 方向重切 mTailCnt×nTailCnt 份,
-// 使尾轮也尽量填满核,且保持搬移效率(128B 对齐约束)
+// 使尾轮也尽量填满核,且保持 128B 搬移对齐 +while ((mTailCnt+1)·nTailCnt·tailCnt <= aicNum ∧ 搬移对齐) mTailCnt++

4. Swizzle 编排(SWAT 窗口 + 蛇形扫描)

-

ASWT 与 StreamK 共用的 swizzle 核心(block_scheduler_aswt.hUpdateMNTileIdxmat_mul_asw_block.hUpdateBasicIndex):

-
mainWindow = min(4, mTileNum)             // 固定窗口 4 行(WINDOW_LEN=4)
-mainRow    = mTileNum / mainWindow - 1
-tailWindow = mTileNum - mainRow · mainWindow
+
+

4.1 ASWT 的 SWAT 蛇形滑动(UpdateMNTileIdx

+
mainWindow = min(4, mCnt)                 // 固定窗口 4 个 base 块(WINDOW_LEN=4)
+mainRow    = mCnt / mainWindow - 1
+tailWindow = mCnt - mainRow·mainWindow
 
-rowIdx = tileIdx / nTileNum / mainWindow
-if (rowIdx < mainRow):
-    mTileIdx = rowIdx·mainWindow + tileIdx % mainWindow      // 窗口内 M 小步滑动
-    nTileIdx = (tileIdx / mainWindow) % nTileNum             // N 方向连续滑动
-else:
-    // 尾窗口特殊处理
-if (rowIdx % 2 != 0):
-    nTileIdx = nTileNum - 1 - nTileIdx                       // 蛇形:奇数行 N 反向
-

SWAT 语义:把 M 轴按窗口(默认 4 个 base 块)分组,窗口内沿 N 连续滑动、M 小步滑动,使相邻核访问的数据在空间上邻近 → 最大化 L2 命中;奇数行 N 反向扫描(蛇形)让相邻轮的首尾块空间相邻,进一步提升 L2 复用。这是官方 matmul_performance.md 中 SWAT(Slide Window Adaptive Template)的落地实现。

-

尾轮重切GetBlockShape):最后一轮把单个 base 块在 M/N 方向再切 mTailCnt×nTailCnt 份分给更多核,blockIdx % tailCnt 决定每核拿哪个子块,消除尾轮算力浪费。

-

StreamK 的 swizzleblock_scheduler_streamk.h):在 SWAT 窗口基础上叠加 DP 主轮(K 不分片)+ SK 尾轮(K 分片) 判定(CheckIsSkScene),主轮每核一个 MN 块算完整 K,尾轮把剩余 MN 块切 K 分多核、由 AIV 在 workspace 上确定性累加。

+rowIdx = tileIdx / nCnt / mainWindow +if (rowIdx < mainRow): // 主窗口区 + mTileIdx = rowIdx·mainWindow + tileIdx % mainWindow // 窗口内 M 小步滑动 + nTileIdx = (tileIdx / mainWindow) % nCnt // N 方向连续滑动 +else: // 尾窗口区(M 剩余不足一窗) + mTileIdx = mainRow·mainWindow + tailIndex % tailWindow + nTileIdx = (tailIndex / tailWindow) % nCnt +if (rowIdx % 2 != 0): // 蛇形:奇数行 N 反向扫描 + nTileIdx = nCnt - 1 - nTileIdx
+

物理含义(结合硬件):把 M 轴按窗口(4 个 base 块)分组,窗口内沿 N 连续滑动、M 小步滑动,使相邻核访问的数据在 GM 地址上空间邻近 → 最大化 L2 命中(重复读走 5.2TB/s 的 L2 而非 1.6TB/s 的 GM)。奇数行 N 反向(蛇形)让相邻两轮的首尾块空间相邻,进一步复用 L2。示意图:

+
M方向 base 块(窗口=4)
+┌──────────────────────────────────────────┐
+│ 窗口0: 核0→N0, 核1→N1, 核2→N2, 核3→N3  (N 连续)      │
+│ 窗口1: 核4→N3, 核5→N2, 核6→N1, 核7→N0  (蛇形反向)      │
+│ ...                                       │
+└──────────────────────────────────────────┘
+   (每行窗口内 N 方向连续滑动 → 相邻核读相邻 A 块 → L2 命中)
+

4.2 尾轮重切(GetBlockShape

+

最后一轮把单个 base 块在 M/N 方向再切 mTailCnt × nTailCnt 份分给更多核,blockIdx % tailCnt 决定每核拿哪个子块,消除尾轮"核数远大于剩余块数"的算力浪费(配合 §3.5)。

+

4.3 StreamK 的 DP/SK 编排(block_scheduler_streamk.h

+

在 SWAT 蛇形基础上叠加 DP 主轮 + SK 尾轮 判定:

+
tileNum = (mCnt·nCnt - tailMNTileNum)  +  tailMNTileNum·skKTileNum·batch
+          └──────── DP 部分(每核一个MN块) ┘  └───── SK 尾轮(每MN块切K) ─────┘
+CheckIsSkScene(tileIdx) = (⌈(tileIdx+1)/usedCoreNum⌉ == ⌈tileNum/usedCoreNum⌉)
+// DP 轮:kTileNum=1(K 不分片);SK 轮:kTileNum=skKTileNum(K 分片)
+

DP 主轮每核一个 MN 块算完整 K(数据并行),SK 尾轮把剩余 MN 块切 K 分给空闲核(提前执行,AIV 累加与 AIC 下一轮重叠)。


5. 各分支优缺点对比

- - - - + + + +
分支适用场景优点缺点 / 局限
K_EQUAL_ZEROK==0 且无 bias极简,AIV 清零不浪费 Cube仅空矩阵乘
TO_MUL高精度 FP32 且 M==1 或 N==1避开 Cube 分形浪费,AIV 向量乘仅 FP32 高精度模式
TO_MULTI_MUL高精度 FP32 且 !ATrans∧BTrans 且 M/N 任意同上 + 转置组合下的内积连续更窄(限转置组合、无 bias)
BASIC_STREAM_KM/N 小、K 大(K≥8192)切 K 用满核;DPSK 尾轮与计算重叠workspace 额外带宽;累加顺序不确定;仅 A 为 ND;DPSK 要求 256 对齐
BASIC_ASWT通用主分支SWAT 提 L2 命中;A/B 全载减重复读;fixpipe 并行搬出;尾轮均衡baseM/N 启发式搜索非严格最优;全载/fixpipe 场景窄
TO_MUL高精度 FP32 且 M==1/N==1避开 Cube 分形浪费,AIV 向量乘仅 FP32 高精度
TO_MULTI_MUL高精度 FP32 且 !ATrans∧BTrans同上 + 内积方向连续更窄(限转置、无 bias)
BASIC_STREAM_KM/N 小、K 大(≥8192)切 K 满核;DPSK 尾轮与计算重叠workspace 额外带宽;累加顺序不确定;仅 A 为 ND;DPSK 要求 256 对齐
BASIC_ASWT通用主分支SWAT 提 L2 命中;A/B 全载减重复读;fixpipe 并行搬出;尾轮均衡baseM/N 启发式非最优;全载/fixpipe 场景窄;GM 带宽不分读写
BASE(ASW)最终兜底保证正确性老接口,无全载/fixpipe/StreamK 优化

6. 初步观察到的可改进点(衔接任务 3.2)

-

在通读源码过程中,已浮现若干值得深挖的改进线索,留待后续对照性能模型严格论证:

+

在通读源码过程中浮现的改进线索,留待后续用性能模型严格论证:

    -
  1. baseM/baseN 搜索目标是启发式的GetRebalanceBlockcubeBoundParam/balanceRate 复合指标剪枝,而非直接代入 §3.2 的 T_total = max(T_MMAD, T_MTE2, T_MTE1, T_FIXPIPE) 精确评估。理论上可用性能模型对候选解做精确打分。
  2. +
  3. baseM/baseN 搜索是启发式的GetRebalanceBlockcubeBoundParam/balanceRate 复合指标剪枝,而非直接代入 T_total = max(T_MMAD, T_MTE2, T_MTE1, T_FIXPIPE) 精确评估。理论上可用性能模型对候选解精确打分。
  4. SWAT 窗口固定为 4WINDOW_LEN=4):未根据 L2 容量、shape、核数自适应调窗。窗口大小直接影响 L2 命中率与重复读量的权衡。
  5. -
  6. A/B 全载只有"整个矩阵常驻"一种粒度:没有"部分驻留"(多个 base 块驻留 L1 的中间态),在 A/B 稍大于 3/4 L1 时直接放弃全载,存在优化断档。
  7. -
  8. fixpipe 优化覆盖窄:仅 K≤256 ∧ M≥256 ∧ N 不对齐 场景触发,其它 Fixpipe Bound 场景(如更小 K)未覆盖。
  9. +
  10. A/B 全载只有"整个矩阵常驻"一种粒度:没有"部分驻留"(多个 base 块驻留 L1 的中间态),A/B 稍大于 3/4 L1 时直接放弃,存在优化断档。
  11. +
  12. fixpipe 优化覆盖窄:仅 K≤256 ∧ M≥256 ∧ N 不对齐 触发,其它 Fixpipe Bound 场景未覆盖。
  13. GM 带宽未区分读写GetHbmBW 统一按 32核·31B/拍 换算,未区分读/写共享 1.6TB/s 的竞争,可能高估有效带宽。
  14. -
  15. FP32 高精度(isForceGrpAccForFp32)的退化分支覆盖不全:M==1/N==1 的 FP16/BF16 场景无对应 AIV 退化分支,仍走 Cube。
  16. +
  17. M==1/N==1 的 FP16/BF16 无退化分支:TO_MUL/TO_MULTI_MUL 仅覆盖 FP32 高精度,FP16/BF16 的退化场景仍走 Cube(1/16 利用率)。

附录:关键源码文件索引

@@ -257,6 +394,7 @@ if (rowIdx % 2 != 0): Hostop_host/op_tiling/arch35/matmul_tiling_registry.h策略注册与 DoTilingImpl 调度 Hostop_host/op_tiling/arch35/matmul_v3_tiling_advanced.cpp主入口 + 各 Phase Hostop_host/op_tiling/arch35/matmul_v3_tiling_helper.cppResetBase/GetRebalanceBlock/CalL1Tiling/GetL0C2Out +Hostop_host/op_tiling/arch35/matmul_v3_common_advanced.h常量与数据结构定义 Hostop_host/op_tiling/arch35/matmul_v3_basic_streamk_tiling.cppStreamK/DPSK 条件与 tiling Hostop_host/op_tiling/arch35/matmul_v3_basic_aswt_tiling.cppASWT 子分支(全载/fixpipe) Hostop_host/op_tiling/arch35/matmul_v3_{k_equal_zero,to_mul,to_multi_mul,asw}_tiling.cpp其余分支