已合并
矩阵乘模板总结文档 #383
sunhao_hw创建于 2025年12月3日
矩阵乘模板总结文档 #383
已合并
共 3 个文件变更+545-1
| @@ -3,5 +3,6 @@ | |||
| 3 | 本文档按照由浅入深的次序,组织CATLASS模板库中的进阶材料,读者可按照个人兴趣查阅具体内容。 | 3 | 本文档按照由浅入深的次序,组织CATLASS模板库中的进阶材料,读者可按照个人兴趣查阅具体内容。 |
| 4 | 4 | ||
| 5 | - [catlass_optimize_guidance](./contents/advanced/catlass_optimize_guidance.md) - 介绍模板库下的基础调优方式,包括如何通过Tiling调参、应用不同的Dispatch策略的方式,快速获得性能提升。 | 5 | - [catlass_optimize_guidance](./contents/advanced/catlass_optimize_guidance.md) - 介绍模板库下的基础调优方式,包括如何通过Tiling调参、应用不同的Dispatch策略的方式,快速获得性能提升。 |
| 6 | +- [matmul_template_summary](./contents/advanced/matmul_template_summary.md) - 对模板库的`examples`目录内已有的`matmul`模板设计进行介绍,包含样例模板清单、理论模板清单、工程优化清单、模板应用浅述,可用于matmul性能调优时参考。 | ||
| 6 | - [swizzle_explanation](./contents/advanced/swizzle_explanation.md) - 对模板库中`Swizzle`策略的基本介绍,这影响了AI Core上计算基本块间的顺序。 | 7 | - [swizzle_explanation](./contents/advanced/swizzle_explanation.md) - 对模板库中`Swizzle`策略的基本介绍,这影响了AI Core上计算基本块间的顺序。 |
| 7 | - [dispatch_policies](./contents/advanced/dispatch_policies.md) - 对模板库在`Block`层面上`BlockMmad`中的一个重要模板参数`DispatchPolicy`的介绍。 | 8 | - [dispatch_policies](./contents/advanced/dispatch_policies.md) - 对模板库在`Block`层面上`BlockMmad`中的一个重要模板参数`DispatchPolicy`的介绍。 |
| @@ -77,7 +77,7 @@ L0C实际占用 = L0::M * L0::N * 4(Byte) | |||
| 77 | 77 | ||
| 78 | ### 样例覆盖和选择 | 78 | ### 样例覆盖和选择 |
| 79 | 79 | ||
| 80 | -当前库上基础Matmul算子有: | 80 | +当前库上基础Matmul算子如下,更详细介绍请见[矩阵乘模板清单](./matmul_template_summary.md): |
| 81 | 81 | ||
| 82 | - [00_basic_matmul](../examples/00_basic_matmul/basic_matmul.cpp),采用`MmadAtlasA2Pingpong`的dispatchPolicy,使能pingpong策略 | 82 | - [00_basic_matmul](../examples/00_basic_matmul/basic_matmul.cpp),采用`MmadAtlasA2Pingpong`的dispatchPolicy,使能pingpong策略 |
| 83 | 83 | ||
| @@ -0,0 +1,543 @@ | |||
| 1 | +# 矩阵乘模板总结 | ||
| 2 | + | ||
| 3 | +当前库上`examples`内包含多种矩阵乘的`样例模板`,其来源是不同的matmul`理论模板`与工程实践中发现的`工程优化`点的组合。在充分理解了各个`理论模板`和`工程优化`后,开发者可以基于问题场景选择适合的`样例模板`、甚至进一步自行组合出库上没有的新的`样例模板`,来达到矩阵乘的性能极致优化。 | ||
| 4 | + | ||
| 5 | +注意,本文档仅总结矩阵乘方案相关的样例,其他涉及量化、groupMatmul、后处理等的矩阵乘不在此处总结。 | ||
| 6 | + | ||
| 7 | +## 样例模板清单 | ||
| 8 | +<details> | ||
| 9 | +<summary><strong><font size="4">00_basic_matmul</font></strong></summary> | ||
| 10 | + | ||
| 11 | +- 理论模板:`Common模板` | ||
| 12 | +- 工程优化:`流水优化(Multi Buffer)` | ||
| 13 | +- 关键交付件 | ||
| 14 | + - host:[00_basic_matmul](../../../examples/00_basic_matmul/basic_matmul.cpp) | ||
| 15 | + - kernel:[basic_matmul.hpp](../../../include/catlass/gemm/kernel/basic_matmul.hpp) | ||
| 16 | + - blockMmad:[block_mmad_pingpong.hpp](../../../include/catlass/gemm/block/block_mmad_pingpong.hpp) | ||
| 17 | +- dispatchPolicy:`MmadAtlasA2Pingpong` | ||
建议附带相关的链接,下同 ![]() ![]() | |||
| 18 | +</details> | ||
| 19 | + | ||
| 20 | +<details> | ||
| 21 | +<summary><strong><font size="4">04_padding_matmul</font></strong></summary> | ||
| 22 | + | ||
| 23 | +- 理论模板:`Common模板` | ||
| 24 | +- 工程优化: | ||
| 25 | + - `流水优化(Multi Buffer)` | ||
| 26 | + - `读取带宽优化(padding)- PaddingMatrixND` | ||
| 27 | +- 关键交付件 | ||
| 28 | + - host:[04_padding_matmul](../../../examples/04_padding_matmul/padding_matmul.cpp) | ||
| 29 | + - kernel:[padding_matmul.hpp](../../../include/catlass/gemm/kernel/padding_matmul.hpp) | ||
| 30 | + - blockMmad:[block_mmad_pingpong.hpp](../../../include/catlass/gemm/block/block_mmad_pingpong.hpp) | ||
| 31 | +- dispatchPolicy:`MmadAtlasA2Pingpong` | ||
| 32 | +</details> | ||
| 33 | + | ||
| 34 | +<details> | ||
| 35 | +<summary><strong><font size="4">06_optimized_matmul</font></strong></summary> | ||
| 36 | + | ||
| 37 | +- 理论模板:`Common模板` | ||
| 38 | +- 工程优化: | ||
| 39 | + - `流水优化(Multi Buffer)` | ||
| 40 | + - `流水优化(Preload)` | ||
| 41 | + - `读取带宽优化(Padding)- PaddingMatrixNZ` | ||
| 42 | + - `读取带宽优化(ShuffleK)` | ||
| 43 | + - `读取带宽优化(小M下指令替换)`(需要修改样例使能) | ||
| 44 | +- 关键交付件 | ||
| 45 | + - host:[06_optimized_matmul](../../../examples/06_optimized_matmul/optimized_matmul.cpp) | ||
| 46 | + - kernel:[optimized_matmul.hpp](../../../include/catlass/gemm/kernel/optimized_matmul.hpp) | ||
| 47 | + - Padding前处理组件:[padding_matmul.hpp](../../../include/catlass/gemm/kernel/padding_matmul.hpp) | ||
| 48 | + - blockMmad:[block_mmad_preload.hpp](../../../include/catlass/gemm/block/block_mmad_preload.hpp) | ||
| 49 | +- dispatchPolicy:`MmadAtlasA2Preload` | ||
| 50 | +- ⚠️ 注意:即使没有使用`PaddingMatrixNZ`前处理,依然会产生MIX算子编译和CV1:0启动的开销(比仅AIC启动的开销大) | ||
| 51 | +</details> | ||
| 52 | + | ||
| 53 | +<details> | ||
| 54 | +<summary><strong><font size="4">09_splitk_matmul</font></strong></summary> | ||
| 55 | + | ||
| 56 | +- 理论模板:`多核切K模板 MultiCoreSplitK` | ||
| 57 | +- 工程优化:`流水优化(Multi Buffer)` | ||
| 58 | +- 关键交付件 | ||
| 59 | + - host:[09_splitk_matmul](../../../examples/09_splitk_matmul/optimized_matmul.cpp) | ||
| 60 | + - kernel:[splitk_matmul.hpp](../../../include/catlass/gemm/kernel/splitk_matmul.hpp) | ||
| 61 | + - blockMmad:[block_mmad_pingpong.hpp](../../../include/catlass/gemm/block/block_mmad_pingpong.hpp) | ||
| 62 | +- dispatchPolicy:`MmadAtlasA2Pingpong` | ||
| 63 | +</details> | ||
| 64 | + | ||
| 65 | +<details> | ||
| 66 | +<summary><strong><font size="4">21_basic_matmul_preload_zN</font></strong></summary> | ||
| 67 | + | ||
| 68 | +(此样例主要承载NZ排布输入的适配方法,也可换成ND排布输入,无MIX算子编译启动的开销) | ||
可以和06_optimized_matmul保持一致,放在注意里面 ![]() ![]() | |||
| 69 | +- 理论模板:`Common模板` | ||
| 70 | +- 工程优化: | ||
| 71 | + - `流水优化(Multi Buffer)` | ||
| 72 | + - `流水优化(Preload)` | ||
| 73 | + - `读取带宽优化(ShuffleK)` | ||
| 74 | +- 关键交付件 | ||
| 75 | + - host:[21_basic_matmul_preload_zN](../../../examples/09_splitk_matmul/basic_matmul_preload_zN.cpp) | ||
| 76 | + - kernel:[basic_matmul_preload.hpp](../../../include/catlass/gemm/kernel/basic_matmul_preload.hpp) | ||
| 77 | + - blockMmad:[block_mmad_preload.hpp](../../../include/catlass/gemm/block/block_mmad_preload.hpp) | ||
| 78 | +- dispatchPolicy:`MmadAtlasA2Preload` | ||
| 79 | +</details> | ||
| 80 | + | ||
| 81 | +<details> | ||
| 82 | +<summary><strong><font size="4">22_padding_splitk_matmul</font></strong></summary> | ||
| 83 | + | ||
| 84 | +- 理论模板:`多核切K模板 MultiCoreSplitK` | ||
| 85 | +- 工程优化: | ||
| 86 | + - `流水优化(Multi Buffer)` | ||
| 87 | + - `读取带宽优化(padding)- PaddingMatrixND` | ||
| 88 | +- 关键交付件 | ||
| 89 | + - host:[22_padding_splitk_matmul](../../../examples/22_padding_splitk_matmul/padding_splitk_matmul.cpp) | ||
| 90 | + - kernel:[padding_splitk_matmul.hpp](../../../include/catlass/gemm/kernel/padding_splitk_matmul.hpp) | ||
| 91 | + - Padding前处理组件:[padding_matmul.hpp](../../../include/catlass/gemm/kernel/padding_matmul.hpp) | ||
| 92 | + - SplitkReduceAdd后处理组件:[splitk_matmul.hpp](../../../include/catlass/gemm/kernel/splitk_matmul.hpp) | ||
| 93 | + - blockMmad:[block_mmad_pingpong.hpp](../../../include/catlass/gemm/block/block_mmad_pingpong.hpp) | ||
| 94 | +- dispatchPolicy:`MmadAtlasA2Pingpong` | ||
前面几个的BlockScheduler也可以考虑补充上(虽然是通用的zn),后面好像单独补充了特殊的几个 ![]() ![]() | |||
| 95 | +</details> | ||
| 96 | + | ||
| 97 | +<details> | ||
| 98 | +<summary><strong><font size="4">25_matmul_full_loadA</font></strong></summary> | ||
| 99 | + | ||
| 100 | +(此样例及相关组件仅适配了A矩阵全载实现,需要实现B矩阵全载可参考关键交付件自行开发) | ||
同21,可以和06_optimized_matmul保持一致,放在注意里面 ![]() ![]() | |||
| 101 | +- 理论模板:`Common模板` | ||
| 102 | +- 工程优化: | ||
| 103 | + - `流水优化(Multi Buffer)`(全载的A矩阵在L1上不使用多buffer) | ||
| 104 | + - `读取带宽优化(L1常驻)` | ||
| 105 | +- 关键交付件 | ||
| 106 | + - host:[25_matmul_full_loadA](../../../examples/09_splitk_matmul/25_matmul_full_loadA.cpp) | ||
| 107 | + - kernel:[matmul_full_loadA.hpp](../../../include/catlass/gemm/kernel/matmul_full_loadA.hpp) | ||
| 108 | + - blockMmad:[block_mmad_pingpong_full_loadA.hpp](../../../include/catlass/gemm/block/block_mmad_pingpong_full_loadA.hpp) | ||
| 109 | +- dispatchPolicy:`MmadAtlasA2FullLoadA` | ||
| 110 | +- BlockScheduler:`GemmIdentityBlockSwizzleL1FullLoad` | ||
| 111 | +</details> | ||
| 112 | + | ||
| 113 | +<details> | ||
| 114 | +<summary><strong><font size="4">31_small_matmul</font></strong></summary> | ||
| 115 | + | ||
| 116 | +- 理论模板:`Common模板` | ||
| 117 | +- 工程优化: | ||
| 118 | + - `流水优化(Multi Buffer)` | ||
| 119 | + - `Scalar开销消减` | ||
| 120 | +- 关键交付件 | ||
| 121 | + - host:[31_small_matmul](../../../examples/31_small_matmul/small_matmul.cpp) | ||
| 122 | + - kernel:[small_matmul.hpp](../../../include/catlass/gemm/kernel/small_matmul.hpp) | ||
| 123 | + - blockMmad:[block_mmad_small.hpp](../../../include/catlass/gemm/block/block_mmad_small.hpp) | ||
| 124 | +- dispatchPolicy:`MmadAtlasA2Small` | ||
| 125 | +- BlockScheduler:kernel内实际不使用 | ||
| 126 | +</details> | ||
| 127 | + | ||
| 128 | +<details> | ||
| 129 | +<summary><strong><font size="4">34_single_core_splitk_matmul</font></strong></summary> | ||
| 130 | + | ||
H 这里可以补充streamK和aivmatmul的相应实现样例,以及对应的说明 ![]() ![]() | |||
| 131 | +- 理论模板:`单核切K模板 SingleCoreSplitK` | ||
| 132 | +- 工程优化: | ||
| 133 | + - `流水优化(Multi Buffer)` | ||
| 134 | + - `读取带宽优化(Padding)- PaddingMatrixNZ` | ||
| 135 | + - `写出带宽优化` | ||
| 136 | +- 关键交付件 | ||
| 137 | + - host:[34_single_core_splitk_matmul](../../../examples/34_single_core_splitk_matmul/single_core_splitk.cpp) | ||
| 138 | + - kernel:[single_core_slicek_matmul.hpp](../../../include/catlass/gemm/kernel/single_core_slicek_matmul.hpp) | ||
| 139 | + - Padding前处理组件和RemovePaddingNDAndCast后处理组件:[padding_matmul.hpp](../../../include/catlass/gemm/kernel/padding_matmul.hpp) | ||
| 140 | + - blockMmad:[block_mmad_single_core_splitk.hpp](../../../include/catlass/gemm/block/block_mmad_single_core_splitk.hpp) | ||
| 141 | +- dispatchPolicy:`MmadAtlasA2SingleCoreSplitk` | ||
| 142 | +- BlockScheduler:`SingleCoreSplitkGemmIdentityBlockSwizzle` | ||
| 143 | +</details> | ||
| 144 | + | ||
| 145 | +## 理论模板清单 | ||
建议调换理论模板清单和样例模板清单的位置,可读性更好;否则阅读样例模板清单时候出现了理论模板清单的相关内容,不符合一般阅读顺序 ![]() ![]() | |||
| 146 | + | ||
| 147 | +<details> | ||
| 148 | +<summary><strong><font size="4">Common模板</font></strong></summary> | ||
| 149 | + | ||
| 150 | +### Tiling建模 | ||
| 151 | + | ||
| 152 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/b1cb21ac-af83-4736-8582-4ed7392d766b/1common.png" width="80%"> | ||
| 153 | + | ||
tiling过程从完整MKN到核内L1上m1,少了分核过程? ![]() ![]() | |||
| 154 | +如图展示一个常规的fp16的矩阵运算(L0C上按照fp32累加),定义相关参数: | ||
| 155 | +- 问题shape:$M$,$N$,$K$ | ||
| 156 | +- 搬入L1Cache时的TileShape:$m_1$,$n_1$,$k_1$ | ||
| 157 | +- 搬入L0A/LOB、搬出L0C时的TileShape:$m_0$,$n_0$,$k_0$ | ||
| 158 | + | ||
| 159 | +采用 $M$、$N$ 方向分核,按照$m_1$、$n_1$切分,产生$\frac{MN}{m_1n_1}$个基本任务块、分配给AIC核完成搬运和计算,每个基本任务块需要搬运$m_1K+Kn_1$的数据、计算得到$m_1n_1$的结果并搬出。由此产生约束: | ||
| 160 | +- $m_1k_1*L1Stage_A + n_1k_1*L1Stage_B <= L1Size / 2Byte$ | ||
| 161 | +- $m_0k_0*L0AStage <= L0ASize / 2Byte$ | ||
| 162 | +- $n_0k_0*L0BStage <= L0BSize / 2Byte$ | ||
| 163 | +- $m_0n_0*L0CStage <= L0CSize / 4Byte$ | ||
| 164 | +- $m_0 = m_1$ | ||
| 165 | +- $n_0 = n_1$ | ||
| 166 | + | ||
| 167 | +### 读取数据量 | ||
| 168 | +每个基本任务块需要搬运$m_1K+Kn_1$的数据,总读取量为: | ||
| 169 | + | ||
| 170 | +$2Byte * [m_1K+Kn_1] * \frac{MN}{m_1n_1} = 2Byte * MNK * [\frac{1}{m_1}+\frac{1}{n_1}]$ | ||
| 171 | + | ||
| 172 | +### 写出数据量 | ||
| 173 | +每个基本任务块计算得到$m_1n_1$的结果并搬出,总写出量为: | ||
| 174 | + | ||
| 175 | +$2Byte * MN$ | ||
| 176 | + | ||
| 177 | +### 计算量 | ||
| 178 | +输出矩阵C的每个数据点需要$K$次乘加,总计算量固定为: | ||
| 179 | + | ||
| 180 | +$2MNK$ | ||
| 181 | + | ||
| 182 | +计算耗时多数情况下为刚性时间,仅与参与计算的AIC核数相关,在各理论模板中都一样,后续不再赘述。 | ||
| 183 | +</details> | ||
| 184 | + | ||
| 185 | +<details> | ||
| 186 | +<summary><strong><font size="4">多核切K模板 MultiCoreSplitK</font></strong></summary> | ||
| 187 | + | ||
| 188 | +### Tiling建模 | ||
| 189 | + | ||
| 190 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/d4b0e2d2-4333-4df4-9af2-44654cc37e54/2multiCoreSplitK.png" width="80%"> | ||
| 191 | + | ||
| 192 | +如图展示一个常规的fp16的矩阵运算(L0C上按照fp32累加),$MN$方向共切分12个基本任务块,假设有24个AIC物理核,此时负载不均衡,故引入$K$轴切分成2个$k$、产生24个基本任务块,在AIC上负载均衡。定义相关参数: | ||
| 193 | +- 问题shape:$M$,$N$,$K$ | ||
| 194 | +- 搬入L1Cache时的TileShape:$m_1$,$n_1$,$k_1$ | ||
| 195 | +- 搬入L0A/LOB、搬出L0C时的TileShape:$m_0$,$n_0$,$k_0$ | ||
| 196 | +- <font color="red">相较Common模板</font>,新增$K$方向切分长度$k$ | ||
| 197 | + | ||
| 198 | +相比`Common模板`,为了减少读取数据量,在较大的$m_1$、$n_1$下,可能存在负载均衡问题,即$MN$方向切分的任务块远少于AIC核数,导致读取带宽不高(核数不够),所以加入$K$方向分核。采用 $M$、$N$、$K$ 方向分核,产生$\frac{MNK}{m_1n_1k}$个基本任务块、分配给AIC核完成搬运和计算,每个基本任务块需要搬运$m_1k+kn_1$的数据、计算得到$m_1n_1$的结果并搬出。硬件上约束与Common相同。 | ||
| 199 | + | ||
| 200 | +### 读取数据量 | ||
| 201 | +每个基本任务块需要搬运$m_1K+Kn_1$的数据,总读取量与`Common模板`一致: | ||
| 202 | + | ||
| 203 | +$2Byte * [m_1k+kn_1] * \frac{MNK}{m_1n_1k} = 2Byte * MNK * [\frac{1}{m_1}+\frac{1}{n_1}]$ | ||
| 204 | + | ||
| 205 | +### 写出数据量 | ||
| 206 | +每个基本任务块计算得到$m_1n_1$的结果并搬出,需要$\frac{K}{k}$个基本块累加来得到输出矩阵C的$m_1n_1$块的最终输出,总写出量为: | ||
| 207 | + | ||
| 208 | +$2Byte * MNK / k$ | ||
| 209 | + | ||
| 210 | +### 定性分析 | ||
| 211 | + | ||
| 212 | +相较`Common模板`,搬入数据量不变,写出数据量增加,并产生后处理ReduceAdd的开销(包含MIX算子编译启动的开销),但切分基本块更多、更易负载均衡。 | ||
| 213 | + | ||
| 214 | +</details> | ||
| 215 | + | ||
| 216 | +<details> | ||
| 217 | +<summary><strong><font size="4">单核切K模板 SingleCoreSplitK</font></strong></summary> | ||
| 218 | + | ||
| 219 | +### Tiling建模 | ||
| 220 | + | ||
| 221 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/e16f5a39-2f7b-4a72-9d79-502cc8682e75/3singleCoreSplitK.png" width="80%"> | ||
| 222 | + | ||
| 223 | +如图展示一个常规的fp16的矩阵运算(L0C上按照fp32累加),定义相关参数: | ||
| 224 | +- 问题shape:$M$,$N$,$K$ | ||
| 225 | +- 搬入L1Cache时的TileShape:$m_1$,$n_1$,$k_1$ | ||
| 226 | +- 搬入L0A/LOB、搬出L0C时的TileShape:$m_0$,$n_0$,$k_0$ | ||
| 227 | + | ||
| 228 | +相比`Common模板`,为了减少读取数据量,进一步增大抽象上的$m_1$、$n_1$,考虑将$m_1k_1$的tile块直接与对应的所有$k_1n_1$的tile块完成计算(等同于将$n_1$放大到$N$),此时输出$m_0n_0$的tile块没法在$L0C$常驻累加,需要及时搬出,通过`atomicAdd`在`GM`上累加。硬件上约束如下: | ||
| 229 | +- $m_1k_1*L1Stage_A + n_1k_1*L1Stage_B <= L1Size / 2Byte$ | ||
| 230 | +- $m_0k_0*L0AStage <= L0ASize / 2Byte$ | ||
| 231 | +- $n_0k_0*L0BStage <= L0BSize / 2Byte$ | ||
| 232 | +- $m_0n_0*L0CStage <= L0CSize / 4Byte$ | ||
| 233 | +- $m_0 <= m_1$ | ||
| 234 | +- $n_0 <= n_1$ | ||
| 235 | + | ||
| 236 | +### 读取数据量 | ||
| 237 | +在`Common模板`的读取数据量公式上,将$n_1$放大到$N$;或者从A矩阵分基本任务块来理解,切分$\frac{MK}{m_1k_1}$个基本块,每个基本块完成搬入此块A矩阵tile块以及对应全部的B矩阵tile块、即搬入$m_1k_1+k_1N$的数据: | ||
| 238 | + | ||
| 239 | +$2Byte * [m_1k_1+k_1N] * \frac{MK}{m_1k_1} = 2Byte * MNK * [\frac{1}{m_1}+\frac{1}{N}]$ | ||
| 240 | + | ||
| 241 | +### 写出数据量 | ||
| 242 | +切分A矩阵分基本任务块,共$\frac{MK}{m_1k_1}$个基本块,每个基本任务块计算得到$m_1N$的结果并搬出,总写出量为: | ||
| 243 | + | ||
| 244 | +$2Byte * MNK / k_1$ | ||
| 245 | + | ||
| 246 | +### 定性分析 | ||
| 247 | + | ||
| 248 | +相较`Common模板`,搬入数据量减少,写出数据量增加,与AIV无关。 | ||
| 249 | + | ||
| 250 | +</details> | ||
| 251 | + | ||
| 252 | +## 工程优化清单 | ||
| 253 | + | ||
| 254 | +<details> | ||
| 255 | +<summary><strong><font size="4">流水优化(Multi Buffer)</font></strong></summary> | ||
| 256 | + | ||
| 257 | +### 现象分析 | ||
| 258 | + | ||
| 259 | +如下图构造一个`Common`模板下的简单场景,对于单个AIC处理一个基本任务块C,需要的A/B矩阵Tile块较小,可以直接全部放入L1,且A/B矩阵从L1搬入L0时需要切4次搬入。 | ||
| 260 | + | ||
| 261 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/a62726da-f3c2-4c37-8a32-711046cfd239/8pingpong0.png" width="80%"> | ||
| 262 | + | ||
| 263 | +各pipe的指令流水图示例如下: | ||
| 264 | + | ||
| 265 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/1dca48b1-2b5d-450c-9f66-18dbc1f7e2d1/8pingpong1.png" width="100%"> | ||
| 266 | + | ||
| 267 | +如果在AIC的L1/L0A/L0B/L0C上,每次载入数据tile块时都尽量塞满所有空间,会导致各PIPE的流水串行,整体效率低下 | ||
| 268 | + | ||
| 269 | +### 优化方案 | ||
| 270 | + | ||
| 271 | +使用常规优化手段Multi Buffer,即在L1/L0A/L0B/L0C上启用多buffer,使得流水尽可能并行,提升效率。如下图在L1/L0A/L0B上采用double buffer: | ||
| 272 | + | ||
| 273 | + | ||
| 274 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/40315511-85cc-44ac-be3f-9efb6b5c0194/8pingpong2.png" width="80%"> | ||
| 275 | + | ||
| 276 | +各pipe的指令流水图示例如下,MTE1上指令的0、1表示pingpong流水: | ||
| 277 | + | ||
| 278 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/5917e1ca-dea0-4e00-8322-ef5ba2f32f46/8pingpong3.png" width="100%"> | ||
| 279 | + | ||
| 280 | +⚠️ 需要注意的是,与`L1常驻`优化结合时,常驻的A/B矩阵的tile块,不启用多buffer。 | ||
| 281 | + | ||
| 282 | +### 特性承载代码 | ||
| 283 | + | ||
| 284 | +由于是常规优化手段,所有blockMmad组件均使能。 | ||
| 285 | + | ||
| 286 | +</details> | ||
| 287 | + | ||
| 288 | +<details> | ||
| 289 | +<summary><strong><font size="4">流水优化(Preload)</font></strong></summary> | ||
| 290 | + | ||
| 291 | +### 现象分析 | ||
| 292 | + | ||
| 293 | +通过仿真流水发现pingpong策略的blockMmad存在问题: | ||
| 294 | +- MTE2流水上,“当前C矩阵基本块计算的最后一个A矩阵(B矩阵)的tile块”和“下一个C矩阵基本块计算的第一个A矩阵(B矩阵)的tile块”之间加载的空泡。 | ||
| 295 | +### 优化方案 | ||
| 296 | + | ||
| 297 | +针对GM->L1过程,读取当前轮次的$m_1k_1$($k_1n_1$)时,计算上一轮读取的数据(假设Preload一轮,PRELOAD_STAGES = 1),步骤伪代码如下: | ||
| 298 | +```cpp | ||
| 299 | +for ... { | ||
| 300 | + # 搬入当前轮次的数据 | ||
| 301 | + copyGM2L1A | ||
| 302 | + copyGM2L1B | ||
| 303 | + preload_count++ | ||
| 304 | + for (preload_count == PRELOAD_STAGES) { | ||
| 305 | + # 计算前PRELOAD_STAGES轮次的数据 | ||
| 306 | + copyL12L0A | ||
| 307 | + copyL12L0B | ||
| 308 | + Mmad | ||
| 309 | + } | ||
| 310 | +} | ||
| 311 | +``` | ||
| 312 | + | ||
| 313 | +如下图构造一个`Common`模板下的简单场景,对于单个AIC处理两个基本任务块C1和C2,需要的A/B矩阵Tile块放入L1需要切2次,且A/B矩阵L1Tile块从L1搬入L0时需要切4次搬入(可以先学习前文`流水优化(Multi Buffer)`来增强理解)。这里给出`MmadAtlasA2Pingpong`和`MmadAtlasA2Preload`、`MmadAtlasA2PreloadAsync`的指令对比: | ||
| 314 | +- `MmadAtlasA2Pingpong`中,调用两次blockMmad分别完成C1和C2的计算 | ||
| 315 | +- `MmadAtlasA2Preload`中,两次blockMmad也是分别完成C1和C2的计算,但A3/B3的GmToL1搬运提前到了第一次blockMmad中执行 | ||
| 316 | +- `MmadAtlasA2PreloadAsync`中,调用两次blockMmad和一次收尾的SynchronizeBlock。A2/B2的L1ToL0搬运、tileMmad以及C1的搬出从第一次blockMmad中推迟到第二次blockMmad中;A4/B4的L1ToL0搬运、tileMmad以及C2的搬出从第二次blockMmad中推迟到SynchronizeBlock中 | ||
| 317 | + | ||
| 318 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/eca1e06a-7c9a-40d6-934b-6843f9229d7c/9preload0.png" width="100%"> | ||
| 319 | + | ||
| 320 | +各pipe的指令流水图示例如下,最终达成了A3、B3块的GmToL1搬运提前,减缓了MTE2上的搬运空泡: | ||
| 321 | + | ||
| 322 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/1edf8fb8-c8e2-4b84-b742-0e6c507efb64/9preload1.png" width="100%"> | ||
| 323 | + | ||
| 324 | +### 特性承载代码 | ||
| 325 | +- [block_mmad_preload.hpp](../../../include/catlass/gemm/block/block_mmad_preload.hpp),对应dispatchPolicy:`MmadAtlasA2Preload`,需要在kernel内手动计算传入下一块预载数据的信息。 | ||
| 326 | +- [block_mmad_preload_async.hpp](../../../include/catlass/gemm/block/block_mmad_preload_async.hpp),对应dispatchPolicy:`MmadAtlasA2PreloadAsync`,通过异步控制,无需手动计算下一块预载数据信息,并支持mmad计算完成后的`Callback`传入。 | ||
| 327 | +- [block_mmad_preload_async_with_callback.hpp](../../../include/catlass/gemm/block/block_mmad_preload_async_with_callback.hpp),对应dispatchPolicy:`MmadAtlasA2PreloadAsyncWithCallback`,通过异步控制,无需手动计算下一块预载数据信息,并支持blockMmad计算前后的`Callback`传入。 | ||
| 328 | +</details> | ||
| 329 | + | ||
| 330 | +<details> | ||
| 331 | +<summary><strong><font size="4">读取带宽优化(Padding)</font></strong></summary> | ||
| 332 | + | ||
| 333 | +### 现象分析 | ||
| 334 | +当数据读取为主流水时,优化读取带宽能带来性能受益,以fp16的A矩阵为例,目前有以下几种低带宽场景: | ||
| 335 | +- **Stride非512B对齐导致的低带宽**。搬运参数srcDValue(详见[昇腾文档:DataCopy-随路转换ND2NZ搬运](https://www.hiascend.com/document/detail/zh/canncommercial/83RC1/API/ascendcopapi/atlasascendc_api_07_00127.html))非512B对齐时,带宽会有明显下降。 | ||
| 336 | +- **搬运指令限制导致的低带宽**。ND2NZ的搬运指令,参数srcDValue是uint16类型,最大值65535。当K>65535时,只能通过取ndNum= 1,在m方向循环调用搬运指令,降低了读取带宽。 | ||
| 337 | +- 相比ND2ND不转换排布,**ND2NZ随路转换有带宽损失**。 | ||
I 针对上述带宽损失情形,是否可以链接昇腾社区的相关文档。如果暂无关联性强的外链,可以在后续文档更新中通过图、表等方式展现不同条件的带宽利用情况。 ![]() ![]() | |||
| 338 | +### 优化方案 | ||
| 339 | +针对上述情况,可以使用AIV对数据格式进行重排(预处理动作),当重排开销低于带宽损失时,会有性能收益。从复杂度和能应对的场景出发,有下列三种不同的重排方式。 | ||
| 340 | +#### PaddingMatrixND | ||
| 341 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/80501346-2ea2-42ba-8cc0-b6f614630606/4paddingND.png" width="100%"> | ||
| 342 | + | ||
| 343 | +将Stride方向按照512B对齐,实现复杂度最低,可以处理Stride非对齐导致的带宽下降。 | ||
| 344 | +#### PaddingMatrixBlockND | ||
| 345 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/9e5e0d37-ef6a-41e0-b54a-1f6d079e1179/4paddingBlockND.png" width="100%"> | ||
| 346 | + | ||
| 347 | +按$m_1*k_1$作为“block”粒度重排,block内行优先、block间行优先,且$k_1$为512B对齐,实现复杂度适中,可以处理Stride非对齐和Stride超过65535导致的带宽下降。 | ||
| 348 | + | ||
| 349 | +#### PaddingMatrixNZ | ||
| 350 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/11728de5-073d-481b-a030-b262f425161f/4paddingNZ.png" width="100%"> | ||
| 351 | + | ||
| 352 | +重排为zN格式,实现复杂度最高,因为和L1上数据排布一致,搬运带宽也最高,可以处理Stride非对齐、Stride超过65535、ND2NZ随路转换导致的带宽下降。 | ||
| 353 | + | ||
| 354 | +<font color="red">实际应用中,不同case适合的padding方式不同,暂无全局最优Padding选择。</font> | ||
| 355 | + | ||
| 356 | +### 特性承载代码 | ||
| 357 | +- [padding_matmul.hpp](../../../include/catlass/gemm/kernel/padding_matmul.hpp)中包含Padding前处理组件。 | ||
| 358 | +- 实际适配可参考[06_optimized_matmul](../../../examples/06_optimized_matmul/optimized_matmul.cpp),通过`PaddingTag`、`PaddingBuilder`组装出A矩阵/B矩阵的Padding前处理。 | ||
| 359 | +</details> | ||
| 360 | + | ||
| 361 | +<details> | ||
| 362 | +<summary><strong><font size="4">读取带宽优化(ShuffleK)</font></strong></summary> | ||
| 363 | + | ||
| 364 | +### 现象分析 | ||
| 365 | +通常,所有AIC核心都从$K$方向的第一个分块开始搬运计算,会存在多个核心同时读取同一片GM上数据的情况,产生数据读取冲突,导致读取带宽降低。 | ||
| 366 | +### 优化方案 | ||
| 367 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/3b79fdb8-1154-46fa-bde8-057950d16b86/5shuffleK.png" width="100%"> | ||
| 368 | + | ||
| 369 | +以`Common模板`为例,如图: | ||
图示建议补充swizzle信息,初学者会对coreid的排布产生误解 ![]() ![]() | |||
| 370 | +- $matC$中的$CoreX$表示该基本块分配给第$X$个AIC进行计算 | ||
| 371 | +- $Aj$表示A矩阵该$m_1$下沿$K$轴切分的第$j$个L1Tile基本块 | ||
| 372 | +- $Bij$表示B矩阵该$n_1$下沿$K$轴切分的第$j$个L1Tile基本块 | ||
| 373 | +- 图中matC基本块分核采用Swizzle<2, 1>,详见[swizzle_explanation](./swizzle_explanation.md) | ||
| 374 | + | ||
| 375 | +如图左原始方案,$Core2$和$Core3$搬运A矩阵时均按照“$A0$->$A1$->$A2$->$A3$”的顺序,产生了数据读取冲突。 | ||
| 376 | + | ||
| 377 | + | ||
| 378 | +如图右$ShuffleK$方案,根据$CoreIdx$来偏移起始起始搬运序号$j$,$Core2$搬运A矩阵时按照“$A2$->$A3$->$A0$->$A1$”的顺序,对应B矩阵按照“$B02$->$B03$->$B00$->$B01$”的顺序;$Core3$搬运A矩阵均按照“$A3$->$A0$->$A1$->$A2$”的顺序,对应B矩阵按照“$B13$->$B10$->$B11$->$B12$”的顺序。从时间上错开,避免同地址访问冲突。 | ||
| 379 | +### 特性承载代码 | ||
| 380 | +- [block_mmad_preload.hpp](../../../include/catlass/gemm/block/block_mmad_preload.hpp) | ||
| 381 | +- [block_mmad_preload_async.hpp](../../../include/catlass/gemm/block/block_mmad_preload_async.hpp) | ||
| 382 | +- [block_mmad_preload_async_with_callback.hpp](../../../include/catlass/gemm/block/block_mmad_preload_async_with_callback.hpp) | ||
| 383 | + | ||
| 384 | +上述BlockMmad内均采用设置起始L1序号为$CoreIdx/kTileCount$的方式来实现错位: | ||
| 385 | +```cpp | ||
| 386 | +kTileCount = CeilDiv<L1TileShape::K>(actualShape.k()); | ||
| 387 | +startTileIdx = AscendC::GetBlockIdx(); | ||
| 388 | +firstTileIdx = startTileIdx % kTileCount; | ||
| 389 | +``` | ||
| 390 | + | ||
| 391 | +</details> | ||
| 392 | + | ||
| 393 | +<details> | ||
| 394 | +<summary><strong><font size="4">读取带宽优化(小M下指令替换)</font></strong></summary> | ||
| 395 | + | ||
| 396 | +### 现象分析 | ||
| 397 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/e3a90904-677a-4973-b3b5-93e93ea072e2/6smallM.png" width="80%"> | ||
| 398 | + | ||
| 399 | +矩阵计算中,当$M$很小时(例如$M$ < 8),采用随路ND2NZ的DataCopy(详见[昇腾文档:DataCopy-随路转换ND2NZ搬运](https://www.hiascend.com/document/detail/zh/canncommercial/83RC1/API/ascendcopapi/atlasascendc_api_07_00127.html))效率不高。 | ||
| 400 | + | ||
| 401 | +### 优化方案 | ||
| 402 | +可以采用普通间隔搬运的DataCopy,for循环每次搬运一行,每一行调用DataCopy多次搬运。 | ||
| 403 | +### 特性承载代码 | ||
| 404 | +- [CopyGmToL1IntervalDataCopy](../../../include/catlass/gemm/tile/copy_gm_to_l1.hpp) | ||
| 405 | +- 实际适配可参考[06_optimized_matmul](../../../examples/06_optimized_matmul/optimized_matmul.cpp),在`struct TileCopyOpt`中手动替换`using CopyGmToL1A = Gemm::Tile::CopyGmToL1IntervalDataCopy<ArchTag, AType>;`,而不是默认的`using CopyGmToL1A = typename Base::CopyGmToL1A;` | ||
| 406 | + | ||
| 407 | +```diff | ||
| 408 | +struct TileCopyOpt : public Catlass::Gemm::Tile::TileCopy<ArchTag, AType, BType, CType, BiasType> { | ||
| 409 | + ... | ||
| 410 | + | ||
| 411 | +- // using CopyGmToL1A = Gemm::Tile::CopyGmToL1IntervalDataCopy<ArchTag, AType>; | ||
| 412 | ++ using CopyGmToL1A = Gemm::Tile::CopyGmToL1IntervalDataCopy<ArchTag, AType>; | ||
| 413 | + | ||
| 414 | +- using CopyGmToL1A = typename Base::CopyGmToL1A; | ||
| 415 | ++ // using CopyGmToL1A = typename Base::CopyGmToL1A; | ||
| 416 | + ... | ||
| 417 | +}; | ||
| 418 | +``` | ||
| 419 | + | ||
| 420 | +</details> | ||
| 421 | + | ||
| 422 | +<details> | ||
| 423 | +<summary><strong><font size="4">读取带宽优化(L1常驻)</font></strong></summary> | ||
| 424 | + | ||
| 425 | +### 优化方案 | ||
| 426 | +实际开发时,可采用tile块常驻L1的方式,减少tile块数据的重复读取,等效提升了读取带宽,该特性需要结合不同理论模板来考率实现方法。 | ||
| 427 | +### 特性承载代码 | ||
| 428 | +- `Common`模板可参考[25_matmul_full_loadA](../../../examples/09_splitk_matmul/25_matmul_full_loadA.cpp)及相关交付件,该样例通过$M$轴上的单核全载或多核全载来在特定场景下优化性能,并配合专门的swizzle策略来提高L1上全载的A矩阵块的复用频率。 | ||
| 429 | + - kernel:[matmul_full_loadA.hpp](../../../include/catlass/gemm/kernel/matmul_full_loadA.hpp) | ||
| 430 | + - blockMmad:[block_mmad_pingpong_full_loadA.hpp](../../../include/catlass/gemm/block/block_mmad_pingpong_full_loadA.hpp) | ||
| 431 | + - dispatchPolicy:`MmadAtlasA2FullLoadA` | ||
| 432 | + - BlockScheduler:`GemmIdentityBlockSwizzleL1FullLoad` | ||
| 433 | +- `单核切K模板`[34_single_core_splitk_matmul](../../../examples/34_single_core_splitk_matmul/single_core_splitk.cpp)在理论设计上就考虑了L1Tile块常驻的优化点。 | ||
H 可以参考或引用单核切k的流水示意图。说明使用单核切k的计算模板之后的数据搬运和计算的流程 ![]() ![]() | |||
| 434 | + - kernel:[single_core_slicek_matmul.hpp](../../../include/catlass/gemm/kernel/single_core_slicek_matmul.hpp) | ||
| 435 | + - blockMmad:[block_mmad_single_core_splitk.hpp](../../../include/catlass/gemm/block/block_mmad_single_core_splitk.hpp) | ||
| 436 | + - dispatchPolicy:`MmadAtlasA2SingleCoreSplitk` | ||
| 437 | + - BlockScheduler:`SingleCoreSplitkGemmIdentityBlockSwizzle` | ||
| 438 | + | ||
| 439 | +</details> | ||
| 440 | + | ||
| 441 | +<details> | ||
| 442 | +<summary><strong><font size="4">Scalar开销消减</font></strong></summary> | ||
| 443 | + | ||
| 444 | +### 现象分析 | ||
| 445 | +对于小Shape场景,如`Common模板`中: | ||
| 446 | +- $M$、$N$方向分核数小于实际物理核数,每个AIC物理核最多仅处理一个基本任务块 | ||
| 447 | +- $k_1$ >= $K$,$K$方向无需切分后从GM搬入L1 | ||
| 448 | + | ||
| 449 | +此时kernel总耗时较小,scalar开销对性能影响显著。 | ||
| 450 | +### 优化方案 | ||
| 451 | +消减冗余的scalar计算 | ||
| 452 | +- kernel内不使用 BlockScheduler 来将任务块分配给物理核,手动计算每个物理核对应的任务块 | ||
| 453 | +- kernel内消除基本块循环(每个AIC仅处理1个任务块) | ||
| 454 | +- kernel内简化offset相关计算 | ||
| 455 | +- blockMmad内消减L1层面$m$、$n$的循环 | ||
| 456 | +- blockMmad内简化offset相关计算 | ||
| 457 | +### 特性承载代码 | ||
| 458 | +- 参考[31_small_matmul](../../../examples/31_small_matmul/small_matmul.cpp),可以和[00_basic_matmul](../../../examples/00_basic_matmul/basic_matmul.cpp)的相关交付件对比来加深理解 | ||
| 459 | + - kernel:[small_matmul.hpp](../../../include/catlass/gemm/kernel/small_matmul.hpp) | ||
| 460 | + - blockMmad:[block_mmad_small.hpp](../../../include/catlass/gemm/block/block_mmad_small.hpp) | ||
| 461 | + | ||
| 462 | +</details> | ||
| 463 | + | ||
| 464 | +<details> | ||
| 465 | +<summary><strong><font size="4">写出带宽优化</font></strong></summary> | ||
| 466 | + | ||
| 467 | +### 现象分析 | ||
| 468 | +当数据写出为主流水时,优化写出带宽能够带来性能受益。 | ||
| 469 | +- 当写出时dstStride非512B对齐时,带宽有明显下降 | ||
| 470 | +- 搬出时用NZ2ND随路格式转换,会产生带宽损失 | ||
| 471 | +### 优化方案 | ||
| 472 | +针对上述情况,可使用AIV对数据格式进行重排,在重排开销低于带宽损失时,会有性能受益。以下提供四种重排方式。 | ||
| 473 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/89afcf74-a193-431b-aea3-a8de2abcb4f9/7rmPadding1.png" width="80%"> | ||
| 474 | + | ||
| 475 | +(↑)**方式一**:使用局部workSpace,ND写出到GM时512B对齐,再按block块粒度在UB上重排,再写出到GM上。 | ||
| 476 | + | ||
| 477 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/12665171-d86f-4208-8c11-3bef2359cfa1/7rmPadding2.png" width="80%"> | ||
| 478 | + | ||
| 479 | +(↑)**方式二**:使用全量workSpace,ND写出到GM时512B对齐,等全量结果写完后,再启动UB上数据重排,写出到GM上。 | ||
| 480 | + | ||
| 481 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/13bd80b2-d6ab-4520-839c-cf5e700db0d5/7rmPadding3.png" width="80%"> | ||
| 482 | + | ||
| 483 | +(↑)**方式三**:使用局部workSpace,NZ写出到GM时512B对齐,再按block块粒度在UB上重排,ND写出到GM上。 | ||
| 484 | + | ||
| 485 | +<img src="https://raw.gitcode.com/user-images/assets/7801479/204d24e9-5dc8-4318-bfe1-7f958598c514/7rmPadding4.png" width="80%"> | ||
| 486 | + | ||
| 487 | +(↑)**方式四**:使用全量workSpace,NZ写出到GM时512B对齐,等全量结果写完后,再启动UB上数据重排,ND写出到GM上。 | ||
| 488 | + | ||
| 489 | +### 特性承载代码 | ||
| 490 | +- [padding_matmul.hpp](../../../include/catlass/gemm/kernel/padding_matmul.hpp)中实现了包含**方式二**的`RemovePaddingNDAndCast`后处理组件 | ||
| 491 | +- 实际适配可参考[34_single_core_splitk_matmul](../../../examples/34_single_core_splitk_matmul/single_core_splitk.cpp) | ||
| 492 | +</details> | ||
| 493 | + | ||
| 494 | +## 模板应用浅述 | ||
| 495 | + | ||
| 496 | +参考[102_dynamic_optimized_matmul的select_kernel策略](../../../examples/102_dynamic_optimized_matmul/include/select_kernel_b16.h) | ||
| 497 | + | ||
| 498 | + | ||
| 499 | +<details> | ||
| 500 | +<summary><strong><font size="4">模板选择</font></strong></summary> | ||
| 501 | + | ||
| 502 | +先尝试基于[00_basic_matmul](../../../examples/00_basic_matmul/basic_matmul.cpp)进行TileShape调优并获得**性能基线**,可参考[模板库优化指引 | ||
| 503 | +](./catlass_optimize_guidance.md) | ||
| 504 | + | ||
| 505 | + | ||
| 506 | +依次识别是否满足各模板适合场景,并和性能基线作比较: | ||
| 507 | +- [31_small_matmul](../../../examples/31_small_matmul/small_matmul.cpp): | ||
| 508 | + - 计算当前基本任务块 taskBlocks | ||
| 509 | + ```cpp | ||
| 510 | + taskBlocks = CeilDiv(M, m1) * CeilDiv(N, n1); | ||
| 511 | + ``` | ||
| 512 | + - 基本任务块小于AIC数: $taskBlocks < aicCoreNum$ | ||
| 513 | + - $K$轴较小,$K <= k_1$ | ||
| 514 | +- [09_splitk_matmul](../../../examples/09_splitk_matmul/optimized_matmul.cpp)或[22_padding_splitk_matmul](../../../examples/22_padding_splitk_matmul/padding_splitk_matmul.cpp)(带Padding前处理) | ||
| 515 | + - 选择$m_1$、$n_1$、$k_1$ | ||
| 516 | + - 先设置$m_1 = 128$、$n_1 = 256$、$k_1 = 256$ | ||
| 517 | + - 满足下列场景其一,修改$m_1 = 256$、$n_1 = 128$ | ||
| 518 | + - A矩阵和B矩阵均为ColumnMajor | ||
| 519 | + - A矩阵为ColumnMajor,B矩阵为RowMajor,且$M > N$ | ||
| 520 | + - 计算当前基本任务块 taskBlocks | ||
| 521 | + ```cpp | ||
| 522 | + taskBlocks = CeilDiv(M, m1) * CeilDiv(N, n1); | ||
| 523 | + ``` | ||
| 524 | + - 满足下列两种场景: | ||
| 525 | + - 基本任务块小于一半AIC数,且$K$轴够大:$taskBlocks < aicCoreNum / 2, K > 5120$ | ||
| 526 | + - 基本任务块小于3块,且$K$轴不会小:$taskBlocks <= 2, K > 1024$ | ||
| 527 | +- [06_optimized_matmul](../../../examples/06_optimized_matmul/optimized_matmul.cpp)(带Padding前处理)和[21_basic_matmul_preload_zN](../../../examples/09_splitk_matmul/basic_matmul_preload_zN.cpp)(手动改为ND输入) | ||
| 528 | + - 泛化性更强,适用于剩余场景 | ||
| 529 | + - 不需要使用Padding时,为了节约MIX算子编译启动的开销,建议使用[21_basic_matmul_preload_zN](../../../examples/09_splitk_matmul/basic_matmul_preload_zN.cpp)模板 | ||
| 530 | + | ||
| 531 | +⚠️ 全载特性的使用[25_matmul_full_loadA](../../../examples/09_splitk_matmul/25_matmul_full_loadA.cpp) 和 单核切K方案[34_single_core_splitk_matmul](../../../examples/34_single_core_splitk_matmul/single_core_splitk.cpp)的适用场景待完善 | ||
| 532 | + | ||
| 533 | + | ||
| 534 | +</details> | ||
| 535 | + | ||
| 536 | +<details> | ||
| 537 | +<summary><strong><font size="4">Padding选择</font></strong></summary> | ||
| 538 | + | ||
| 539 | +当Stride非512B对齐时可以考虑使用Padding前处理,但需要考虑Padding带来的开销以及MIX算子编译启动的开销(小shape[31_small_matmul](../../../examples/31_small_matmul/small_matmul.cpp)方法不推荐额外适配Padding) | ||
| 540 | + | ||
| 541 | +`PaddingMatrixND`、`PaddingMatrixBlockND`和`PaddingMatrixNZ`各自的适用场景待完善,泛化上`PaddingMatrixNZ`更具有优势。 | ||
| 542 | + | ||
| 543 | +</details> | ||


样例模板清单是否缺少30样例和32样例,是否需要预留位置后续补充,建议简要说明不放在该文档目录下的原因