已合并
BlockScheduler & BlockMmad 重构 #92
BlockScheduler & BlockMmad 重构 #92
已合并
林旭创建于 6月25日
32 个文件变更+1629-1688
@@ -11,7 +11,7 @@
11 11 
12所有 BlockEpilogue 组件基于 [block_epilogue.md](./block/block_epilogue.md) 公共框架实现,包含统一的:12所有 BlockEpilogue 组件基于 [block_epilogue.md](./block/block_epilogue.md) 公共框架实现,包含统一的:
13- 类型别名13- 类型别名
14-- 数据结构(Arguments、Params)14+- 数据结构(Params)
15- 核心方法(Init、Run、operator)15- 核心方法(Init、Run、operator)
16 16 
17详见:[block_epilogue.md](./block/block_epilogue.md)17详见:[block_epilogue.md](./block/block_epilogue.md)
@@ -22,7 +22,7 @@
22BlockEpilogue22BlockEpilogue
23 ├── BlockShape (Block 形状)23 ├── BlockShape (Block 形状)
24 ├── BlockCoord (Block 坐标)24 ├── BlockCoord (Block 坐标)
25- ├── Arguments (参数结构)25+ ├── Params (参数结构)
26 └── 核心方法26 └── 核心方法
27 ├── Init (初始化)27 ├── Init (初始化)
28 ├── Run (执行后处理)28 ├── Run (执行后处理)
@@ -16,21 +16,11 @@ Block 层后处理组件,用于矩阵乘计算后的额外处理。不同实
16 16 
17### 核心数据结构17### 核心数据结构
18 18 
19-#### Arguments
20-```
21-struct Arguments {
22- // 具体成员根据实现不同
23- GM_ADDR cGmAddr; // C 矩阵 GM 地址(可选)
24- GM_ADDR workspaceGmAddr; // Workspace 地址(可选)
25-};
26-```
27-说明:Host 端参数结构体,传递给 Kernel。
28- 
29#### Params19#### Params
30```20```
31struct Params {21struct Params {
32 // 具体成员根据实现不同22 // 具体成员根据实现不同
33- // 通常与 Arguments 相同或包含更多运行时参数23+ // 通常运行时参数
34};24};
35```25```
36说明:Kernel 运行时参数结构体。26说明:Kernel 运行时参数结构体。
@@ -31,14 +31,6 @@ using MatmulKernel = Blaze::Gemm::Kernel::KernelMatmulBasic<
31 31 
32## 特殊数据结构32## 特殊数据结构
33 33 
34-### Arguments
35-```
36-struct Arguments {
37- Arguments() = default;
38-};
39-```
40-说明:空参数结构体,无任何成员。
41- 
42### Params34### Params
43```35```
44struct Params {36struct Params {
@@ -66,7 +58,7 @@ __aicore__ inline void Run()
66 58 
67### operator函数(参数版本)59### operator函数(参数版本)
68```60```
69-__aicore__ inline void operator()(Arguments const& params)61+__aicore__ inline void operator()(Params const& params)
70{62{
71 Run(); // 调用空的 Run()63 Run(); // 调用空的 Run()
72}64}
@@ -141,11 +133,11 @@ BlockEpilogueStreamK ← 实际实现(用于 StreamK Kernel)
141// 自定义 Epilogue 示例(伪代码)133// 自定义 Epilogue 示例(伪代码)
142class BlockEpilogueRelu {134class BlockEpilogueRelu {
143public:135public:
144- struct Arguments {136+ struct Params {
145 float threshold; // ReLU 参数137 float threshold; // ReLU 参数
146 };138 };
147 139 
148- __aicore__ inline void Init(Arguments const& args) {140+ __aicore__ inline void Init(Params const& args) {
149 threshold_ = args.threshold;141 threshold_ = args.threshold;
150 }142 }
151 143 
@@ -153,7 +145,7 @@ public:
153 AscendC::Relu(outputTensor, inputTensor, threshold_);145 AscendC::Relu(outputTensor, inputTensor, threshold_);
154 }146 }
155 147 
156- __aicore__ inline void operator()(Arguments const& args) {148+ __aicore__ inline void operator()(Params const& args) {
157 Init(args);149 Init(args);
158 Run();150 Run();
159 }151 }
@@ -62,19 +62,14 @@ StreamK 矩阵乘后处理 Block,运行在 AIV 核。从 workspace 读取 AIC
62 62 
63## 特殊数据结构63## 特殊数据结构
64 64 
65-### Arguments65+### Params
66```66```
67-struct Arguments {67+struct Params {
68 GM_ADDR cGmAddr{nullptr}; // C 矩阵 GM 地址68 GM_ADDR cGmAddr{nullptr}; // C 矩阵 GM 地址
69 GM_ADDR workspaceGmAddr{nullptr}; // Workspace GM 地址69 GM_ADDR workspaceGmAddr{nullptr}; // Workspace GM 地址
70};70};
71```71```
72 72 
73-### Params
74-```
75-using Params = Arguments;
76-```
77- 
78### AivParams73### AivParams
79```74```
80struct AivParams {75struct AivParams {
@@ -22,7 +22,7 @@
22### BlockMmad 公共框架22### BlockMmad 公共框架
23所有 BlockMmad 组件基于 [block_mmad.md](./block_mmad.md) 公共框架实现,包含统一的:23所有 BlockMmad 组件基于 [block_mmad.md](./block_mmad.md) 公共框架实现,包含统一的:
24- 模板参数24- 模板参数
25-- 数据结构(Arguments、Params)25+- 数据结构(Params)
26- 核心方法(Init、operator)26- 核心方法(Init、operator)
27 27 
28详见:[block_mmad.md](./block_mmad.md)28详见:[block_mmad.md](./block_mmad.md)
@@ -53,13 +53,13 @@ Block 层矩阵乘计算组件,执行单个 block 的矩阵乘计算。基于
53 53 
54### 核心数据结构54### 核心数据结构
55 55 
56-#### Arguments / Params / GmParams56+#### Params
57```57```
58-struct Arguments {58+struct Params {
59- GM_ADDR aGmAddr; // A 矩阵 GM 起始地址59+ GM_ADDR aGmAddr; // A 矩阵 GM 地址
60- GM_ADDR bGmAddr; // B 矩阵 GM 起始地址60+ GM_ADDR bGmAddr; // B 矩阵 GM 地址
61- GM_ADDR cGmAddr; // C 矩阵 GM 起始地址61+ GM_ADDR cGmAddr; // C 矩阵 GM 地址
62- GM_ADDR biasGmAddr; // Bias GM 起始地址(可选)62+ GM_ADDR biasGmAddr; // Bias GM 地址(可选)
63 GM_ADDR workspaceGmAddr; // Workspace 地址(可选,StreamK)63 GM_ADDR workspaceGmAddr; // Workspace 地址(可选,StreamK)
64};64};
65```65```
@@ -90,20 +90,17 @@ __aicore__ inline ~BlockMmad()
90```90```
91__aicore__ inline void Init(91__aicore__ inline void Init(
92 const TupleShape& shape, // 问题规模92 const TupleShape& shape, // 问题规模
93- const TupleShape& tileL1, // L1 切分形状93+ const Params& params) // BlockMmad 参数
94- const TupleShape& tileL0, // L0 切分形状
95- bool isBias, // 是否启用 bias
96- ... 其他参数 )
97```94```
98功能:初始化 BlockMmad 组件,设置问题规模、tile 形状和缓冲策略。95功能:初始化 BlockMmad 组件,设置问题规模、tile 形状和缓冲策略。
99 96 
100### operator函数97### operator函数
101```98```
102__aicore__ inline void operator()(99__aicore__ inline void operator()(
103- TensorC gmC, // C 矩阵输出 Tensor
104 TensorA gmA, // A 矩阵输入 Tensor100 TensorA gmA, // A 矩阵输入 Tensor
105 TensorB gmB, // B 矩阵输入 Tensor101 TensorB gmB, // B 矩阵输入 Tensor
106 TensorBias gmBias, // Bias 输入 Tensor102 TensorBias gmBias, // Bias 输入 Tensor
103+ TensorC gmC, // C 矩阵输出 Tensor
107 TupleShape tileShape, // Tile 形状104 TupleShape tileShape, // Tile 形状
108 ... 其他参数)105 ... 其他参数)
109```106```
@@ -159,15 +156,23 @@ using BlockMmad = Blaze::Gemm::Block::BlockMmad<
159```156```
160BlockMmad blockMmad;157BlockMmad blockMmad;
161TupleShape problemShape{m, n, k, batch};158TupleShape problemShape{m, n, k, batch};
162-TupleShape tileL1{mL1, nL1, kL1, 0, 0, 0};159+BlockMmad::Params params = {
163-TupleShape tileL0{baseM, baseN, baseK, 0, 0, 0};160+ .aGmAddr = aGM,
164-blockMmad.Init(problemShape, tileL1, tileL0, isBias, ...);161+ .bGmAddr = bGM,
162+ .cGmAddr = cGM,
163+ .biasGmAddr = biasGM,
164+ .ml1 = mL1, .nl1 = nL1, .kl1 = kL1,
165+ .ml0 = baseM, .nl0 = baseN, .kl0 = baseK,
166+ .l1Stages = 2,
167+ .l0cStages = 1
168+};
169+blockMmad.Init(problemShape, params);
165```170```
166 171 
167### 执行模板172### 执行模板
168```173```
169-TupleL1L0Shape tileShape{shapeM, shapeN, shapeK, baseM, baseN, baseK};174+TupleL1L0Shape tileShape{shapeM, shapeN, shapeK, batch, baseM, baseN};
170-blockMmad(gmC, gmA, gmB, gmBias, tileShape, ...);175+blockMmad(gmA, gmB, gmBias, gmC, tileShape);
171```176```
172 177 
173## 数据流与流水线178## 数据流与流水线
@@ -2,9 +2,9 @@
2> [代码位置](../../../../include/blaze/gemm/block/block_mmad_matmul_basic.h)2> [代码位置](../../../../include/blaze/gemm/block/block_mmad_matmul_basic.h)
3 3 
4## 功能说明4## 功能说明
5-基础矩阵乘 Block,基于 Tensor API 实现,仅支持 AIC 计算。支持 L1/L0C 可配置缓冲、Bias 加法,适用于 Basic Kernel 场景。5+基础矩阵乘 Block,基于 Tensor API 实现,仅支持 AIC 计算。支持 L1/L0C 可配置缓冲、Bias 加法,适用于 Basic Kernel 场景。
6 6 
7-**继承自**:[Block Mmad 基础框架](./block_mmad.md)7+**继承自**:BlockMmad 基础模板(特化实现)
8 8 
9## 特殊约束9## 特殊约束
10 10 
@@ -22,150 +22,248 @@
22### 输出目标22### 输出目标
23结果直接输出到 GM,不支持 workspace。23结果直接输出到 GM,不支持 workspace。
24 24 
25-### weightNZFormat25+### Layout Trait
26-支持 B 矩阵 NZ 格式,通过 `weightNZFormat` 静态常量标识。26+使用 `IsTrans` `IsWeightNz` traits 判断 Layout:
27+- `IsTrans<LayoutA>::value`:判断 A 矩阵是否转置
28+- `IsTrans<LayoutB>::value`:判断 B 矩阵是否转置
29+- `IsWeightNz<LayoutB>::value`:判断 B 矩阵是否为 NZ 格式
27 30 
28-### HF32 模式31+### L1 缓冲布局
29-HF32 模式由 Kernel 层控制,BlockMmad 层不直接处理。32+```
33+L1 空间布局(2 buffer):
34+AL1Ping|BL1Ping|BiasPing|AL1Pong|BL1Pong|BiasPong
35+ 
36+L1 空间布局(4 buffer):
37+AL1Buf0|BL1Buf0|BiasBuf0|AL1Buf1|BL1Buf1|BiasBuf1|AL1Buf2|BL1Buf2|BiasBuf2|AL1Buf3|BL1Buf3|BiasBuf3
38+```
39+ 
40+### MM Layout Transform
41+构造函数和析构函数中设置 MM Layout Transform:
42+```
43+// 构造函数(ASCEND_IS_NOT_AIV)
44+SetMMLayoutTransform(true); // 适配 Fixpipe 输出
45+ 
46+// 析构函数(ASCEND_IS_NOT_AIV)
47+SetMMLayoutTransform(false); // 关闭
48+```
49+ 
50+## 模板参数
51+ 
52+| 参数 | 类型 | 说明 |
53+|------|------|------|
54+| FULL_LOAD_MODE_ | uint64_t | 全载模式:0=非全载, 1=A全载, 2=B全载 |
55+| FUSED_OP_TYPE_ | uint64_t | 融合操作类型 |
56+| KernelSchedule_ | class | Kernel 调度类型 |
57+| AType_ | class | A 矩阵数据类型 |
58+| LayoutA_ | class | A 矩阵布局类型 |
59+| BType_ | class | B 矩阵数据类型 |
60+| LayoutB_ | class | B 矩阵布局类型 |
61+| CType_ | class | C 矩阵输出类型 |
62+| LayoutC_ | class | C 矩阵布局类型 |
63+| BiasType_ | class | Bias 数据类型 |
64+| LayoutBias_ | class | Bias 布局类型 |
65+ 
66+## 类型别名
67+ 
68+| 类型 | 说明 |
69+|------|------|
70+| AType | A 矩阵数据类型 |
71+| BType | B 矩阵数据类型 |
72+| CType | C 矩阵输出类型 |
73+| BiasType | Bias 数据类型 |
74+| LayoutA | A 矩阵布局类型 |
75+| LayoutB | B 矩阵布局类型 |
76+| LayoutC | C 矩阵布局类型 |
77+| LayoutBias | Bias 布局类型 |
78+| DispatchPolicy | 调度策略类型 |
79+| TupleShape | 问题规模:`Shape<int64_t, int64_t, int64_t, int64_t>` |
80+| TupleL1L0Shape | Tile 形状:`Shape<int64_t, int64_t, int64_t, int64_t, int64_t, int64_t>` |
81+| TileShape | Tile 形状:`Shape<int64_t, int64_t, int64_t>` |
30 82 
31## 特殊静态常量83## 特殊静态常量
32 84 
33| 常量 | 说明 |85| 常量 | 说明 |
34|------|------|86|------|------|
35-| weightNZFormat | B 矩阵是否为 NZ 格式继承自 BlockMmad,用于 Kernel 判断) |87+| transA | A 矩阵是否转置通过 IsTrans trait 判断) |
36-| HALF_L0_SIZE | L0 缓冲区半大小 A 类型计算) |88+| transB | B 矩阵是否转置通过 IsTrans trait 判断) |
37-| HALF_L0C_SIZE | L0C 缓冲区半大小 float 计算) |89+| weightNZFormat | B 矩阵是否为 NZ 格式通过 IsWeightNz trait 判断) |
38-| HALF_L1_SIZE | L1 缓冲区半大小 |
39| MTE1_MTE2_EVENT_ID_NUM | L1 双缓冲事件标志数量(固定 4 个) |90| MTE1_MTE2_EVENT_ID_NUM | L1 双缓冲事件标志数量(固定 4 个) |
40 91 
41-## 特殊成员方法92+## Params 参数结构
93+ 
94+### 结构定义
95+```cpp
96+struct Params {
97+ GM_ADDR aGmAddr{nullptr}; // A 矩阵 GM 地址
98+ GM_ADDR bGmAddr{nullptr}; // B 矩阵 GM 地址
99+ GM_ADDR cGmAddr{nullptr}; // C 矩阵 GM 地址
100+ GM_ADDR biasGmAddr{nullptr}; // Bias GM 地址
101+ GM_ADDR groupListGmAddr{nullptr}; // GroupList 地址(预留扩展)
102+ GM_ADDR workspaceGmAddr{nullptr}; // Workspace 地址(预留扩展)
103+ uint64_t ml1{0}; // L1 M 维度尺寸
104+ uint64_t nl1{0}; // L1 N 维度尺寸
105+ uint64_t kl1{0}; // L1 K 维度尺寸
106+ uint32_t ml0{0}; // L0 M 维度尺寸
107+ uint32_t nl0{0}; // L0 N 维度尺寸
108+ uint32_t kl0{0}; // L0 K 维度尺寸
109+ uint32_t l1Stages{1}; // L1 缓冲数量
110+ uint16_t l0cStages{1}; // L0C 缓冲数量
111+};
112+```
113+ 
114+### 参数详解
115+ 
116+#### GM 地址参数
117+| 参数 | 类型 | 说明 |
118+|------|------|------|
119+| aGmAddr | GM_ADDR | A 矩阵 GM 地址 |
120+| bGmAddr | GM_ADDR | B 矩阵 GM 地址 |
121+| cGmAddr | GM_ADDR | C 矩阵 GM 地址 |
122+| biasGmAddr | GM_ADDR | Bias GM 地址(nullptr 表示无 bias) |
123+ 
124+#### L1/L0 形状参数
125+| 参数 | 类型 | 说明 | 建议值 |
126+|------|------|------|--------|
127+| ml1 | uint64_t | L1 M 维度尺寸 | 128~256 |
128+| nl1 | uint64_t | L1 N 维度尺寸 | 128~256 |
129+| kl1 | uint64_t | L1 K 维度尺寸 | 64~128 |
130+| ml0 | uint32_t | L0 M 维度尺寸 | 64~128 |
131+| nl0 | uint32_t | L0 N 维度尺寸 | 64~128 |
132+| kl0 | uint32_t | L0 K 维度尺寸 | 32~64 |
133+ 
134+#### 缓冲配置参数
135+| 参数 | 类型 | 说明 | 建议值 |
136+|------|------|------|--------|
137+| l1Stages | uint32_t | L1 缓冲数量 | 1、2 或 4(默认 1) |
138+| l0cStages | uint16_t | L0C 缓冲数量 | 1 或 2(默认 1) |
139+ 
140+## 公共成员方法(Public API)
42 141 
43### 构造函数142### 构造函数
44-```143+```cpp
45__aicore__ inline BlockMmad()144__aicore__ inline BlockMmad()
46```145```
47-功能:构造 BlockMmad 对象,初始化硬件事件标志。146+功能:构造 BlockMmad 对象,初始化硬件事件标志和 MM Layout Transform
48-执行流程:设置 4 个 MTE1_MTE2 标志、2 个 FIX_M 标志、2 个 M_MTE1 标志。147+执行流程:
148+1. ASCEND_IS_NOT_AIV 时设置 4 个 MTE1_MTE2 标志、2 个 FIX_M 标志、2 个 M_MTE1 标志
149+2. ASCEND_IS_NOT_AIV 时调用 `SetMMLayoutTransform(true)`(适配 Fixpipe)
49 150 
50### 析构函数151### 析构函数
51-```152+```cpp
52__aicore__ inline ~BlockMmad()153__aicore__ inline ~BlockMmad()
53```154```
54-功能:析构 BlockMmad 对象,等待硬件事件完成。155+功能:析构 BlockMmad 对象,等待硬件事件完成并关闭 MM Layout Transform
55-执行流程:等待 4 个 MTE1_MTE2 标志、2 个 FIX_M 标志、2 个 M_MTE1 标志。156+执行流程:
157+1. ASCEND_IS_NOT_AIV 时等待 4 个 MTE1_MTE2 标志、2 个 FIX_M 标志、2 个 M_MTE1 标志
158+2. ASCEND_IS_NOT_AIV 时调用 `SetMMLayoutTransform(false)`(关闭)
56 159 
57### Init函数160### Init函数
58-```161+```cpp
59-template <uint64_t FULL_LOAD_MODE_ = B_FULL_LOAD_MODE>
60__aicore__ inline void Init(162__aicore__ inline void Init(
61 const TupleShape& shape, // 问题规模163 const TupleShape& shape, // 问题规模
62- const TupleShape& tileL1, // L1 切分形状164+ const Params& params) // BlockMmad 参数
63- const TupleShape& tileL0, // L0 切分形状
64- bool isBias, // 是否启用 bias
65- uint64_t l1BufNum, // L1 缓冲数量(1 或 2)
66- bool l0cDB) // 是否启用 L0C 双缓冲
67```165```
68功能:初始化 BlockMmad 组件。166功能:初始化 BlockMmad 组件。
69参数说明:167参数说明:
70| 参数 | 类型 | 说明 |168| 参数 | 类型 | 说明 |
71|------|------|------|169|------|------|------|
72-| shape | TupleShape | 问题规模 |170+| shape | TupleShape | 问题规模 `(m, n, k, batch)` |
73-| tileL1 | TupleShape | L1 tile 形状 |171+| params | Params | BlockMmad 参数 |
74-| tileL0 | TupleShape | L0 tile 形状 |
75-| isBias | bool | 是否包含 bias 计算 |
76-| l1BufNum | uint64_t | L1 双缓冲数量,1 或 2 |
77-| l0cDB | bool | 是否启用 L0C 双缓冲优化 |
78 172 
79-说明173+执行流程
80--板参数 `FULL_LOAD_MODE_` 用于指定全载模式(默认 B_FULL_LOAD_MODE)174+1. 设置问题规:m_, n_, k_
81-- L1 缓冲数量可配置(1 2),影响 GM→L1 流水线并行度175+2. 设置 L1/L0 形状:mL1_, nL1_, kL1_, baseM_, baseN_, baseK_
82-- L0C 双缓冲可配置,实现 L0C 搬出与写入的并行176+3. 判断 Bias:`isBias_ = params.biasGmAddr != nullptr`
177+4. 设置缓冲策略:l1Stages_, enableL0cPingPong_
178+5. 计算缓冲偏移:aL1Buffer_[i], bL1Buffer_[i], biasL1Buffer_[i]
83 179 
84### operator函数180### operator函数
85-```181+```cpp
86-template <typename TensorC, typename TensorA, typename TensorB, typename TensorBias>182+template <typename TensorA, typename TensorB, typename TensorBias, typename TensorC>
87__aicore__ inline void operator()(183__aicore__ inline void operator()(
88- TensorC gmC, // C 矩阵 GM Tensor184+ TensorA& gmA, // A 矩阵 GM Tensor
89- TensorA gmA, // A 矩阵 GM Tensor185+ TensorB& gmB, // B 矩阵 GM Tensor
90- TensorB gmB, // B 矩阵 GM Tensor186+ TensorBias& gmBias, // Bias GM Tensor
91- TensorBias gmBias, // Bias GM Tensor187+ TensorC& gmC, // C 矩阵 GM Tensor
92- TupleL1L0Shape tileShape) // Tile 形状188+ TupleL1L0Shape& tileShape) // Tile 形状
93```189```
94功能:执行单个 block 的矩阵乘计算。190功能:执行单个 block 的矩阵乘计算。
95参数说明:191参数说明:
96| 参数 | 类型 | 说明 |192| 参数 | 类型 | 说明 |
97|------|------|------|193|------|------|------|
98-| gmC | TensorC | C 矩阵输出 Tensor(已 Slice 到当前 block) |
99| gmA | TensorA | A 矩阵输入 Tensor(已 Slice 到当前 block) |194| gmA | TensorA | A 矩阵输入 Tensor(已 Slice 到当前 block) |
100| gmB | TensorB | B 矩阵输入 Tensor(已 Slice 到当前 block) |195| gmB | TensorB | B 矩阵输入 Tensor(已 Slice 到当前 block) |
101| gmBias | TensorBias | Bias 输入 Tensor(已 Slice) |196| gmBias | TensorBias | Bias 输入 Tensor(已 Slice) |
102-| tileShape | TupleL1L0Shape | Tile 形状 `(m, n, k, m0, n0, k0)` |197+| gmC | TensorC | C 矩阵输出 Tensor(已 Slice 到当前 block) |
198+| tileShape | TupleL1L0Shape | Tile 形状 `(mL1, nL1, k, batch, mL0, nL0)` |
103 199 
104-## 特殊数据结构200+执行流程:
201+1. **K 轴外层循环**:按 kL1 切分
202+2. **搬运 A/B/Bias 到 L1**:根据 l1Stages 决定缓冲数量
203+3. **K 轴内层循环**:按 baseK 切分
204+4. **搬运 A/B 到 L0**:双缓冲模式
205+5. **Mmad 计算**:首次迭代时加载 Bias
206+6. **结果搬出**:L0C → GM(通过 Fixpipe)
105 207 
106-### Arguments / Params208+## 事件同步
107-```
108-struct Arguments {
109- GM_ADDR aGmAddr; // A 矩阵 GM 起始地址
110- GM_ADDR bGmAddr; // B 矩阵 GM 起始地址
111- GM_ADDR cGmAddr; // C 矩阵 GM 起始地址
112- GM_ADDR biasGmAddr; // Bias GM 起始地址(可选)
113- GM_ADDR groupListGmAddr; // GroupList 地址(预留扩展)
114- GM_ADDR workspaceGmAddr; // 工作空间地址(预留扩展)
115-};
116-```
117- 
118-说明:`Params``Arguments`,无 workspace 实际使用。
119- 
120-## 事件同步(Basic 特有)
121 209 
122| 事件 | 用途 |210| 事件 | 用途 |
123|------|------|211|------|------|
124-| MTE1_MTE2 | L1 缓冲同步(4 个标志) |212+| MTE1_MTE2 (0-3) | L1 缓冲同步(4 个标志) |
125-| FIX_M | L0C 双缓冲同步(2 个标志) |213+| FIX_M (0-1) | L0C 双缓冲同步(2 个标志) |
126-| M_MTE1 | L0 双缓冲同步(2 个标志) |214+| M_MTE1 (6-7) | L0 双缓冲同步(2 个标志) |
127| MTE2_MTE1 | GM→L1 完成同步 |215| MTE2_MTE1 | GM→L1 完成同步 |
128| MTE1_M | L1→L0 完成同步 |216| MTE1_M | L1→L0 完成同步 |
129-| M_FIX | Mmad 计算完成同步 |
130- 
131-说明:事件数量可通过 Init 参数配置启用/禁用。
132 217 
133## 调用示例218## 调用示例
134 219 
135### 组件组装220### 组件组装
136-```221+```cpp
137using AType = half;222using AType = half;
138using BType = half;223using BType = half;
139using CType = float;224using CType = float;
140using BiasType = float;225using BiasType = float;
141-using LayoutA = AscendC::Te::Layout::RowMajor;226+using LayoutA = AscendC::Te::NZLayoutPtn;
142-using LayoutB = AscendC::Te::Layout::ColMajor;227+using LayoutB = AscendC::Te::NZLayoutPtn;
143-using LayoutC = AscendC::Te::Layout::RowMajor;228+using LayoutC = AscendC::Te::NDLayoutPtn;
144using LayoutBias = LayoutC;229using LayoutBias = LayoutC;
145 230 
146-using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockBasic<B_FULL_LOAD_MODE>;231+using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockBasic<0>; // 非全载
147using BlockMmad = Blaze::Gemm::Block::BlockMmad<232using BlockMmad = Blaze::Gemm::Block::BlockMmad<
148 DispatchPolicy, AType, LayoutA, BType, LayoutB, CType, LayoutC, BiasType, LayoutBias>;233 DispatchPolicy, AType, LayoutA, BType, LayoutB, CType, LayoutC, BiasType, LayoutBias>;
149```234```
150 235 
151-### 组件实例化236+### 参数准备
237+```cpp
238+BlockMmad::Params params = {
239+ .aGmAddr = aGM,
240+ .bGmAddr = bGM,
241+ .cGmAddr = cGM,
242+ .biasGmAddr = biasGM, // nullptr 表示无 bias
243+ .ml1 = 256,
244+ .nl1 = 256,
245+ .kl1 = 128,
246+ .ml0 = 128,
247+ .nl0 = 128,
248+ .kl0 = 64,
249+ .l1Stages = 2, // L1 双缓冲
250+ .l0cStages = 1 // L0C 单缓冲
251+};
152```252```
253+ 
254+### 组件实例化
255+```cpp
153BlockMmad blockMmad;256BlockMmad blockMmad;
154```257```
155 258 
156### 组件初始化259### 组件初始化
157-```260+```cpp
158TupleShape problemShape{m, n, k, batch};261TupleShape problemShape{m, n, k, batch};
159-TupleShape tileL1{mL1, nL1, kL1, 0, 0, 0};262+blockMmad.Init(problemShape, params);
160-TupleShape tileL0{baseM, baseN, baseK, 0, 0, 0};
161-bool isBias = true;
162-uint64_t l1BufNum = 2; // L1 双缓冲
163-bool l0cDB = true; // L0C 双缓冲
164-blockMmad.Init(problemShape, tileL1, tileL0, isBias, l1BufNum, l0cDB);
165```263```
166 264 
167### 组件执行265### 组件执行
168-```266+```cpp
169// 准备 GM Tensor(已在 kernel 层创建)267// 准备 GM Tensor(已在 kernel 层创建)
170auto gmA = AscendC::Te::MakeTensor(...);268auto gmA = AscendC::Te::MakeTensor(...);
171auto gmB = AscendC::Te::MakeTensor(...);269auto gmB = AscendC::Te::MakeTensor(...);
@@ -179,48 +277,56 @@ auto gmBlockC = gmC.Slice(AscendC::MakeCoord(coordM, coordN), AscendC::MakeShape
179auto gmBlockBias = gmBias.Slice(AscendC::MakeCoord(0, coordN), AscendC::MakeShape(1, shapeN));277auto gmBlockBias = gmBias.Slice(AscendC::MakeCoord(0, coordN), AscendC::MakeShape(1, shapeN));
180 278 
181// 执行矩阵乘279// 执行矩阵乘
182-TupleL1L0Shape tileShape{shapeM, shapeN, shapeK, baseM, baseN, baseK};280+TupleL1L0Shape tileShape{shapeM, shapeN, shapeK, batch, mL0, nL0};
183-blockMmad(gmBlockC, gmBlockA, gmBlockB, gmBlockBias, tileShape);281+blockMmad(gmBlockA, gmBlockB, gmBlockBias, gmBlockC, tileShape);
184```282```
185 283 
186## 数据流284## 数据流
187 285 
188-### 存储层次(Basic 特有)286+### 存储层次
189```287```
190-GM → L1 (缓冲) → L0A/L0B (双缓冲) → L0C (双缓冲) → GM288+GM (A/B/Bias) → L1 (缓冲) → L0A/L0B (双缓冲) → L0C (单缓冲或双缓冲) → GM (C)
191-
192- BIAS → L1 → BIAS Buffer
193```289```
194 290 
195### 执行流程291### 执行流程
196```292```
197K 轴外层循环:按 kL1 切分293K 轴外层循环:按 kL1 切分
198294
199-搬运 A、B、Bias 到 L1295+搬运 A、B、Bias 到 L1(多缓冲)
200296
201K 轴内层循环:按 baseK 切分297K 轴内层循环:按 baseK 切分
202298
203-搬运 A、B 到 L0299+搬运 A、B 到 L0(双缓冲)
204300
205Mmad 计算:C += A × B + Bias(首次迭代)301Mmad 计算:C += A × B + Bias(首次迭代)
206302
207-结果搬出:L0C → GM303+结果搬出:L0C → GM(Fixpipe)
208```304```
209 305 
210-## 性能优化建议(Basic 特有)306+## 性能优化建议
211 307 
212### L1 缓冲配置308### L1 缓冲配置
213-- 矩阵场景:建议 `l1BufNum = 2` 最大化流水线并行度309+- **单缓冲(l1Stages=1)**:小矩阵场景,减少缓冲开销
214-- 矩阵场景:可使用 `l1BufNum = 1` 减少缓冲开销310+- **双缓冲(l1Stages=2)**:中等矩阵场景,平衡并行度和开销
311+- **四缓冲(l1Stages=4)**:大矩阵场景,最大化流水线并行度
215 312 
216### L0C 双缓冲313### L0C 双缓冲
217-- 启用 L0C 双缓冲(`l0cDB = true`可隐藏搬出延迟314+- **单缓冲(l0cStages=1**:小矩阵场景,默认配置
218-- 禁用时`l0cDB = false`可减少事件同步开销315+- **双缓冲l0cStages=2**:大矩阵场景,隐藏搬出延迟
316+ 
317+### L1/L0 形状配置
318+- **mL1/baseM 成倍数关系**:减少尾块开销
319+- **nL1/baseN 成倍数关系**:减少尾块开销
320+- **kL1/baseK 成倍数关系**:减少尾块开销
219 321 
220### 全载模式选择322### 全载模式选择
221-- **非全载模式**:每次迭代重新加载 A/B 块,适于小 K 场景323+- **非全载模式(FULL_LOAD_MODE=0)**:用场景,支持 SplitK
222-- **B 全载模式**:B 矩阵常驻 L1适用于大 K、小 N 场景324+- **B 全载模式(FULL_LOAD_MODE=2)**:B 矩阵较小可完全载入 L1
223-- **A 全载模式**:A 矩阵常驻 L1适用于大 K、小 M 场景325+- **A 全载模式(FULL_LOAD_MODE=1)**:A 矩阵较小可完全载入 L1
326+ 
327+### NZ 格式优化
328+- **权重矩阵(B)**:优先使用 NZ 格式,提升 L1/L0 搬运效率
329+- **激活矩阵(A)**:使用 ND 格式即可
224 330 
225### 适用场景331### 适用场景
226- Basic Kernel 的 BlockMmad 实现332- Basic Kernel 的 BlockMmad 实现
@@ -30,12 +30,24 @@ StreamK 矩阵乘 Block,基于 Tensor API 实现,仅支持 AIC 计算。支
30 30 
31### L1/L0 缓冲31### L1/L0 缓冲
32- **L1 双缓冲**:固定使用 2 个缓冲(`BUFFER_NUM = 2`32- **L1 双缓冲**:固定使用 2 个缓冲(`BUFFER_NUM = 2`
33-- **L0 双缓冲**:固定使用 2 个缓冲(`HALF_L0_SIZE`)33+- **L0 双缓冲**:固定使用 2 个缓冲
34- **L0C 单缓冲**:固定使用单缓冲(offset = 0)34- **L0C 单缓冲**:固定使用单缓冲(offset = 0)
35 35 
36+### L1 缓冲布局
37+```
38+L1 空间布局:
39+a1|b1|bias1|a2|b2|bias2|
40+```
41+ 
42+说明:
43+- `a1|a2`:A 矩阵双缓冲(ping-pong)
44+- `b1|b2`:B 矩阵双缓冲(ping-pong)
45+- `bias1|bias2`:Bias 双缓冲
46+- 优势:避免 A/B 缓冲区 bank conflict
47+ 
36### Bias 处理48### Bias 处理
37Bias 仅在首次 K 轴切分(`kCntIndex = 0`)时加载并累加:49Bias 仅在首次 K 轴切分(`kCntIndex = 0`)时加载并累加:
38-- 首次 `iter0 = 0` 且 `iter1 = 0` 且 `kCntIndex = 0`:加载 Bias50+- 首次迭代且 `kCntIndex = 0`:加载 Bias
39- 后续迭代:不加载 Bias,累加计算51- 后续迭代:不加载 Bias,累加计算
40 52 
41### CmatrixInitVal53### CmatrixInitVal
@@ -49,15 +61,23 @@ cmatrixInitVal = (iter0 == 0 && iter1 == 0 && (!isBias_ || (isBias_ && kCntIndex
49- 有 Bias 且首次 K 切分:不初始化(Bias 提供初始值)61- 有 Bias 且首次 K 切分:不初始化(Bias 提供初始值)
50- 有 Bias 且后续 K 切分:初始化为 062- 有 Bias 且后续 K 切分:初始化为 0
51 63 
52-### unitFlag64+### Layout Trait
53-Mmad 计算的 unitFlag 根据迭代位置确定65+使用 `IsTrans` `IsWeightNz` traits 判断 Layout
54-```66+- `IsTrans<LayoutA>`:判断 A 矩阵是否转置
55-unitFlag = (iter0 + 1 == curKL1Iter && iter1 + 1 == kL0Iter) ? FINAL_ACCUMULATION : NON_FINAL_ACCUMULATION67+- `IsTrans<LayoutB>`:判断 B 矩阵是否转置
56-```68+- `IsWeightNz<LayoutB>`:判断 B 矩阵是否为 NZ 格式
57 69 
58-说明:70+说明:通过 trait 自动判断 transpose 信息,无需模板参数传递。
59-- 最后一次迭代:FINAL_ACCUMULATION(最终累加)71+ 
60-- 其他迭代:NON_FINAL_ACCUMULATION(非最终累加)72+### MM Layout Transform
73+构造函数和析构函数中设置 MM Layout Transform:
74+```
75+// 构造函数(ASCEND_IS_NOT_AIV)
76+SetMMLayoutTransform(true); // 适配 Fixpipe 输出
77+ 
78+// 析构函数(ASCEND_IS_NOT_AIV)
79+SetMMLayoutTransform(false); // 关闭
80+```
61 81 
62## 特殊静态常量82## 特殊静态常量
63 83 
@@ -70,77 +90,72 @@ unitFlag = (iter0 + 1 == curKL1Iter && iter1 + 1 == kL0Iter) ? FINAL_ACCUMULATIO
70 90 
71## 特殊数据结构91## 特殊数据结构
72 92 
73-### GmParams93+### Params
74```94```
75-struct GmParams {95+struct Params {
76 GM_ADDR aGmAddr{nullptr}; // A 矩阵 GM 地址96 GM_ADDR aGmAddr{nullptr}; // A 矩阵 GM 地址
77 GM_ADDR bGmAddr{nullptr}; // B 矩阵 GM 地址97 GM_ADDR bGmAddr{nullptr}; // B 矩阵 GM 地址
78 GM_ADDR cGmAddr{nullptr}; // C 矩阵 GM 地址(DP 模式)98 GM_ADDR cGmAddr{nullptr}; // C 矩阵 GM 地址(DP 模式)
79- GM_ADDR biasGmAddr{nullptr}; // Bias GM 地址(可选)99+ GM_ADDR biasGmAddr{nullptr}; // Bias GM 地址
100+ GM_ADDR groupListGmAddr{nullptr}; // GroupList 地址(预留扩展)
80 GM_ADDR workspaceGmAddr{nullptr}; // Workspace GM 地址(SK 模式)101 GM_ADDR workspaceGmAddr{nullptr}; // Workspace GM 地址(SK 模式)
102+ uint64_t ml1{0}; // L1 M 维度尺寸
103+ uint64_t nl1{0}; // L1 N 维度尺寸
104+ uint64_t kl1{0}; // L1 K 维度尺寸
105+ uint32_t ml0{0}; // L0 M 维度尺寸
106+ uint32_t nl0{0}; // L0 N 维度尺寸
107+ uint32_t kl0{0}; // L0 K 维度尺寸
108+ uint32_t l1Stages{2}; // L1 缓冲数量
109+ uint16_t l0cStages{1}; // L0C 缓冲数量
81};110};
82```111```
83 112 
84说明:`cGmAddr``workspaceGmAddr` 均需提供,根据 `checkIsSkScene` 选择输出目标。113说明:`cGmAddr``workspaceGmAddr` 均需提供,根据 `checkIsSkScene` 选择输出目标。
85 114 
86-### L1 缓冲布局
87-```
88-L1 空间布局:
89-Bias0|A0|A1|BInit|B0|B1|
90-```
91- 
92-说明:
93-- `Bias0`:Bias 缓冲(`nL1 × sizeof(BiasType) × BUFFER_NUM`
94-- `A0|A1`:A 矩阵双缓冲(`mL1 × kL1 × BUFFER_NUM`
95-- `BInit`:B 缓冲起始偏移(`biasL1Offset + aL1OneBuffer × BUFFER_NUM`
96-- `B0|B1`:B 矩阵双缓冲(`nL1 × kL1 × BUFFER_NUM`
97- 
98## 特殊成员方法115## 特殊成员方法
99 116 
100### 构造函数117### 构造函数
101```118```
102__aicore__ inline BlockMmad()119__aicore__ inline BlockMmad()
103```120```
104-功能:构造 BlockMmad 对象,初始化硬件事件标志。121+功能:构造 BlockMmad 对象,初始化硬件事件标志和 MM Layout Transform
105-执行流程:设置 4 个 MTE1_MTE2 标志、2 个 M_MTE1 标志。122+执行流程:
123+1. 设置 4 个 MTE1_MTE2 标志、2 个 M_MTE1 标志
124+2. ASCEND_IS_NOT_AIV 时调用 `SetMMLayoutTransform(true)`(适配 Fixpipe)
106 125 
107### 析构函数126### 析构函数
108```127```
109__aicore__ inline ~BlockMmad()128__aicore__ inline ~BlockMmad()
110```129```
111-功能:析构 BlockMmad 对象,等待硬件事件完成。130+功能:析构 BlockMmad 对象,等待硬件事件完成并关闭 MM Layout Transform
112-执行流程:等待 4 个 MTE1_MTE2 标志、2 个 M_MTE1 标志。131+执行流程:
132+1. 等待 4 个 MTE1_MTE2 标志、2 个 M_MTE1 标志
133+2. ASCEND_IS_NOT_AIV 时调用 `SetMMLayoutTransform(false)`(关闭)
113 134 
114### Init函数135### Init函数
115```136```
116__aicore__ inline void Init(137__aicore__ inline void Init(
117 const TupleShape& shape, // 问题规模138 const TupleShape& shape, // 问题规模
118- const TupleShape& tileL1, // L1 切分形状139+ const Params& params) // mmad 参数
119- const TupleShape& tileL0, // L0 切分形状
120- bool isBias) // 是否启用 bias
121```140```
122-功能:初始化 BlockMmadMatmulStreamK 组件。141+功能:初始化 BlockMmad 组件。
123参数说明:142参数说明:
124| 参数 | 类型 | 说明 |143| 参数 | 类型 | 说明 |
125|------|------|------|144|------|------|------|
126| shape | TupleShape | 问题规模 |145| shape | TupleShape | 问题规模 |
127-| tileL1 | TupleShape | L1 tile 形状 |146+| params | Params | mmad 参数(包含 isBias 判断) |
128-| tileL0 | TupleShape | L0 tile 形状 |
129-| isBias | bool | 是否包含 bias 计算 |
130 147 
131说明:148说明:
132-- L1 缓冲数量固定为 2149+- isBias 通过 `params.biasGmAddr != nullptr` 判断
133-- Bias L1 偏移计算:`biasL1Offset_ = nL1 × sizeof(BiasType) × BUFFER_NUM`
134-- B 缓冲起始偏移:`bL1Init_ = biasL1Offset + aL1OneBuffer × BUFFER_NUM`
135 150 
136### operator函数151### operator函数
137```152```
138template <typename TensorC, typename TensorA, typename TensorB, typename TensorBias, typename TensorWorkspace>153template <typename TensorC, typename TensorA, typename TensorB, typename TensorBias, typename TensorWorkspace>
139__aicore__ inline void operator()(154__aicore__ inline void operator()(
140- TensorC gmC, // C 矩阵 GM Tensor(DP 模式输出)
141 TensorA gmA, // A 矩阵 GM Tensor155 TensorA gmA, // A 矩阵 GM Tensor
142 TensorB gmB, // B 矩阵 GM Tensor156 TensorB gmB, // B 矩阵 GM Tensor
143 TensorBias gmBias, // Bias GM Tensor157 TensorBias gmBias, // Bias GM Tensor
158+ TensorC gmC, // C 矩阵 GM Tensor(DP 模式输出)
144 TensorWorkspace gmWorkspace, // Workspace GM Tensor(SK 模式输出)159 TensorWorkspace gmWorkspace, // Workspace GM Tensor(SK 模式输出)
145 TupleShape tileShape, // Tile 形状160 TupleShape tileShape, // Tile 形状
146 int64_t kCntIndex, // K 轴切分索引161 int64_t kCntIndex, // K 轴切分索引
@@ -150,10 +165,10 @@ __aicore__ inline void operator()(
150参数说明:165参数说明:
151| 参数 | 类型 | 说明 |166| 参数 | 类型 | 说明 |
152|------|------|------|167|------|------|------|
153-| gmC | TensorC | C 矩阵输出 Tensor(DP 模式) |
154| gmA | TensorA | A 矩阵输入 Tensor(已 Slice) |168| gmA | TensorA | A 矩阵输入 Tensor(已 Slice) |
155| gmB | TensorB | B 矩阵输入 Tensor(已 Slice) |169| gmB | TensorB | B 矩阵输入 Tensor(已 Slice) |
156| gmBias | TensorBias | Bias 输入 Tensor(已 Slice) |170| gmBias | TensorBias | Bias 输入 Tensor(已 Slice) |
171+| gmC | TensorC | C 矩阵输出 Tensor(DP 模式) |
157| gmWorkspace | TensorWorkspace | Workspace 输出 Tensor(SK 模式) |172| gmWorkspace | TensorWorkspace | Workspace 输出 Tensor(SK 模式) |
158| tileShape | TupleShape | Tile 形状 `(m, n, k)` |173| tileShape | TupleShape | Tile 形状 `(m, n, k)` |
159| kCntIndex | int64_t | K 轴切分索引(0 = 首次切分) |174| kCntIndex | int64_t | K 轴切分索引(0 = 首次切分) |
@@ -162,8 +177,8 @@ __aicore__ inline void operator()(
162执行流程:177执行流程:
1631. **K 轴外层循环**:按 kL1 切分1781. **K 轴外层循环**:按 kL1 切分
1642. **搬运 Bias 到 L1**:首次切分且首次迭代时搬运1792. **搬运 Bias 到 L1**:首次切分且首次迭代时搬运
165-3. **搬运 A 到 L1**:双缓冲模式180+3. **搬运 A 到 L1**:双缓冲模式(事件 0、1)
166-4. **搬运 B 到 L1**:双缓冲模式(事件偏移 +2181+4. **搬运 B 到 L1**:双缓冲模式(事件 2、3,偏移 L1_EVENT_ID_OFFSET
1675. **K 轴内层循环**:按 baseK 切分(Iterate)1825. **K 轴内层循环**:按 baseK 切分(Iterate)
1686. **搬运 A/B/Bias 到 L0**:双缓冲模式1836. **搬运 A/B/Bias 到 L0**:双缓冲模式
1697. **Mmad 计算**:根据 `kCntIndex` 决定是否加载 Bias1847. **Mmad 计算**:根据 `kCntIndex` 决定是否加载 Bias
@@ -173,7 +188,6 @@ __aicore__ inline void operator()(
173 188 
174### L1 B 缓冲事件偏移189### L1 B 缓冲事件偏移
175```190```
176-uint64_t offsetBL1 = (bL1Init + bL1OneBuffer * l1BufId) * sizeof(BType);
177AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId + L1_EVENT_ID_OFFSET); // B 使用事件 2、3191AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId + L1_EVENT_ID_OFFSET); // B 使用事件 2、3
178```192```
179 193 
@@ -202,20 +216,29 @@ using BiasType = float;
202using LayoutA = AscendC::Te::NDExtLayoutPtn;216using LayoutA = AscendC::Te::NDExtLayoutPtn;
203using LayoutB = AscendC::Te::NZLayoutPtn;217using LayoutB = AscendC::Te::NZLayoutPtn;
204using LayoutC = AscendC::Te::NDExtLayoutPtn;218using LayoutC = AscendC::Te::NDExtLayoutPtn;
219+using LayoutBias = LayoutC;
205 220 
206using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>;221using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>;
207using BlockMmad = Blaze::Gemm::Block::BlockMmad<222using BlockMmad = Blaze::Gemm::Block::BlockMmad<
208 DispatchPolicy, AType, LayoutA, BType, LayoutB, CType, LayoutC, BiasType, LayoutBias>;223 DispatchPolicy, AType, LayoutA, BType, LayoutB, CType, LayoutC, BiasType, LayoutBias>;
209```224```
210 225 
226+### 参数准备
227+```
228+BlockMmad::Params params = {
229+ aGM, // A 矩阵 GM 地址
230+ bGM, // B 矩阵 GM 地址
231+ cGM, // C 矩阵 GM 地址(DP 模式)
232+ biasGM, // Bias GM 地址(nullptr 表示无 bias)
233+ workspaceGM // Workspace GM 地址(SK 模式)
234+};
atomgit-bot
atomgit-botatomgit-bot6月25日

🟡 Medium Priority

变更行(第228-234行):block_mmad_matmul_streamk.md 的 Params 初始化示例使用位置初始化,但参数顺序错误。

证据链:

  • 源代码 include/blaze/gemm/block/block_mmad_matmul_streamk.h 第58-73行 Params 结构体字段顺序为:
    1. aGmAddr, 2. bGmAddr, 3. cGmAddr, 4. biasGmAddr, 5. groupListGmAddr, 6. workspaceGmAddr
  • 第5个位置参数 workspaceGM(意为 Workspace GM 地址)实际被赋给了第5个字段 groupListGmAddr(GroupList 地址,预留扩展),而非预期的第6个字段 workspaceGmAddr
  • workspaceGmAddr 使用默认值 nullptr,导致 StreamK 模式下 Workspace 输出目标为空

影响:用户按此示例代码编写初始化逻辑后,StreamK 模式的 workspace 输出地址为 nullptr,可能导致运行时数据写入空地址,引发计算错误或程序崩溃。这是文档中的误导性代码示例,且 StreamK 场景下 workspaceGmAddr 是必需的关键参数。

修复方案:改用指定初始化器(designated initializers),与 Basic 文档示例风格保持一致:

建议:将示例代码从位置初始化改为指定初始化器,确保 workspaceGmAddr 字段被正确赋值:.workspaceGmAddr = workspaceGM

改动建议
234
+ BlockMmad::Params params = {
235
+ .aGmAddr = aGM, // A 矩阵 GM 地址
236
+ .bGmAddr = bGM, // B 矩阵 GM 地址
237
+ .cGmAddr = cGM, // C 矩阵 GM 地址(DP 模式)
238
+ .biasGmAddr = biasGM, // Bias GM 地址(nullptr 表示无 bias)
239
+ .workspaceGmAddr = workspaceGM // Workspace GM 地址(SK 模式)
234
240
  };
应用建议
likedislike
不准确?
235+```
236+ 
211### 组件初始化237### 组件初始化
212```238```
213BlockMmad blockMmad;239BlockMmad blockMmad;
214TupleShape problemShape{m, n, k};240TupleShape problemShape{m, n, k};
215-TupleShape tileL1{mL1, nL1, kL1};241+blockMmad.Init(problemShape, params);
216-TupleShape tileL0{baseM, baseN, baseK};
217-bool isBias = true;
218-blockMmad.Init(problemShape, tileL1, tileL0, isBias);
219```242```
220 243 
221### 组件执行244### 组件执行
@@ -231,21 +254,21 @@ auto gmBias = AscendC::Te::MakeTensor(...);
231auto gmBlockA = gmA.Slice(...);254auto gmBlockA = gmA.Slice(...);
232auto gmBlockB = gmB.Slice(...);255auto gmBlockB = gmB.Slice(...);
233auto gmBlockC = gmC.Slice(...);256auto gmBlockC = gmC.Slice(...);
234-auto gmWorkspace = gmWorkspace.Slice(...);257+auto gmBlockWorkspace = gmWorkspace.Slice(...);
235auto gmBlockBias = gmBias.Slice(...);258auto gmBlockBias = gmBias.Slice(...);
236 259 
237// 执行矩阵乘260// 执行矩阵乘
238TupleShape tileShape{shapeM, shapeN, shapeK};261TupleShape tileShape{shapeM, shapeN, shapeK};
239int64_t kCntIndex = 0; // K 轴切分索引262int64_t kCntIndex = 0; // K 轴切分索引
240bool checkIsSkScene = true; // SK 模式(输出到 workspace)263bool checkIsSkScene = true; // SK 模式(输出到 workspace)
241-blockMmad(gmBlockC, gmBlockA, gmBlockB, gmBlockBias, gmWorkspace, tileShape, kCntIndex, checkIsSkScene);264+blockMmad(gmBlockA, gmBlockB, gmBlockBias, gmBlockC, gmBlockWorkspace, tileShape, kCntIndex, checkIsSkScene);
242```265```
243 266 
244## 数据流267## 数据流
245 268 
246### 存储层次269### 存储层次
247```270```
248-GM (A/B/Bias) → L1 (双缓冲) → L0A/L0B (双缓冲) → L0C → GM/Workspace271+GM (A/B/Bias) → L1 (双缓冲: a1|b1|bias1|a2|b2|bias2) → L0A/L0B (双缓冲) → L0C → GM/Workspace
249```272```
250 273 
251### DP 模式流程274### DP 模式流程
@@ -278,6 +301,7 @@ Mmad 计算(根据 kCntIndex 决定 Bias 加载)
278### L1 缓冲配置301### L1 缓冲配置
279- 固定双缓冲(BUFFER_NUM = 2)302- 固定双缓冲(BUFFER_NUM = 2)
280- A 和 B 使用不同事件 ID(0-1 vs 2-3),最大化并行度303- A 和 B 使用不同事件 ID(0-1 vs 2-3),最大化并行度
304+- L1 布局:`a1|b1|bias1|a2|b2|bias2`,避免 bank conflict
281 305 
282### K 轴切分策略306### K 轴切分策略
283- `kCntIndex` 用于标识当前 K 轴切分索引307- `kCntIndex` 用于标识当前 K 轴切分索引
@@ -289,6 +313,11 @@ Mmad 计算(根据 kCntIndex 决定 Bias 加载)
289- **SK 模式**:K 轴切分,输出到 workspace313- **SK 模式**:K 轴切分,输出到 workspace
290- workspace 大小:`skKTileNum × BLOCK_BASE_M × BLOCK_BASE_N × sizeof(float)`314- workspace 大小:`skKTileNum × BLOCK_BASE_M × BLOCK_BASE_N × sizeof(float)`
291 315 
316+### MM Layout Transform
317+- 构造函数中设置 `SetMMLayoutTransform(true)`
318+- 析构函数中关闭 `SetMMLayoutTransform(false)`
319+- 仅在 ASCEND_IS_NOT_AIV 时执行
320+ 
292### L0C 单缓冲321### L0C 单缓冲
293- StreamK BlockMmad 固定使用 L0C 单缓冲322- StreamK BlockMmad 固定使用 L0C 单缓冲
294- L0C 双缓冲在 Kernel 层处理(通过多个 tile 并行)323- L0C 双缓冲在 Kernel 层处理(通过多个 tile 并行)
@@ -79,12 +79,12 @@ AscendC::Te::Mmad(
79### Params79### Params
80```80```
81struct Params {81struct Params {
82- GM_ADDR aGmAddr; // A 矩阵 GM 起始地址82+ GM_ADDR aGmAddr{nullptr}; // A 矩阵 GM 地址
83- GM_ADDR bGmAddr; // B 矩阵 GM 起始地址83+ GM_ADDR bGmAddr{nullptr}; // B 矩阵 GM 地址
84- GM_ADDR cGmAddr; // C 矩阵 GM 起始地址84+ GM_ADDR cGmAddr{nullptr}; // C 矩阵 GM 地址
85- GM_ADDR biasGmAddr; // Bias GM 起始地址(可选)85+ GM_ADDR biasGmAddr{nullptr}; // Bias GM 地址
86- GM_ADDR scaleAGmAddr; // A 矩阵 Scale GM 地址86+ GM_ADDR scaleAGmAddr{nullptr}; // A 矩阵 Scale GM 地址
87- GM_ADDR scaleBGmAddr; // B 矩阵 Scale GM 地址87+ GM_ADDR scaleBGmAddr{nullptr}; // B 矩阵 Scale GM 地址
88};88};
89```89```
90 90 
@@ -93,17 +93,17 @@ struct Params {
93struct L1Params {93struct L1Params {
94 uint64_t kL1; // L1 K 轴切分大小94 uint64_t kL1; // L1 K 轴切分大小
95 uint64_t scaleKL1; // Scale K 轴切分大小95 uint64_t scaleKL1; // Scale K 轴切分大小
96- uint64_t l1BufNum; // L1 缓冲数量(2 或 4)96+ uint64_t l1BufNum; // L1 缓冲数量
97};97};
98```98```
99 99 
100### TileL1L0Param100### TileL1L0Param
101```101```
102struct TileL1L0Param {102struct TileL1L0Param {
103- uint64_t curM; // 当前 M 维大小103+ uint64_t curM = 0; // 当前 M 维大小
104- uint64_t curN; // 当前 N 维大小104+ uint64_t curN = 0; // 当前 N 维大小
105- uint64_t curGmKL1; // A/B 矩阵当前 GM K 维大小105+ uint64_t curGmKL1 = 0; // A/B 矩阵当前 GM K 维大小
106- uint64_t curPadKL1; // A/B 矩阵对齐后的 K 维大小(对齐到 64106+ uint64_t curPadKL1 = 0; // pad to 64 align
107};107};
108```108```
109 109 
@@ -71,28 +71,16 @@ __aicore__ inline int64_t GetTotalTileNum(); // BlockSchedulerStreamK
71```71```
72功能:返回总 tile 数量(含 batch)。72功能:返回总 tile 数量(含 batch)。
73 73 
74-### GetTileL1Shape
75-```cpp
76-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL1Shape()
77-```
78-功能:返回 L1 tile 形状 `{mL1, nL1, kL1, 1}`
79- 
80-### GetTileL0Shape
81-```cpp
82-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL0Shape()
83-```
84-功能:返回 L0 tile 形状 `{baseM, baseN, baseK, 1}`
85- 
86### GetBlockNum74### GetBlockNum
87```cpp75```cpp
88__aicore__ inline int64_t GetBlockNum(ProblemShape shape, int64_t blockNum)76__aicore__ inline int64_t GetBlockNum(ProblemShape shape, int64_t blockNum)
89```77```
90功能:返回实际使用的 Block 数量(不超过 tile 总数)。78功能:返回实际使用的 Block 数量(不超过 tile 总数)。
91 79 
92-### GetBlockShape / GetSingleCoreShape80+### GetBlockShape
93```cpp81```cpp
94__aicore__ inline BlockShape GetBlockShape(int64_t tileIdx, ...); // BlockSchedulerMatmulBasic82__aicore__ inline BlockShape GetBlockShape(int64_t tileIdx, ...); // BlockSchedulerMatmulBasic
95-__aicore__ inline BlockShape GetSingleCoreShape(int64_t tileIdx); // BlockSchedulerStreamK83+__aicore__ inline BlockShape GetBlockShape(int64_t tileIdx); // BlockSchedulerStreamK
96template <QuantMode aQuantMode, QuantMode bQuantMode, bool weightNz = false>84template <QuantMode aQuantMode, QuantMode bQuantMode, bool weightNz = false>
97__aicore__ inline BlockShape GetBlockShape(BlockCoord blockCoord); // BlockSchedulerQuantBatchMatmulV385__aicore__ inline BlockShape GetBlockShape(BlockCoord blockCoord); // BlockSchedulerQuantBatchMatmulV3
98```86```
@@ -100,10 +88,10 @@ __aicore__ inline BlockShape GetBlockShape(BlockCoord blockCoord); // Block
100 88 
101QuantBatchMatmulV3 的 `BlockShape` 第 3、4 个字段用于携带 M/N 尾块切分偏移。89QuantBatchMatmulV3 的 `BlockShape` 第 3、4 个字段用于携带 M/N 尾块切分偏移。
102 90 
103-### GetBlockCoord / GetSingleCoreCoord / GetTileIdx91+### GetBlockCoord / GetTileIdx
104```cpp92```cpp
105__aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx); // BlockSchedulerMatmulBasic93__aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx); // BlockSchedulerMatmulBasic
106-__aicore__ inline BlockCoord GetSingleCoreCoord(int64_t tileIdx); // BlockSchedulerStreamK94+__aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx); // BlockSchedulerStreamK
107__aicore__ inline bool GetTileIdx(BlockCoord& blockCoord); // BlockSchedulerQuantBatchMatmulV395__aicore__ inline bool GetTileIdx(BlockCoord& blockCoord); // BlockSchedulerQuantBatchMatmulV3
108```96```
109功能:返回当前 tile 的 Block 坐标。97功能:返回当前 tile 的 Block 坐标。
@@ -198,7 +186,10 @@ BlockScheduler::Params params = {
198};186};
199 187 
200ProblemShape shape{m, n, k, batch};188ProblemShape shape{m, n, k, batch};
201-BlockScheduler scheduler(shape, blockIdx, blockNum, params, isFp32, isNdFormat);189+BlockScheduler scheduler(shape, params);
190+ 
191+int64_t blockIdx = AscendC::GetBlockIdx();
192+int64_t blockNum = scheduler.GetBlockNum(shape);
202 193 
203for (int64_t tileIdx = blockIdx; tileIdx < scheduler.GetTileNum(); tileIdx += blockNum) {194for (int64_t tileIdx = blockIdx; tileIdx < scheduler.GetTileNum(); tileIdx += blockNum) {
204 auto blockShape = scheduler.GetBlockShape<transB, BType>(tileIdx);195 auto blockShape = scheduler.GetBlockShape<transB, BType>(tileIdx);
@@ -2,9 +2,9 @@
2> [代码位置](../../../../include/blaze/gemm/block/block_scheduler_matmul_basic.h)2> [代码位置](../../../../include/blaze/gemm/block/block_scheduler_matmul_basic.h)
3 3 
4## 功能说明4## 功能说明
5-MatmulBasic 内置调度器,支持 tile 切分、block 分配、Z 型扫描、尾块切分、单核 SplitK 切分等。适用于 Basic Kernel 和通用矩阵乘场景。5+MatmulBasic 调度器,支持 tile 切分、Z 型扫描、尾块切分、FP32 SplitK 切分等。适用于 Basic Kernel 场景。
6 6 
7-**继承自**:[Block Scheduler 公共框架](./block_scheduler.md)7+**继承自**:无(独立类)
8 8 
9## 模板参数9## 模板参数
10 10 
@@ -12,51 +12,39 @@ MatmulBasic 内置调度器,支持 tile 切分、block 分配、Z 型扫描、
12|------|------|--------|------|12|------|------|--------|------|
13| ProblemShape_ | Shape<int64_t, int64_t, int64_t, int64_t> | - | 问题规模 `(m, n, k, batch)` |13| ProblemShape_ | Shape<int64_t, int64_t, int64_t, int64_t> | - | 问题规模 `(m, n, k, batch)` |
14| FullLoadMode_ | int64_t | 0 | 全载模式:0=非全载, 1=A全载, 2=B全载 |14| FullLoadMode_ | int64_t | 0 | 全载模式:0=非全载, 1=A全载, 2=B全载 |
15+| IsFp32_ | bool | false | 是否为 FP32 类型 |
16+| IsNdFormat_ | bool | true | 是否为 ND 格式 |
15 17 
16## 全载模式18## 全载模式
17 19 
18-| 值 | 常量 | 说明 | 适用场景 |20+| 值 | 说明 | 适用场景 |
19-|----|------|------|----------|21+|----|------|----------|
20-| 0 | - | 非全载模式(默认) | 通用场景,支持 SplitK |22+| 0 | 非全载模式(默认) | 通用场景,支持 SplitK |
21-| 1 | A_FULL_LOAD_MODE | A 矩阵全载 | A 矩阵较小,可完全载入 L1 |23+| 1 | A 矩阵全载 | A 矩阵较小,可完全载入 L1 |
22-| 2 | B_FULL_LOAD_MODE | B 矩阵全载 | B 矩阵较小,可完全载入 L1 |24+| 2 | B 矩阵全载 | B 矩阵较小,可完全载入 L1 |
23 25 
24## Params 参数结构26## Params 参数结构
25 27 
26### 结构定义28### 结构定义
27```cpp29```cpp
28struct Params {30struct Params {
29- // L1 tile 形状(必填)31+ uint32_t mL1 = 0; // M 轴 L1 tile 尺寸
30- uint32_t mL1 = 0; // M 轴 L1 tile 尺寸32+ uint32_t nL1 = 0; // N 轴 L1 tile 尺寸
31- uint32_t nL1 = 0; // N 轴 L1 tile 尺寸33+ uint32_t kL1 = 0; // K 轴 L1 tile 尺寸
32- uint32_t kL1 = 0; // KL1 tile 尺寸34+ uint32_t baseM = 0; // ML0 base 尺寸
33- 35+ uint32_t baseN = 0; // N 轴 L0 base 尺寸
34- // L0 base 形状(必填)36+ uint32_t baseK = 0; // K 轴 L0 base 尺寸
35- uint32_t baseM = 0; // M 轴 L0 base 尺寸37+ uint32_t mTailCnt = 0; // M 轴尾块切分数量
36- uint32_t baseN = 0; // N 轴 L0 base 尺寸38+ uint32_t nTailCnt = 0; // N 轴尾块切分数量
37- uint32_t baseK = 0; // KL0 base 尺寸39+ uint32_t mBaseTailSplitCnt = 1; // ML1 尾块切分数量
38- 40+ uint32_t nBaseTailSplitCnt = 1; // N 轴 L1 尾块切分数量
39- // 尾块切分(Batch=1 场景,可选)41+ uint32_t mTailMain = 1; // M 轴 L1 尾块主尺寸
40- uint32_t mTailCnt = 0; // M 轴尾块切分数量42+ uint32_t nTailMain = 1; // N L1 尾块主尺寸
41- uint32_t nTailCnt = 0; // N 轴尾块切分数量43+ uint8_t isHf32 = 0; // ub默认不开db为1
atomgit-bot
atomgit-botatomgit-bot6月25日

🔵 Low Priority

变更行(第43行):Params 结构体中 isHf32 字段的注释为 // ub默认不开db为1

证据链:

  • 对应源代码 include/blaze/gemm/block/block_scheduler_matmul_basic.h 第46行注释为 // HF32开启标志(HF32 enable flag)
  • 文档中的注释 "ub默认不开db为1" 含义不明确,看起来像是编辑过程中残留的碎片文本(可能是 "UB默认不开双缓冲" 之类的片段)
  • 该注释与字段实际含义(HF32模式开关)完全无关,无法为读者提供有效信息

影响:读者看到 "ub默认不开db为1" 会感到困惑,不知道这个参数的真实用途。isHf32 控制 HF32 计算模式的开关(见文档第128-136行的专项说明),注释应反映这一含义。

修复方案:将注释修改为与源代码一致的 // HF32开启标志,或使用更清晰的描述如 // HF32 模式标志(0=关闭, 1=开启)

建议:将 isHf32 字段的注释修改为与源代码一致的 // HF32开启标志

likedislike
不准确?
42- 44+ uint32_t l2CacheMode = L2_CACHE_DEFAULT; // L2Cache默认使能
43- // L1 尾块切分(可选)45+ uint32_t sliceM; // 鞧连续场景m轴
44- uint32_t mBaseTailSplitCnt = 1; // M L1 尾块切分数量46+ uint32_t srcNdStride; // 鞧连续场景mstride
45- uint32_t nBaseTailSplitCnt = 1; // N L1 尾块切分数量47+ uint32_t innerBatch = 1; // 鞧连续transpose场景内batch值
atomgit-bot
atomgit-botatomgit-bot6月25日

🟡 Medium Priority

变更行(第45-47行):Params 结构体中的注释使用了 "鞧连续"(如 // 鞧连续场景m轴// 鞧连续场景m轴stride)。

证据链:

  • 对应源代码 include/blaze/gemm/block/block_scheduler_matmul_basic.h 第48-50行正确使用了 "非连续"(如 // 非连续场景m轴
  • "鞧"(读作 qiū,意为皮革带)是一个罕见汉字,此处明显是 "非连续"(non-contiguous)的 UTF-8 字节序列被错误解码后的结果
  • 该字符编码损坏发生在文档的三处注释中(第45、46、47行)

影响:用户阅读文档时无法理解 "鞧连续场景" 的含义,会误以为这是某个专用术语。由于 sliceM/srcNdStride/innerBatch 这几个参数与非连续(非 ND 连续格式)矩阵场景密切相关,注释含义完全无法从损坏后的文字中推断,可能导致用户错误配置参数。

修复方案:将三处 "鞧连续" 替换为 "非连续"。

改动建议
47
+ uint32_t sliceM; // 非连续场景m轴
48
+ uint32_t srcNdStride; // 非连续场景m轴stride
47
- uint32_t innerBatch = 1; // 连续transpose场景内轴batch值
49
+ uint32_t innerBatch = 1; // 连续transpose场景内轴batch值
应用建议
likedislike
不准确?
林旭
林旭
6月25日 评论:
46- uint32_t mTailMain = 1; // M 轴 L1 尾块主尺寸
47- uint32_t nTailMain = 1; // N 轴 L1 尾块主尺寸
48- 
49- // 其他配置(可选)
50- uint8_t isHf32 = 0; // HF32 模式标志
51- uint8_t l1BufferNum = 0; // L1 缓冲数量(双缓冲=2)
52- uint8_t l0cDB = 1; // L0C 双缓冲(1=单缓冲, 2=双缓冲)
53- uint8_t ubDB = 1; // UB 双缓冲(1=单缓冲, 2=双缓冲)
54- L2CacheMode l2CacheDisable = L2CacheMode::L2_CACHE_DEFAULT; // L2Cache 配置
55- 
56- // 非连续场景(可选)
57- uint32_t sliceM = 0; // 非连续场景 M 轴 slice 尺寸
58- uint32_t srcNdStride = 0; // 非连续场景 stride
59- uint32_t innerBatch = 1; // 非连续 transpose 场景内轴 batch
60};48};
61```49```
62 50 
@@ -108,7 +96,7 @@ baseM=128, baseN=128, baseK=64
108 96 
109**触发条件**97**触发条件**
110- `batch_ == 1`98- `batch_ == 1`
111-- `tileIdx / blockNum_ == perCoreBlockNum_ - 1`(最后一个 tile)99+- `tileIdx / blockNum_ == (perCoreBlockNum_ - 1)`(最后一个 tile)
112 100 
113**传值建议**101**传值建议**
114| 参数 | 建议值 | 说明 |102| 参数 | 建议值 | 说明 |
@@ -125,30 +113,6 @@ mTailCnt=0, nTailCnt=0 // 实际会被设为 1
125mTailCnt=2, nTailCnt=2 // 尾块切为 4 份,4 个 Block 并行处理113mTailCnt=2, nTailCnt=2 // 尾块切为 4 份,4 个 Block 并行处理
126```114```
127 115 
128-**示意图**
129-```
130-尾块切分示意(mTailCnt=2, nTailCnt=2)
131- 
132-┌───────────────────────────────────┐
133-│ 尾块 (mL1TailLast) │
134-│ ┌──────────┐ ┌──────────┐ │
135-│ │ Block 0 │ │ Block 1 │ │ ← M 轴切分
136-│ │ (0,0) │ │ (0,1) │ │
137-│ └──────────┘ └──────────┘ │
138-│ ┌──────────┐ ┌──────────┐ │
139-│ │ Block 2 │ │ Block 3 │ │ ← M 轴切分
140-│ │ (1,0) │ │ (1,1) │ │
141-│ └──────────┘ └──────────┘ │
142-│ ↑ ↑ │
143-│ N轴切分 N轴切分 │
144-└───────────────────────────────────┘
145- 
146-切分计算:
147- splitBlkM = CeilDiv(mL1TailLast, mTailCnt)
148- splitBlkN = CeilDiv(nL1TailLast, nTailCnt)
149- tailCnt = mTailCnt × nTailCnt
150-```
151- 
152#### 4. L1 尾块切分 (mBaseTailSplitCnt, nBaseTailSplitCnt, mTailMain, nTailMain)116#### 4. L1 尾块切分 (mBaseTailSplitCnt, nBaseTailSplitCnt, mTailMain, nTailMain)
153 117 
154**作用**:当矩阵 M/N 轴不能被 mL1/nL1 整除时,尾块区域进一步切分。118**作用**:当矩阵 M/N 轴不能被 mL1/nL1 整除时,尾块区域进一步切分。
@@ -161,79 +125,27 @@ mTailCnt=2, nTailCnt=2 // 尾块切为 4 份,4 个 Block 并行处理
161| mTailMain | 1 | M 轴尾块主尺寸(当切分数量>1 时使用) |125| mTailMain | 1 | M 轴尾块主尺寸(当切分数量>1 时使用) |
162| nTailMain | 1 | N 轴尾块主尺寸(当切分数量>1 时使用) |126| nTailMain | 1 | N 轴尾块主尺寸(当切分数量>1 时使用) |
163 127 
164-**示意图**:128+#### 5. HF32 模式 (isHf32)
165-```
166-L1 尾块切分示意(mBaseTailSplitCnt=2, nBaseTailSplitCnt=1)
167 129 
168-┌────────────────────────────────────────────────────────────┐130+**作用**:启用 HF32 计算模式,用于特定精度场景。
169-│ 矩阵 M×N │
170-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
171-│ │ Normal │ │ Normal │ │ Normal │ │ Normal │ │ ← mL1NormCnt 个正常 tile
172-│ │ mL1×nL1 │ │ mL1×nL1 │ │ mL1×nL1 │ │ mL1×nL1 │ │
173-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
174-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
175-│ │ Normal │ │ Normal │ │ Normal │ │ Normal │ │
176-│ │ mL1×nL1 │ │ mL1×nL1 │ │ mL1×nL1 │ │ mL1×nL1 │ │
177-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
178-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
179-│ │ TailMain │ │ TailMain │ │ TailMain │ │ TailMain │ │ ← mBaseTailSplitCnt-1 个主尾块
180-│ │mTailMain │ │mTailMain │ │mTailMain │ │mTailMain │ │
181-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
182-│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
183-│ │ TailLast │ │ TailLast │ │ TailLast │ │ TailLast │ │ ← 最后一个尾块
184-│ │mL1TailLast││mL1TailLast││mL1TailLast││mL1TailLast│ │
185-│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
186-└────────────────────────────────────────────────────────────┘
187- 
188-计算公式:
189- mL1NormCnt = mTileNum_ - mBaseTailSplitCnt
190- mL1TailMain = (mBaseTailSplitCnt > 1) ? mTailMain : tailL1M
191- mL1TailLast = tailL1M - (mBaseTailSplitCnt - 1) × mL1TailMain
192-```
193- 
194-#### 5. 双缓冲配置 (l1BufferNum, l0cDB, ubDB)
195- 
196-**作用**:启用双缓冲可以提高数据搬运和计算的并行度。
197 131 
198**传值建议**132**传值建议**
199-| 参数 | 建议值 | 说明 |133+| 值 | 说明 |
200-|------|--------|------|134+|----|------|
201-| l1BufferNum | 2 | L1 双缓冲,建议大 tile 场景启用 |135+| 0 | 关闭 HF32 模式(默认) |
202-| l0cDB | 2 | L0C 双缓冲,建议大 tile 场景启用 |136+| 1 | 启用 HF32 模式 |
203-| ubDB | 2 | UB 双缓冲,建议大 tile 场景启用 |
204 137 
205-**示例**:138+#### 6. L2 Cache 配置 (l2CacheMode)
206-```
207-// 单缓冲(小矩阵场景)
208-l1BufferNum=1, l0cDB=1, ubDB=1
209 139 
210-// 双缓冲(大矩阵场景)140+**作用**:控制 A/B 矩阵的 L2 Cache 行为。
211-l1BufferNum=2, l0cDB=2, ubDB=2
212-```
213- 
214-#### 6. L2Cache 配置 (l2CacheDisable)
215- 
216-**作用**:控制 A/B 矩阵的 L2Cache 行为,某些场景禁用 L2Cache 可提高性能。
217 141 
218**可选值**142**可选值**
219| 常量 | 说明 | 适用场景 |143| 常量 | 说明 | 适用场景 |
220|------|------|----------|144|------|------|----------|
221-| L2_CACHE_DEFAULT | L2Cache 使能(默认) | 通用场景 |145+| L2_CACHE_DEFAULT | L2 Cache 使能(默认) | 通用场景 |
222-| A_L2_CACHE_DISABLE | 禁用 A 矩阵 L2Cache | A 矩阵复用少 |146+| A_L2_CACHE_DISABLE | 禁用 A 矩阵 L2 Cache | A 矩阵复用少 |
223-| B_L2_CACHE_DISABLE | 禁用 B 矩阵 L2Cache | B 矩阵复用少 |147+| B_L2_CACHE_DISABLE | 禁用 B 矩阵 L2 Cache | B 矩阵复用少 |
224-| ALL_L2_CACHE_DISABLE | 禁用所有 L2Cache | 矩阵场景 |148+| ALL_L2_CACHE_DISABLE | 禁用所有 L2 Cache | 矩阵场景 |
atomgit-bot
atomgit-botatomgit-bot6月25日

🟡 Medium Priority

证据链:

建议:统一 L2 Cache 在大矩阵场景下的建议。两种修复方向:(A)若大矩阵应禁用 L2 Cache(与 StreamK 文档一致),将第389行改为"禁用 L2 Cache,增大 tile 尺寸";(B)若 Basic 调度器大矩阵应启用 L2 Cache,将第148行 ALL_L2_CACHE_DISABLE 的场景恢复为"小矩阵场景"。需要结合实际代码逻辑确认正确方向。

likedislike
不准确?
林旭
林旭
6月25日 评论:
225- 
226-**示例**
227-```
228-// 默认配置
229-l2CacheDisable = L2CacheMode::L2_CACHE_DEFAULT
230- 
231-// 禁用 A 矩阵 L2Cache
232-l2CacheDisable = L2CacheMode::A_L2_CACHE_DISABLE
233- 
234-// 禁用所有 L2Cache
235-l2CacheDisable = L2CacheMode::ALL_L2_CACHE_DISABLE
236-```
237 149 
238#### 7. 非连续场景参数 (sliceM, srcNdStride, innerBatch)150#### 7. 非连续场景参数 (sliceM, srcNdStride, innerBatch)
239 151 
@@ -244,137 +156,35 @@ l2CacheDisable = L2CacheMode::ALL_L2_CACHE_DISABLE
244|------|------|----------|156|------|------|----------|
245| sliceM | M 轴 slice 尺寸 | 非 ND 连续格式 |157| sliceM | M 轴 slice 尺寸 | 非 ND 连续格式 |
246| srcNdStride | M 轴 stride | 非 ND 连续格式 |158| srcNdStride | M 轴 stride | 非 ND 连续格式 |
247-| innerBatch | transpose 内轴 batch | transpose 场景 |159+| innerBatch | transpose 场景内轴 batch | transpose 场景 |
atomgit-bot
atomgit-botatomgit-bot6月25日

🟡 Medium Priority

变更行(第159行):表格中 innerBatch 参数的描述为 "非 transpose 场景内轴 batch",而适用场景列为 "transpose 场景"。

证据链:

  • 源代码 include/blaze/gemm/block/block_scheduler_matmul_basic.h 第50行注释为 // 非连续transpose场景内轴batch值,意为"非连续格式下的转置场景内轴 batch 值"
  • 文档描述丢失了关键的 "非连续" 修饰语,并将 "transpose" 误改为 "非 transpose"(non-transpose)
  • 表格中描述列说 "非 transpose 场景",场景列却说 "transpose 场景"——两者直接矛盾

影响:读者无法判断 innerBatch 究竟是用于 transpose 场景还是非 transpose 场景。根据源码注释,该参数的正确用途是:在非连续(非 ND)格式的 transpose 场景中设置内轴 batch 值。文档的描述和场景产生了自相矛盾,可能导致参数配置错误。

修复方案:将描述修改为 "非连续场景 transpose 内轴 batch",与源代码注释含义一致。

建议:将 innerBatch 的描述从 "非 transpose 场景内轴 batch" 改为 "非连续场景 transpose 内轴 batch"。

改动建议
159
- | innerBatch | 非 transpose 场景内轴 batch | transpose 场景 |
159
+ | innerBatch | 非连续场景 transpose 内轴 batch | transpose 场景 |
应用建议
likedislike
不准确?
248 160 
249**判断逻辑**161**判断逻辑**
250```162```
251isSlice_ = (srcNdStride != 1 && sliceM != 0)163isSlice_ = (srcNdStride != 1 && sliceM != 0)
252```164```
253 165 
254-**示例**:166+## 类型别名
255-```
256-// 连续 ND 格式(默认)
257-sliceM=0, srcNdStride=0 // isSlice_ = false
258 167 
259-// ND 连续格式168+| 类型 | 说明 |
260-sliceM=64, srcNdStride=128 // isSlice_ = true169+|------|------|
261-```170+| BlockShape | Block 形状:`Shape<int64_t, int64_t, int64_t, int64_t>` |
262- 171+| BlockL1L0Shape | Block L1/L0 形状:`Shape<int64_t, int64_t, int64_t, int64_t, int64_t, int64_t>` |
263-## SplitK 切分172+| BlockCoord | Block 坐标:`Coord<int64_t, int64_t, int64_t, int64_t>` (mOffset, nOffset, mOffsetNonContiguous, batchIdx) |
264- 173+| ProblemShape | 问题规模类型(模板参数) |
265-### 触发条件
266-```
267-isFp32_ && !isHf32_ && isNdFormat_ && k_ > fp32SplitKThreshold && FullLoadMode_ == 0
268-```
269- 
270-### 阈值配置
271-| 常量 | 值 | 说明 |
272-|------|-----|------|
273-| FP32_K_SWITCH_THRESHOLD | 268435456 | 大 K 阈值切换点 |
274-| FP32_SPLIT_K_THRESHOLD1 | 1024 | 小 K 场景切分阈值 |
275-| FP32_SPLIT_K_THRESHOLD2 | 8192 | 大 K 场景切分阈值 |
276- 
277-### 切分逻辑
278-```
279-if (k_ > FP32_K_SWITCH_THRESHOLD) {
280- splitSingleK_ = FP32_SPLIT_K_THRESHOLD2; // 8192
281-} else {
282- splitSingleK_ = FP32_SPLIT_K_THRESHOLD1; // 1024
283-}
284- 
285-splitSingleKRound_ = CeilDiv(k_, splitSingleK_);
286-splitSingleKTail_ = k_ % splitSingleK_ + splitSingleK_;
287-```
288- 
289-### 示意图
290-```
291-SplitK 切分示意(k=20480, splitSingleK_=8192)
292- 
293-┌─────────────────────────────────────────────────────────────┐
294-│ K 轴 (k=20480) │
295-│ ┌─────────────────┐ │
296-│ │ Round 0 │ kOffset=0 │
297-│ │ 0~8191 │ blkK_=8192 │
298-│ └─────────────────┘ │
299-│ ┌─────────────────┐ │
300-│ │ Round 1 │ kOffset=8192 │
301-│ │ 8192~16383 │ blkK_=8192 │
302-│ └─────────────────┘ │
303-│ ┌─────────────────┐ │
304-│ │ Round 2 (Tail) │ kOffset=16384 │
305-│ │ 16384~20479 │ blkK_=4096 │
306-│ └─────────────────┘ │
307-└─────────────────────────────────────────────────────────────┘
308- 
309-splitSingleKRound_ = 3
310-splitSingleKTail_ = 4096
311-```
312- 
313-## Z 型扫描
314- 
315-### 扫描逻辑
316-```
317-// 奇数行反向扫描
318-if (rowIdx % 2 != 0) {
319- nTileIdx_ = nTileNum_ - 1 - nTileIdx_;
320-}
321-```
322- 
323-### 示意图
324-```
325-Z 型扫描示意(mTileNum_=4, nTileNum_=4)
326- 
327- N轴 →
328- ┌──┬──┬──┬──┐
329- │0 │1 │2 │3 │ ← Row 0(正向)
330-M ├──┼──┼──┼──┤
331-轴 │7 │6 │5 │4 │ ← Row 1(反向)
332-↓ ├──┼──┼──┼──┤
333- │8 │9 │10│11│ ← Row 2(正向)
334- ├──┼──┼──┼──┤
335- │15│14│13│12│ ← Row 3(反向)
336- └──┴──┴──┴──┘
337- 
338-扫描顺序:0→1→2→3→7→6→5→4→8→9→10→11→15→14→13→12
339-```
340- 
341-### 窗口扫描
342-```
343-mainWindow_ = 4 (窗口长度)
344-mainRow_ = mTileNum_ / mainWindow_ - 1
345-tailWindow_ = mTileNum_ - mainRow_ * mainWindow_
346- 
347-示例(mTileNum_=10):
348- mainWindow_ = 4
349- mainRow_ = 2
350- tailWindow_ = 2
351- 
352-扫描区域:
353- Row 0-1:mainWindow_=4 正常扫描
354- Row 2:tailWindow_=2 扫描
355-```
356 174 
357## 构造函数175## 构造函数
358 176 
359```cpp177```cpp
360__aicore__ inline BlockSchedulerMatmulBasic(178__aicore__ inline BlockSchedulerMatmulBasic(
361 const ProblemShape& shape, // 问题规模 (m, n, k, batch)179 const ProblemShape& shape, // 问题规模 (m, n, k, batch)
362- int64_t blockIdx, // 当前 Block 索引180+ const Params& params) // 参数
363- int64_t blockNum, // 总 Block 数量
364- const Params& params, // 参数
365- bool isFp32 = false, // 是否为 FP32
366- bool isNdFormat = true) // 是否为 ND 格式
367```181```
368 182 
369### 参数说明183### 参数说明
370| 参数 | 类型 | 说明 |184| 参数 | 类型 | 说明 |
371|------|------|------|185|------|------|------|
372| shape | ProblemShape | 问题规模 `(m, n, k, batch)` |186| shape | ProblemShape | 问题规模 `(m, n, k, batch)` |
373-| blockIdx | int64_t | 当前 Block 索引(`GetBlockIdx()`) |
374-| blockNum | int64_t | 总 Block 数量 |
375| params | Params | 调度参数 |187| params | Params | 调度参数 |
376-| isFp32 | bool | 是否为 FP32(影响 SplitK 切分) |
377-| isNdFormat | bool | 是否为 ND 格式(影响尾块切分) |
378 188 
379### 执行流程189### 执行流程
380```190```
@@ -388,13 +198,7 @@ __aicore__ inline BlockSchedulerMatmulBasic(
3888. 计算扫描窗口:mainWindow_, mainRow_, tailWindow_1988. 计算扫描窗口:mainWindow_, mainRow_, tailWindow_
389```199```
390 200 
391-## 成员方法201+## 公共成员方法(Public API)
392- 
393-### DisableSplitSingleK
394-```cpp
395-__aicore__ inline void DisableSplitSingleK()
396-```
397-功能:禁用 SplitK 切分。
398 202 
399### GetTileNum203### GetTileNum
400```cpp204```cpp
@@ -402,36 +206,12 @@ __aicore__ inline int64_t GetTileNum()
402```206```
403功能:返回总 tile 数量(`tileNum_ * batch_`)。207功能:返回总 tile 数量(`tileNum_ * batch_`)。
404 208 
405-### Gethf32Flag
406-```cpp
407-__aicore__ inline bool Gethf32Flag()
408-```
409-功能:返回 HF32 模式标志(`isHf32_ > 0`)。
410- 
411-### GetL1BuferNum_
412-```cpp
413-__aicore__ inline uint64_t GetL1BuferNum_()
414-```
415-功能:返回 L1 缓冲数量。
416- 
417-### GetTileL1Shape
418-```cpp
419-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL1Shape()
420-```
421-功能:返回 L1 tile 形状 `{mL1_, nL1_, kL1_, 1}`
422- 
423-### GetTileL0Shape
424-```cpp
425-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL0Shape()
426-```
427-功能:返回 L0 tile 形状 `{baseM_, baseN_, baseK_, 1}`
428- 
429### GetBlockNum209### GetBlockNum
430```cpp210```cpp
431-__aicore__ inline int64_t GetBlockNum(ProblemShape shape, int64_t blockNum)211+__aicore__ inline int64_t GetBlockNum(ProblemShape shape)
432```212```
433功能:返回实际使用的 Block 数量(不超过 tile 总数)。213功能:返回实际使用的 Block 数量(不超过 tile 总数)。
434-返回值:`min(tileNum_ * batch_, blockNum)`214+返回值:`min(tileNum_ * batch_, blockNum_)`
435 215 
436### GetBlockShape216### GetBlockShape
437```cpp217```cpp
@@ -442,6 +222,20 @@ __aicore__ inline BlockL1L0Shape GetBlockShape(
442功能:返回当前 tile 的 Block 形状。222功能:返回当前 tile 的 Block 形状。
443返回值:`BlockL1L0Shape {mL1, nL1, k, batch, mL0, nL0}`223返回值:`BlockL1L0Shape {mL1, nL1, k, batch, mL0, nL0}`
444 224 
225+参数说明:
226+| 参数 | 类型 | 说明 |
227+|------|------|------|
228+| tileIdx | int64_t | tile 索引 |
229+| mOffset | int64_t | M 轴偏移(默认 0) |
230+| nOffset | int64_t | N 轴偏移(默认 0) |
231+| kOffset | int64_t | K 轴偏移(默认 0,用于 SplitK) |
232+ 
233+模板参数说明:
234+| 参数 | 说明 |
235+|------|------|
236+| TransB_ | B 矩阵是否转置(默认 false) |
237+| B_T | B 矩阵数据类型 |
238+ 
445### GetBlockCoord239### GetBlockCoord
446```cpp240```cpp
447__aicore__ inline BlockCoord GetBlockCoord(int tileIdx)241__aicore__ inline BlockCoord GetBlockCoord(int tileIdx)
@@ -449,42 +243,10 @@ __aicore__ inline BlockCoord GetBlockCoord(int tileIdx)
449功能:返回当前 tile 的 Block 坐标。243功能:返回当前 tile 的 Block 坐标。
450返回值:`BlockCoord {mOffset, nOffset, mOffsetNonContiguous, batchIdx}`244返回值:`BlockCoord {mOffset, nOffset, mOffsetNonContiguous, batchIdx}`
451 245 
452-### GetSplitKBlockCoord246+参数说明:
453-```cpp247+| 参数 | 类型 | 说明 |
454-__aicore__ inline BlockCoord GetSplitKBlockCoord(int tileIdx)248+|------|------|------|
455-```249+| tileIdx | int | tile 索引 |
456-功能:返回 SplitK 场景的 Block 坐标。
457-返回值:`BlockCoord {mOffset, nOffset, kOffset, batchIdx}`
458- 
459-### GetSplitOffset
460-```cpp
461-__aicore__ inline Shape<int64_t, int64_t> GetSplitOffset()
462-```
463-功能:返回尾块切分偏移 `{mSplitOffset_, nSplitOffset_}`
464- 
465-### GetNonContinuousParams
466-```cpp
467-__aicore__ inline Shape<int64_t, int64_t, int64_t> GetNonContinuousParams()
468-```
469-功能:返回非连续场景参数 `{sliceM_, srcNdStride_, innerBatch_}`
470- 
471-### GetTailParams
472-```cpp
473-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTailParams()
474-```
475-功能:返回尾块参数 `{mL1NormCnt_, mL1TailMain_, nL1NormCnt_, nL1TailMain_}`
476- 
477-### GetL0cDB / GetUbDB
478-```cpp
479-__aicore__ inline bool GetL0cDB() // 返回 L0C 双缓冲标志(l0cDB_ > 1)
480-__aicore__ inline bool GetUbDB() // 返回 UB 双缓冲标志(ubDB_ > 1)
481-```
482- 
483-### GetAL2CacheDisable / GetBL2CacheDisable
484-```cpp
485-__aicore__ inline bool GetAL2CacheDisable() // 返回 A 矩阵 L2Cache 禁用标志
486-__aicore__ inline bool GetBL2CacheDisable() // 返回 B 矩阵 L2Cache 禁用标志
487-```
488 250 
489## 调用示例251## 调用示例
490 252 
@@ -518,13 +280,11 @@ BlockScheduler::Params params = {
518 .mTailMain = 1,280 .mTailMain = 1,
519 .nTailMain = 1,281 .nTailMain = 1,
520 282 
521- // 双缓冲283+ // HF32 模式
522- .l1BufferNum = 2,284+ .isHf32 = 0,
523- .l0cDB = 2,
524- .ubDB = 2,
525 285 
526- // L2Cache286+ // L2 Cache
527- .l2CacheDisable = L2CacheMode::L2_CACHE_DEFAULT,287+ .l2CacheMode = L2_CACHE_DEFAULT,
528 288 
529 // 非连续场景(连续 ND 格式不需要设置)289 // 非连续场景(连续 ND 格式不需要设置)
530 .sliceM = 0,290 .sliceM = 0,
@@ -536,17 +296,13 @@ BlockScheduler::Params params = {
536### 组件初始化296### 组件初始化
537```cpp297```cpp
538ProblemShape shape{m, n, k, batch};298ProblemShape shape{m, n, k, batch};
539-int64_t blockIdx = GetBlockIdx();299+BlockScheduler scheduler(shape, params);
540-int64_t blockNum = GetBlockNum();
541-bool isFp32 = false; // 非 FP32 场景
542-bool isNdFormat = true; // ND 格式
543- 
544-BlockScheduler scheduler(shape, blockIdx, blockNum, params, isFp32, isNdFormat);
545```300```
546 301 
547### 获取 tile 数量302### 获取 tile 数量
548```cpp303```cpp
549int64_t tileNum = scheduler.GetTileNum();304int64_t tileNum = scheduler.GetTileNum();
305+int64_t blockNum = scheduler.GetBlockNum(shape);
550for (int64_t tileIdx = blockIdx; tileIdx < tileNum; tileIdx += blockNum) {306for (int64_t tileIdx = blockIdx; tileIdx < tileNum; tileIdx += blockNum) {
551 // 处理 tile307 // 处理 tile
552}308}
@@ -556,27 +312,72 @@ for (int64_t tileIdx = blockIdx; tileIdx < tileNum; tileIdx += blockNum) {
556```cpp312```cpp
557using B_T = half;313using B_T = half;
558bool TransB = false;314bool TransB = false;
559-auto blockShape = scheduler.GetBlockShape<TransB, B_T>(tileIdx, mOffset, nOffset, kOffset);315+auto blockShape = scheduler.GetBlockShape<TransB, B_T>(tileIdx);
560int64_t mL1 = Get<0>(blockShape);316int64_t mL1 = Get<0>(blockShape);
561int64_t nL1 = Get<1>(blockShape);317int64_t nL1 = Get<1>(blockShape);
562int64_t kL1 = Get<2>(blockShape);318int64_t kL1 = Get<2>(blockShape);
319+int64_t batch = Get<3>(blockShape);
563int64_t mL0 = Get<4>(blockShape);320int64_t mL0 = Get<4>(blockShape);
564int64_t nL0 = Get<5>(blockShape);321int64_t nL0 = Get<5>(blockShape);
565```322```
566 323 
567### 获取 Block 坐标324### 获取 Block 坐标
568```cpp325```cpp
569-// 正常场景
570auto blockCoord = scheduler.GetBlockCoord(tileIdx);326auto blockCoord = scheduler.GetBlockCoord(tileIdx);
571int64_t mOffset = Get<0>(blockCoord);327int64_t mOffset = Get<0>(blockCoord);
572int64_t nOffset = Get<1>(blockCoord);328int64_t nOffset = Get<1>(blockCoord);
573int64_t batchIdx = Get<3>(blockCoord);329int64_t batchIdx = Get<3>(blockCoord);
574- 
575-// SplitK 场景
576-auto splitKCoord = scheduler.GetSplitKBlockCoord(tileIdx);
577-int64_t kOffset = Get<2>(splitKCoord);
578```330```
579 331 
332+## 数据流
333+ 
334+### Z 型扫描
335+```
336+// 奇数行反向扫描
337+if (rowIdx % 2 != 0) {
338+ nTileIdx_ = nTileNum_ - 1 - nTileIdx_;
339+}
340+```
341+ 
342+**示意图**
343+```
344+Z 型扫描示意(mTileNum_=4, nTileNum_=4)
345+ 
346+ N轴 →
347+ ┌──┬──┬──┬──┐
348+ │0 │1 │2 │3 │ ← Row 0(正向)
349+M ├──┼──┼──┼──┤
350+轴 │7 │6 │5 │4 │ ← Row 1(反向)
351+↓ ├──┼──┼──┼──┤
352+ │8 │9 │10│11│ ← Row 2(正向)
353+ ├──┼──┼──┼──┤
354+ │15│14│13│12│ ← Row 3(反向)
355+ └──┴──┴──┴──┘
356+ 
357+扫描顺序:0→1→2→3→7→6→5→4→8→9→10→11→15→14→13→12
358+```
359+ 
360+### 窗口扫描
361+```
362+mainWindow_ = 4 (窗口长度)
363+mainRow_ = mTileNum_ / mainWindow_ - 1
364+tailWindow_ = mTileNum_ - mainRow_ * mainWindow_
365+```
366+ 
367+## SplitK 切分
368+ 
369+### 触发条件
370+```
371+IsFp32_ && !isHf32_ && IsNdFormat_ && k_ > fp32SplitKThreshold && FullLoadMode_ == 0 && !isSlice_
372+```
373+ 
374+### 阈值配置
375+| 常量 | 值 | 说明 |
376+|------|-----|------|
377+| FP32_K_SWITCH_THRESHOLD | 268435456 | 大 K 阈值切换点 |
378+| FP32_SPLIT_K_THRESHOLD1 | 1024 | 小 K 场景切分阈值 |
379+| FP32_SPLIT_K_THRESHOLD2 | 8192 | 大 K 场景切分阈值 |
380+ 
580## 适用场景381## 适用场景
581 382 
582| 场景 | 配置建议 |383| 场景 | 配置建议 |
@@ -584,5 +385,5 @@ int64_t kOffset = Get<2>(splitKCoord);
584| Basic Kernel | FullLoadMode=0,默认配置 |385| Basic Kernel | FullLoadMode=0,默认配置 |
585| FP32 大 K | isFp32=true,启用 SplitK |386| FP32 大 K | isFp32=true,启用 SplitK |
586| 尾块优化 | batch=1,设置 mTailCnt/nTailCnt |387| 尾块优化 | batch=1,设置 mTailCnt/nTailCnt |
587-| 小矩阵 | 禁用 L2Cache,减小 tile 尺寸 |388+| 小矩阵 | 禁用 L2 Cache,减小 tile 尺寸 |
588-| 大矩阵 | 启用双缓冲,增大 tile 尺寸 |389+| 大矩阵 | 启用 L2 Cache(默认),增大 tile 尺寸 |
@@ -37,16 +37,20 @@ SK 模式:CeilDiv((tileIdx + 1), usedCoreNum_) == CeilDiv(tileNum_, usedCoreNu
37- **Batch 索引**:在 tile 循环中由 Kernel 层处理37- **Batch 索引**:在 tile 循环中由 Kernel 层处理
38 38 
39### Z 型扫描39### Z 型扫描
40-与 Swat 调度器相同,使用 Z 型扫描策略:40+使用 Z 型扫描策略:
41-- **WINDOW_LEN = 4**:扫描窗口大小
42- **正向扫描**:偶数行(rowIdx % 2 == 0)41- **正向扫描**:偶数行(rowIdx % 2 == 0)
43- **反向扫描**:奇数行(rowIdx % 2 != 0)42- **反向扫描**:奇数行(rowIdx % 2 != 0)
44 43 
45### HF32 模式44### HF32 模式
46支持 HF32 计算模式:45支持 HF32 计算模式:
47-- **isHf32_**:HF32 标志(从 params 传入)46+- **isHf32_**:HF32 标志(uint8_t,从 params 传入)
48- **GetHf32Flag()**:返回 HF32 标志47- **GetHf32Flag()**:返回 HF32 标志
49 48 
49+### L2 Cache 配置
50+支持 L2 Cache 配置:
51+- **l2CacheMode_**:L2 Cache 模式(从 params 传入)
52+- **GetL2CacheMode()**:返回 L2 Cache 模式
53+ 
50## 特殊静态常量54## 特殊静态常量
51 55 
52| 常量 | 说明 |56| 常量 | 说明 |
@@ -61,25 +65,30 @@ SK 模式:CeilDiv((tileIdx + 1), usedCoreNum_) == CeilDiv(tileNum_, usedCoreNu
61| BlockCoord | Block 坐标:`Coord<int64_t, int64_t, int64_t, int64_t>` (mTileIdx, nTileIdx, kTileIdx, 0) |65| BlockCoord | Block 坐标:`Coord<int64_t, int64_t, int64_t, int64_t>` (mTileIdx, nTileIdx, kTileIdx, 0) |
62| ProblemShape | 问题规模类型(模板参数) |66| ProblemShape | 问题规模类型(模板参数) |
63 67 
64-## 特殊结构68+## Params 参数结构
65 69 
66-### Params70+### 结构定义
67-```71+```cpp
68struct Params {72struct Params {
69- int64_t usedCoreNum{0}; // 使用的核数73+ int64_t usedCoreNum{0}; // 使用的核数
70- int64_t baseM{0}; // L0 M 维度 base 大小74+ int64_t baseM{0}; // L0 M 维度 base 大小
71- int64_t baseN{0}; // L0 N 维度 base 大小75+ int64_t baseN{0}; // L0 N 维度 base 大小
72- int64_t baseK{0}; // L0 K 维度 base 大小(固定 32)76+ int64_t baseK{0}; // L0 K 维度 base 大小
73- int64_t singleCoreK{0}; // SK 模式下单核处理的 K 大小77+ int64_t singleCoreK{0}; // SK 模式下单核处理的 K 大小
74- int64_t kL1{0}; // L1 K 维度大小78+ int64_t kL1{0}; // L1 K 维度大小
75- int64_t isHf32{0}; // HF32 模式标志79+ uint8_t isHf32{0}; // HF32 模式标志
80+ uint32_t l2CacheMode = L2_CACHE_DEFAULT; // L2 Cache 配置
76};81};
77```82```
78 83 
79说明:84说明:
80- `usedCoreNum`:参与计算的 AIC 核数量85- `usedCoreNum`:参与计算的 AIC 核数量
81-- `singleCoreK`:SK 模式下每个核处理的 K 维大小(用于 K 轴切分)86+- `baseM` / `baseN` / `baseK`:L0 base 形状
87+- `singleCoreK`:SK 模式下单核处理的 K 维大小(用于 K 轴切分)
88+- `kL1`:L1 K 维度大小
82- `baseK`:固定为 32,需根据 baseM, baseN, L0 调整89- `baseK`:固定为 32,需根据 baseM, baseN, L0 调整
90+- `isHf32`:HF32 模式标志(uint8_t 类型)
91+- `l2CacheMode`:L2 Cache 配置模式
83 92 
84## 特殊成员变量93## 特殊成员变量
85 94 
@@ -94,7 +103,8 @@ struct Params {
94| kTileIdx_ | 当前 K 轴切分索引(SK 模式) |103| kTileIdx_ | 当前 K 轴切分索引(SK 模式) |
95| curKTileNum_ | 当前 K 轴 tile 数量(DP=1, SK=skKTileNum_) |104| curKTileNum_ | 当前 K 轴 tile 数量(DP=1, SK=skKTileNum_) |
96| skSingleCoreK_ | SK 模式单核 K 大小 |105| skSingleCoreK_ | SK 模式单核 K 大小 |
97-| isHf32_ | HF32 模式标志 |106+| isHf32_ | HF32 模式标志(uint8_t) |
107+| l2CacheMode_ | L2 Cache 配置模式 |
98 108 
99## 特殊成员方法109## 特殊成员方法
100 110 
@@ -107,7 +117,7 @@ __aicore__ inline BlockSchedulerMatmulStreamK(const ProblemShape& shape, const P
107| 参数 | 类型 | 说明 |117| 参数 | 类型 | 说明 |
108|------|------|------|118|------|------|------|
109| shape | ProblemShape | 问题规模 `(m, n, k, batch)` |119| shape | ProblemShape | 问题规模 `(m, n, k, batch)` |
110-| params | Params | 调度参数(usedCoreNum, baseM, baseN, baseK, singleCoreK, kL1, isHf32) |120+| params | Params | 调度参数(usedCoreNum, baseM, baseN, baseK, singleCoreK, kL1, isHf32, l2CacheMode) |
111 121 
112执行流程:122执行流程:
1131. 设置问题规模:`m_`, `n_`, `k_`, `batch_`1231. 设置问题规模:`m_`, `n_`, `k_`, `batch_`
@@ -117,30 +127,26 @@ __aicore__ inline BlockSchedulerMatmulStreamK(const ProblemShape& shape, const P
117 - `tailMNTileNum = (mTileNum_ × nTileNum_) % usedCoreNum_`(SK 模式 tile 数量)127 - `tailMNTileNum = (mTileNum_ × nTileNum_) % usedCoreNum_`(SK 模式 tile 数量)
118 - `totalMNTileNumInDP_ = mTileNum_ × nTileNum_ - tailMNTileNum`(DP 模式 tile 数量)128 - `totalMNTileNumInDP_ = mTileNum_ × nTileNum_ - tailMNTileNum`(DP 模式 tile 数量)
119 - `tileNum_ = totalMNTileNumInDP_ + tailMNTileNum × skKTileNum_`(总 tile 数量)129 - `tileNum_ = totalMNTileNumInDP_ + tailMNTileNum × skKTileNum_`(总 tile 数量)
130+5. 设置 HF32 和 L2 Cache 模式:`isHf32_`, `l2CacheMode_`
120 131 
121-### GetTotalTileNum132+### GetTileNum
122```133```
123-__aicore__ inline int64_t GetTotalTileNum()134+__aicore__ inline int64_t GetTileNum()
124```135```
125功能:返回总 tile 数量(`tileNum_ × batch_`)。136功能:返回总 tile 数量(`tileNum_ × batch_`)。
126 137 
127### GetHf32Flag138### GetHf32Flag
128```139```
129-__aicore__ inline int64_t GetHf32Flag()140+__aicore__ inline uint8_t GetHf32Flag()
130```141```
131功能:返回 HF32 模式标志(`isHf32_`)。142功能:返回 HF32 模式标志(`isHf32_`)。
132 143 
133-### GetTileL1Shape144+### GetL2CacheMode
134```145```
135-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL1Shape()146+__aicore__ inline uint32_t GetL2CacheMode()
136```147```
137-功能:返回 L1 tile 形状 `{mL1_, nL1_, kL1_, 1}`。148+功能:返回 L2 Cache 配置模式(`l2CacheMode_`
138 149 
139-### GetTileL0Shape
140-```
141-__aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL0Shape()
142-```
143-功能:返回 L0 tile 形状 `{baseM_, baseN_, baseK_, 1}`
144 150 
145### GetMNKTileNum151### GetMNKTileNum
146```152```
@@ -168,9 +174,9 @@ __aicore__ inline int64_t GetCurKSingleCore(int64_t tileIdx)
168- **DP 模式**`k_`(完整 K)174- **DP 模式**`k_`(完整 K)
169- **SK 模式**`skSingleCoreK_`(切分 K)175- **SK 模式**`skSingleCoreK_`(切分 K)
170 176 
171-### GetSingleCoreShape177+### GetBlockShape
172```178```
173-__aicore__ inline BlockShape GetSingleCoreShape(int64_t tileIdx)179+__aicore__ inline BlockShape GetBlockShape(int64_t tileIdx)
174```180```
175功能:返回当前 tile 的单核形状。181功能:返回当前 tile 的单核形状。
176参数说明:182参数说明:
@@ -185,9 +191,9 @@ __aicore__ inline BlockShape GetSingleCoreShape(int64_t tileIdx)
185- **DP 模式**`blkK = k_`(完整 K)191- **DP 模式**`blkK = k_`(完整 K)
186- **SK 模式**`blkK = skSingleCoreK_``tailSingleCoreK`192- **SK 模式**`blkK = skSingleCoreK_``tailSingleCoreK`
187 193 
188-### GetSingleCoreCoord194+### GetBlockCoord
189```195```
190-__aicore__ inline BlockCoord GetSingleCoreCoord(int64_t tileIdx)196+__aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx)
191```197```
192功能:返回当前 tile 的单核坐标。198功能:返回当前 tile 的单核坐标。
193参数说明:199参数说明:
@@ -253,7 +259,8 @@ BlockScheduler::Params params = {
253 baseK, // L0 K 维度 base(如 32)259 baseK, // L0 K 维度 base(如 32)
254 singleCoreK, // SK 模式单核 K 大小(如 k_ / 4)260 singleCoreK, // SK 模式单核 K 大小(如 k_ / 4)
255 kL1, // L1 K 维度(如 baseK)261 kL1, // L1 K 维度(如 baseK)
256- isHf32 // HF32 模式(0 或 1)262+ isHf32, // HF32 模式(uint8_t,0 或 1)
263+ l2CacheMode // L2 Cache 配置
257};264};
258```265```
259 266 
@@ -265,7 +272,7 @@ BlockScheduler scheduler(shape, params);
265 272 
266### 获取 tile 数量273### 获取 tile 数量
267```274```
268-int64_t tileNum = scheduler.GetTotalTileNum();275+int64_t tileNum = scheduler.GetTileNum();
269int64_t blockNum = scheduler.GetBlockNum(GetBlockNum());276int64_t blockNum = scheduler.GetBlockNum(GetBlockNum());
270for (int64_t tileIdx = GetBlockIdx(); tileIdx < tileNum; tileIdx += blockNum) {277for (int64_t tileIdx = GetBlockIdx(); tileIdx < tileNum; tileIdx += blockNum) {
271 // 处理 tile278 // 处理 tile
@@ -284,7 +291,7 @@ if (isSkScene) {
284 291 
285### 获取单核形状292### 获取单核形状
286```293```
287-auto singleCoreShape = scheduler.GetSingleCoreShape(tileIdx);294+auto singleCoreShape = scheduler.GetBlockShape(tileIdx);
288int64_t blkM = Get<0>(singleCoreShape);295int64_t blkM = Get<0>(singleCoreShape);
289int64_t blkN = Get<1>(singleCoreShape);296int64_t blkN = Get<1>(singleCoreShape);
290int64_t blkK = Get<2>(singleCoreShape);297int64_t blkK = Get<2>(singleCoreShape);
@@ -292,7 +299,7 @@ int64_t blkK = Get<2>(singleCoreShape);
292 299 
293### 获取单核坐标300### 获取单核坐标
294```301```
295-auto singleCoreCoord = scheduler.GetSingleCoreCoord(tileIdx);302+auto singleCoreCoord = scheduler.GetBlockCoord(tileIdx);
296int64_t mTileIdx = Get<0>(singleCoreCoord);303int64_t mTileIdx = Get<0>(singleCoreCoord);
297int64_t nTileIdx = Get<1>(singleCoreCoord);304int64_t nTileIdx = Get<1>(singleCoreCoord);
298int64_t kTileIdx = Get<2>(singleCoreCoord); // SK 模式有效305int64_t kTileIdx = Get<2>(singleCoreCoord); // SK 模式有效
@@ -307,9 +314,8 @@ int64_t curK = scheduler.GetCurKSingleCore(tileIdx);
307 314 
308### 获取配置315### 获取配置
309```316```
310-int64_t hf32Flag = scheduler.GetHf32Flag();317+uint8_t hf32Flag = scheduler.GetHf32Flag();
311-auto tileL1Shape = scheduler.GetTileL1Shape();318+uint32_t l2CacheMode = scheduler.GetL2CacheMode();
312-auto tileL0Shape = scheduler.GetTileL0Shape();
313auto mnkTileNum = scheduler.GetMNKTileNum();319auto mnkTileNum = scheduler.GetMNKTileNum();
314```320```
315 321 
@@ -341,7 +347,7 @@ curKTileNum = 1(不切分 K)
341347
342kTileIdx = 0348kTileIdx = 0
343349
344-GetSingleCoreShape:blkK = k_(完整 K)350+GetBlockShape:blkK = k_(完整 K)
345351
346BlockMmad:输出到 GM352BlockMmad:输出到 GM
347```353```
@@ -354,7 +360,7 @@ curKTileNum = skKTileNum(K 轴切分)
354360
355kTileIdx = (tileIdx % usedCoreNum) % curKTileNum361kTileIdx = (tileIdx % usedCoreNum) % curKTileNum
356362
357-GetSingleCoreShape:blkK = skSingleCoreK_ 或 tailSingleCoreK363+GetBlockShape:blkK = skSingleCoreK_ 或 tailSingleCoreK
358364
359BlockMmad:输出到 workspace365BlockMmad:输出到 workspace
360366
@@ -401,6 +407,13 @@ rowIdx % 2 != 0:反向扫描(nTileIdx = nTileNum - 1 - nTileIdx)
401- **isHf32 = 1**:启用 HF32 计算模式407- **isHf32 = 1**:启用 HF32 计算模式
402- **适用场景**:需要高精度计算的 FP32 场景408- **适用场景**:需要高精度计算的 FP32 场景
403 409 
410+### L2 Cache 配置
411+- **L2_CACHE_DEFAULT**:L2 Cache 使能(默认)
412+- **A_L2_CACHE_DISABLE**:禁用 A 矩阵 L2 Cache
413+- **B_L2_CACHE_DISABLE**:禁用 B 矩阵 L2 Cache
414+- **ALL_L2_CACHE_DISABLE**:禁用所有 L2 Cache
415+- **适用场景**:大矩阵场景建议禁用 L2 Cache 避免缓存污染
416+ 
404### 适用场景417### 适用场景
405- **StreamK Kernel**:AIC + AIV 双核协同418- **StreamK Kernel**:AIC + AIV 双核协同
406- **大矩阵场景**:(m × n × k) 较大,需要多核并行419- **大矩阵场景**:(m × n × k) 较大,需要多核并行
@@ -13,7 +13,7 @@
13 13 
14所有 Kernel 组件基于 [kernel.md](./kernel.md) 公共框架实现,包含统一的:14所有 Kernel 组件基于 [kernel.md](./kernel.md) 公共框架实现,包含统一的:
15- 模板参数15- 模板参数
16-- 数据结构(Params、Arguments16+- 数据结构(Params)
17- 核心方法(Init、operator)17- 核心方法(Init、operator)
18 18 
19详见:[kernel.md](./kernel.md)19详见:[kernel.md](./kernel.md)
@@ -70,15 +70,6 @@ struct Params {
70};70};
71```71```
72 72 
73-#### Arguments
74-```
75-struct Arguments {
76- ProblemShape problemShape; // 问题 shape (m, n, k, batch)
77- BlockMmadArguments mmadArgs; // mmad 参数
78- BlockEpilogueArguments epilogueArgs; // epilogue 参数
79-};
80-```
81- 
82### 核心成员变量73### 核心成员变量
83| 变量 | 类型 | 说明 |74| 变量 | 类型 | 说明 |
84|------|------|------|75|------|------|------|
@@ -4,19 +4,19 @@
4## 功能说明4## 功能说明
5基础矩阵乘 Kernel,仅支持 AIC 计算,无 AIV 参与,不支持 workspace。适用于小矩阵、简单计算场景,集成 BlockScheduler 调度、BlockMmad 计算和 BlockEpilogueEmpty 后处理组件。5基础矩阵乘 Kernel,仅支持 AIC 计算,无 AIV 参与,不支持 workspace。适用于小矩阵、简单计算场景,集成 BlockScheduler 调度、BlockMmad 计算和 BlockEpilogueEmpty 后处理组件。
6 6 
7-**继承自**:[Kernel Matmul 基础框架](./kernel.md)7+**继承自**:GemmUniversal 基础模板(特化实现)
8 8 
9## 特殊约束9## 特殊约束
10 10 
11### BlockEpilogue 限制11### BlockEpilogue 限制
12仅支持 `Block::BlockEpilogueEmpty`,不支持任何后处理操作。12仅支持 `Block::BlockEpilogueEmpty`,不支持任何后处理操作。
13-```13+```cpp
14using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty;14using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty;
15```15```
16 16 
17### 计算模式17### 计算模式
18仅在 AIC 核函数中执行,不支持 AIV 计算(AIV 核直接返回)。18仅在 AIC 核函数中执行,不支持 AIV 计算(AIV 核直接返回)。
19-```19+```cpp
20if ASCEND_IS_AIV {20if ASCEND_IS_AIV {
21 return; // AIV 核直接返回,不执行任何计算21 return; // AIV 核直接返回,不执行任何计算
22}22}
@@ -31,70 +31,113 @@ if ASCEND_IS_AIV {
31### FP32 大 K31### FP32 大 K
32不支持 FP32 大 K 场景(K 轴切分受硬件限制),K 值过大时需使用 StreamK Kernel。32不支持 FP32 大 K 场景(K 轴切分受硬件限制),K 值过大时需使用 StreamK Kernel。
33 33 
34-## 特殊成员方法34+## 类型别名
35+ 
36+| 类型 | 说明 |
37+|------|------|
38+| BlockMmad | BlockMmadMatmulBasic 组件 |
39+| ProblemShape | 问题规模类型:`Shape<int64_t, int64_t, int64_t, int64_t>` |
40+| BlockScheduler | BlockSchedulerMatmulBasic 组件 |
41+| BlockEpilogue | BlockEpilogueEmpty 组件 |
42+| BlockMmadParams | BlockMmad::Params |
43+| BlockEpilogueParams | BlockEpilogue::Params |
44+| BlockSchedulerParams | BlockScheduler::Params |
45+| AType | A 矩阵数据类型 |
46+| BType | B 矩阵数据类型 |
47+| CType | C 矩阵输出类型 |
48+| BiasType | Bias 数据类型 |
49+| LayoutA | A 矩阵布局类型 |
50+| LayoutB | B 矩阵布局类型 |
51+| LayoutC | C 矩阵布局类型 |
52+| LayoutBias | Bias 布局类型 |
53+ 
54+## 静态常量
55+ 
56+| 常量 | 说明 |
57+|------|------|
58+| isFp32 | 是否为 FP32 类型 |
59+| C0_SIZE | Cube 单元大小(FP32=16, FP16=32) |
60+| transA | A 矩阵是否转置 |
61+| transB | B 矩阵是否转置 |
62+| weightNZFormat | B 矩阵是否为 NZ 格式 |
63+ 
64+## Params 参数结构
65+ 
66+### 结构定义
67+```cpp
68+struct Params {
69+ ProblemShape problemShape; // 问题规模 (m, n, k, batch)
70+ BlockMmadParams mmadParams; // BlockMmad 参数
71+ BlockEpilogueParams epilogueParams; // BlockEpilogue 参数(Empty 无需设置)
72+ BlockSchedulerParams schParams; // BlockScheduler 参数
73+};
74+```
75+ 
76+### 参数详解
77+ 
78+#### ProblemShape 参数
79+| 参数 | 类型 | 说明 | 示例 |
80+|------|------|------|------|
81+| m | int64_t | M 轴尺寸 | 1024 |
82+| n | int64_t | N 轴尺寸 | 1024 |
83+| k | int64_t | K 轴尺寸 | 512 |
84+| batch | int64_t | Batch 数量(0 或 1 为单 batch) | 1 |
85+ 
86+#### BlockMmad 参数
87+详见 [BlockMmadMatmulBasic Params](../block/block_mmad_matmul_basic.md#params-参数结构)
88+ 
89+#### BlockScheduler 参数
90+详见 [BlockSchedulerMatmulBasic Params](../block/block_scheduler_matmul_basic.md#params-参数结构)
91+ 
92+#### BlockEpilogue 参数
93+Empty Epilogue 无需设置参数。
94+ 
95+## 公共成员方法(Public API)
35 96 
36### 构造函数97### 构造函数
98+```cpp
99+__aicore__ inline GemmUniversal()
37```100```
38-__aicore__ inline KernelMatmulBasic()101+功能:构造 GemmUniversal(KernelMatmulBasic)对象。
39-```
40-功能:构造 KernelMatmulBasic 对象。
41 102 
42### 析构函数103### 析构函数
104+```cpp
105+__aicore__ inline ~GemmUniversal()
43```106```
44-__aicore__ inline ~KernelMatmulBasic()107+功能:析构 GemmUniversal(KernelMatmulBasic)对象。
45-```
46-功能:析构 KernelMatmulBasic 对象。
47 108 
48-### UnsetHf32函数109+### operator函数
110+```cpp
111+__aicore__ inline void operator()(Params const& params)
49```112```
50-__aicore__ inline void UnsetHf32(bool isHf32)113+功能:执行基础矩阵乘 Kernel 计算。
114+执行流程:
51```115```
52-功能:关闭 HF32 模式。116+AIV 核检查:直接返回
53-参数说明:117+
54-| 参数 | 类型 | 说明 |118+Init:设置问题规模、GM 地址
55-|------|------|------|119+
56-| isHf32 | bool | 是否启用 HF32 模式 |120+BlockScheduler 初始化
57- 121+
58-说明122+Block 索引检查超出实际数量则返回
59-- 当 `isHf32 = true` 时,调用 `AscendC::SetHF32Mode(0)` 关闭 HF32 模式123+
60-- Basic Kernel 在计算完成后自动调用此函数清理 HF32 状态124+HF32 模式设置(可选)
61- 125+
62-### HF32 模式设置流程126+BlockMmad 初始化
127+
128+创建 GM Tensor (ND/NZ layout)
129+
130+SetL2Cache:配置 L2 Cache(可选)
131+
132+遍历 tile → BlockMmad 执行(每个 tile 独立计算)
133+
134+UnsetHf32:关闭 HF32 模式
63```135```
64-// Kernel 开始时
65-if (isHf32) {
66- AscendC::SetHF32Mode(1);
67- AscendC::SetHF32TransMode(1);
68-}
69- 
70-// Kernel 结束时
71-UnsetHf32(isHf32); // 关闭 HF32 模式
72-```
73- 
74-### MM Layout Transform
75-```
76-SetMMLayoutTransform(true); // 调用 BlockMmad 前设置为列主序(适配 Fixpipe)
77-// ... BlockMmad 计算 ...
78-SetMMLayoutTransform(false); // 计算后关闭
79-```
80-说明:MM Layout Transform 用于适配 Fixpipe 输出格式,确保 L0C 数据正确搬出到 GM。
81- 
82-### L2 Cache 配置
83-```
84-// 根据 scheduler 参数禁用 A/B 的 L2 Cache
85-if (bs.GetBL2CacheDisable()) {
86- gmB.SetL2CacheHint(AscendC::Te::CacheMode::CACHE_MODE_DISABLE);
87-}
88-if (bs.GetAL2CacheDisable()) {
89- gmA.SetL2CacheHint(AscendC::Te::CacheMode::CACHE_MODE_DISABLE);
90-}
91-```
92-说明:可选禁用 A/B 矩阵的 L2 Cache,避免大矩阵场景下的缓存污染。
93 136 
94## Tile 循环策略137## Tile 循环策略
95 138 
96### Basic 特有的循环策略139### Basic 特有的循环策略
97-```140+```cpp
98for (int64_t tileIdx = curBlockIdx; tileIdx < tileNum; tileIdx += blockNum) {141for (int64_t tileIdx = curBlockIdx; tileIdx < tileNum; tileIdx += blockNum) {
99 // 每个 block 处理 tileIdx = curBlockIdx, curBlockIdx + blockNum, curBlockIdx + 2*blockNum, ...142 // 每个 block 处理 tileIdx = curBlockIdx, curBlockIdx + blockNum, curBlockIdx + 2*blockNum, ...
100 // 多 block 并行处理不同 tile143 // 多 block 并行处理不同 tile
@@ -107,21 +150,6 @@ for (int64_t tileIdx = curBlockIdx; tileIdx < tileNum; tileIdx += blockNum) {
107- **无 workspace**:每个 tile 完整计算,不依赖中间结果150- **无 workspace**:每个 tile 完整计算,不依赖中间结果
108- **无 AIC-AIV 同步**:单核计算,无需跨核同步151- **无 AIC-AIV 同步**:单核计算,无需跨核同步
109 152 
110-### BlockScheduler 功能(Basic 特有)
111-| 功能 | 说明 |
112-|------|------|
113-| GetTileNum | 获取总 tile 数量 |
114-| GetTileL1Shape | 获取 L1 tile 形状 |
115-| GetTileL0Shape | 获取 L0 tile 形状 |
116-| GetBlockNum | 计算实际需要的 block 数量 |
117-| GetBlockCoord | 获取 tile 的坐标 |
118-| GetBlockShape | 获取 tile 的形状 |
119-| Gethf32Flag | 获取 HF32 模式标志 |
120-| GetL1BuferNum | 获取 L1 缓冲数量 |
121-| GetL0cDB | 获取 L0C 双缓冲标志 |
122-| GetBL2CacheDisable | 获取 B 矩阵 L2 Cache 禁用标志 |
123-| GetAL2CacheDisable | 获取 A 矩阵 L2 Cache 禁用标志 |
124- 
125## 调用示例153## 调用示例
126 154 
127### Kernel 组装与调用155### Kernel 组装与调用
@@ -144,8 +172,7 @@ using ProblemShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
144// ============== 3. BlockScheduler 组装 ==============172// ============== 3. BlockScheduler 组装 ==============
145// FullLoadMode: 0=非全载(默认), 1=A全载, 2=B全载173// FullLoadMode: 0=非全载(默认), 1=A全载, 2=B全载
146constexpr int64_t FULL_LOAD_MODE = 0;174constexpr int64_t FULL_LOAD_MODE = 0;
147-using BlockScheduler = Blaze::Gemm::Block::BlockSchedulerMatmulBasic<175+using BlockScheduler = Blaze::Gemm::Block::BlockSchedulerMatmulBasic<ProblemShape, FULL_LOAD_MODE>;
148- ProblemShape, FULL_LOAD_MODE>;
149 176 
150// ============== 4. BlockMmad 组装 ==============177// ============== 4. BlockMmad 组装 ==============
151// DispatchPolicy: 调度策略,FusedOpType: 融合操作类型178// DispatchPolicy: 调度策略,FusedOpType: 融合操作类型
@@ -161,7 +188,7 @@ using BlockMmad = Blaze::Gemm::Block::BlockMmad<
161using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty;188using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty;
162 189 
163// ============== 6. Kernel 组装 ==============190// ============== 6. Kernel 组装 ==============
164-using MatmulKernel = Blaze::Gemm::Kernel::KernelMatmulBasic<191+using MatmulKernel = Blaze::Gemm::Kernel::GemmUniversal<
165 ProblemShape, BlockMmad, BlockEpilogue, BlockScheduler>;192 ProblemShape, BlockMmad, BlockEpilogue, BlockScheduler>;
166 193 
167// ============== 7. Params 构造 ==============194// ============== 7. Params 构造 ==============
@@ -176,48 +203,26 @@ params.mmadParams.aGmAddr = aGM; // A 矩阵 GM 地址
176params.mmadParams.bGmAddr = bGM; // B 矩阵 GM 地址203params.mmadParams.bGmAddr = bGM; // B 矩阵 GM 地址
177params.mmadParams.cGmAddr = cGM; // C 矩阵 GM 地址204params.mmadParams.cGmAddr = cGM; // C 矩阵 GM 地址
178params.mmadParams.biasGmAddr = biasGM; // Bias GM 地址(可选,nullptr 表示无 bias)205params.mmadParams.biasGmAddr = biasGM; // Bias GM 地址(可选,nullptr 表示无 bias)
206+params.mmadParams.ml1 = 256; // L1 M 维度尺寸
207+params.mmadParams.nl1 = 256; // L1 N 维度尺寸
208+params.mmadParams.kl1 = 128; // L1 K 维度尺寸
209+params.mmadParams.ml0 = 128; // L0 M 维度尺寸
210+params.mmadParams.nl0 = 128; // L0 N 维度尺寸
211+params.mmadParams.kl0 = 64; // L0 K 维度尺寸
212+params.mmadParams.l1Stages = 2; // L1 缓冲数量(双缓冲)
213+params.mmadParams.l0cStages = 1; // L0C 缓冲数量(单缓冲)
179 214 
180// --- BlockScheduler 参数 ---215// --- BlockScheduler 参数 ---
181-// L1 tile 形状:决定每个 tile 的 M/N/K 轴尺寸216+params.schParams.mL1 = 256; // M L1 tile 尺寸
182-params.schedulerParams.mL1 = 256; // M 轴 L1 tile 尺寸217+params.schParams.nL1 = 256; // N 轴 L1 tile 尺寸
183-params.schedulerParams.nL1 = 256; // N 轴 L1 tile 尺寸218+params.schParams.kL1 = 128; // K 轴 L1 tile 尺寸
184-params.schedulerParams.kL1 = 128; // KL1 tile 尺寸219+params.schParams.baseM = 128; // ML0 base 尺寸
185- 220+params.schParams.baseN = 128; // N 轴 L0 base 尺寸
186-// L0 base 形状:决定每次 Mmad 计算的 M/N/K 轴尺寸221+params.schParams.baseK = 64; // K 轴 L0 base 尺寸
187-params.schedulerParams.baseM = 128; // M 轴 L0 base 尺寸222+params.schParams.mTailCnt = 2; // M 轴尾块切分数量(Batch=1 场景)
188-params.schedulerParams.baseN = 128; // N 轴 L0 base 尺寸223+params.schParams.nTailCnt = 2; // N 轴尾块切分数量(Batch=1 场景)
189-params.schedulerParams.baseK = 64; // K 轴 L0 base 尺寸224+params.schParams.isHf32 = 0; // HF32 模式标志(0=关闭)
190- 225+params.schParams.l2CacheMode = Blaze::Gemm::L2_CACHE_DEFAULT; // L2Cache 使能
191-// 尾块切分(Batch=1 场景,提升尾块并行度)
192-params.schedulerParams.mTailCnt = 2; // M 轴尾块切分数量(建议 1~4)
193-params.schedulerParams.nTailCnt = 2; // N 轴尾块切分数量(建议 1~4)
194- 
195-// L1 尾块切分(矩阵不能被 tile 整除时使用)
196-params.schedulerParams.mBaseTailSplitCnt = 1; // M 轴 L1 尾块切分数量(建议 1)
197-params.schedulerParams.nBaseTailSplitCnt = 1; // N 轴 L1 尾块切分数量(建议 1)
198-params.schedulerParams.mTailMain = 1; // M 轴 L1 尾块主尺寸
199-params.schedulerParams.nTailMain = 1; // N 轴 L1 尾块主尺寸
200- 
201-// 双缓冲配置(提升数据搬运与计算并行度)
202-params.schedulerParams.l1BufferNum = 2; // L1 缓冲数量(1=单缓冲, 2=双缓冲)
203-params.schedulerParams.l0cDB = 2; // L0C 双缓冲(1=单缓冲, 2=双缓冲)
204-params.schedulerParams.ubDB = 2; // UB 双缓冲(1=单缓冲, 2=双缓冲)
205- 
206-// HF32 模式(可选,用于特定精度场景)
207-params.schedulerParams.isHf32 = 0; // HF32 模式标志(0=关闭)
208- 
209-// L2Cache 配置(可选,控制 A/B 矩阵 L2Cache 行为)
210-params.schedulerParams.l2CacheDisable =
211- Blaze::Gemm::L2CacheMode::L2_CACHE_DEFAULT; // L2Cache 使能(默认)
212-// 其他选项:
213-// A_L2_CACHE_DISABLE 禁用 A 矩阵 L2Cache
214-// B_L2_CACHE_DISABLE 禁用 B 矩阵 L2Cache
215-// ALL_L2_CACHE_DISABLE 禁用所有 L2Cache
216- 
217-// 非连续场景参数(连续 ND 格式不需要设置)
218-params.schedulerParams.sliceM = 0; // M 轴 slice 尺寸(非连续场景)
219-params.schedulerParams.srcNdStride = 0; // stride(非连续场景)
220-params.schedulerParams.innerBatch = 1; // transpose 内轴 batch
221 226 
222// --- BlockEpilogue 参数 ---227// --- BlockEpilogue 参数 ---
223// Empty Epilogue 无需设置参数228// Empty Epilogue 无需设置参数
@@ -228,67 +233,44 @@ MatmulKernel mm;
228mm(params); // 执行矩阵乘计算233mm(params); // 执行矩阵乘计算
229```234```
230 235 
231-### 参数详解236+### 常用配置示例
232- 
233-#### ProblemShape 参数
234-| 参数 | 类型 | 说明 | 示例 |
235-|------|------|------|------|
236-| m | int64_t | M 轴尺寸 | 1024 |
237-| n | int64_t | N 轴尺寸 | 1024 |
238-| k | int64_t | K 轴尺寸 | 512 |
239-| batch | int64_t | Batch 数量(0 或 1 为单 batch) | 1 |
240- 
241-#### BlockMmad 参数
242-| 参数 | 类型 | 说明 | 示例 |
243-|------|------|------|------|
244-| aGmAddr | GM_ADDR | A 矩阵 GM 地址 | aGM |
245-| bGmAddr | GM_ADDR | B 矩阵 GM 地址 | bGM |
246-| cGmAddr | GM_ADDR | C 矩阵 GM 地址 | cGM |
247-| biasGmAddr | GM_ADDR | Bias GM 地址(nullptr 表示无 bias) | biasGM 或 nullptr |
248- 
249-#### BlockScheduler 参数
250-详见 [BlockSchedulerMatmulBasic 参数详解](../block/block_scheduler_matmul_basic.md#params-参数结构)
251- 
252-#### 常用配置示例
253 237 
254**小矩阵场景**238**小矩阵场景**
255```cpp239```cpp
256-params.schedulerParams.mL1 = 128;240+params.schParams.mL1 = 128;
257-params.schedulerParams.nL1 = 128;241+params.schParams.nL1 = 128;
258-params.schedulerParams.kL1 = 64;242+params.schParams.kL1 = 64;
259-params.schedulerParams.baseM = 64;243+params.schParams.baseM = 64;
260-params.schedulerParams.baseN = 64;244+params.schParams.baseN = 64;
261-params.schedulerParams.baseK = 32;245+params.schParams.baseK = 32;
262-params.schedulerParams.l1BufferNum = 1; // 单缓冲246+params.mmadParams.l1Stages = 1; // 单缓冲
263-params.schedulerParams.l0cDB = 1;247+params.mmadParams.l0cStages = 1;
264-params.schedulerParams.ubDB = 1;
265```248```
266 249 
267**大矩阵场景**250**大矩阵场景**
268```cpp251```cpp
269-params.schedulerParams.mL1 = 256;252+params.schParams.mL1 = 256;
270-params.schedulerParams.nL1 = 256;253+params.schParams.nL1 = 256;
271-params.schedulerParams.kL1 = 128;254+params.schParams.kL1 = 128;
272-params.schedulerParams.baseM = 128;255+params.schParams.baseM = 128;
273-params.schedulerParams.baseN = 128;256+params.schParams.baseN = 128;
274-params.schedulerParams.baseK = 64;257+params.schParams.baseK = 64;
275-params.schedulerParams.l1BufferNum = 2; // 双缓冲258+params.mmadParams.l1Stages = 2; // 双缓冲
276-params.schedulerParams.l0cDB = 2;259+params.mmadParams.l0cStages = 1;
277-params.schedulerParams.ubDB = 2;260+params.schParams.l2CacheMode = Blaze::Gemm::ALL_L2_CACHE_DISABLE;
278-params.schedulerParams.l2CacheDisable = Blaze::Gemm::L2CacheMode::ALL_L2_CACHE_DISABLE;
279```261```
280 262 
281**尾块优化场景(Batch=1)**263**尾块优化场景(Batch=1)**
282```cpp264```cpp
283-params.schedulerParams.mTailCnt = 4; // 尾块切为 4×4 = 16 份265+params.schParams.mTailCnt = 4; // 尾块切为 4×4 = 16 份
284-params.schedulerParams.nTailCnt = 4; // 16 个 Block 并行处理尾块266+params.schParams.nTailCnt = 4; // 16 个 Block 并行处理尾块
285```267```
286 268 
287## 数据流269## 数据流
288 270 
289### 存储层次271### 存储层次
290```272```
291-GM (A/B/Bias) → BlockScheduler (tile 切分) → L1 (缓冲) → L0A/L0B (双缓冲) → L0C (双缓冲) → GM (C)273+GM (A/B/Bias) → BlockScheduler (tile 切分) → L1 (缓冲) → L0A/L0B (双缓冲) → L0C (单缓冲或双缓冲) → GM (C)
292```274```
293 275 
294### Kernel 执行流程276### Kernel 执行流程
@@ -303,18 +285,23 @@ BlockMmad 初始化 (设置缓冲策略)
303285
304创建 GM Tensor (ND/NZ layout)286创建 GM Tensor (ND/NZ layout)
305287
306-配置 L2 Cache (可选禁用)288+配置 L2 Cache (可选)
307289
308遍历 tile → BlockMmad 执行 (每个 tile 独立计算)290遍历 tile → BlockMmad 执行 (每个 tile 独立计算)
309291
310-清理 (关闭 HF32/MM Layout Transform)292+清理 (关闭 HF32)
311```293```
312 294 
313-## 性能优化建议(Basic 特有)295+## 性能优化建议
314 296 
315### L2 Cache 配置297### L2 Cache 配置
316-- **大矩阵场景**:建议禁用 L2 Cache 避免缓存污染298+- **大矩阵场景**:建议禁用 L2 Cache 避免缓存污染(`ALL_L2_CACHE_DISABLE`)
317-- **小矩阵场景**:可保留 L2 Cache 提升数据复用299+- **小矩阵场景**:可保留 L2 Cache 提升数据复用(`L2_CACHE_DEFAULT`)
300+ 
301+### L1/L0 缓冲配置
302+- **小矩阵场景**:使用单缓冲(`l1Stages=1, l0cStages=1`
303+- **中等矩阵场景**:使用双缓冲(`l1Stages=2, l0cStages=1`
304+- **大矩阵场景**:使用四缓冲(`l1Stages=4, l0cStages=2`
318 305 
319### Bias 预处理306### Bias 预处理
320- **常量 bias**:可预先处理减少运行时开销307- **常量 bias**:可预先处理减少运行时开销
@@ -328,6 +315,10 @@ BlockMmad 初始化 (设置缓冲策略)
328- `kL1``baseK` 应根据数据局部性和复用率优化315- `kL1``baseK` 应根据数据局部性和复用率优化
329- 避免 K 轴切分过于细碎导致搬运开销增加316- 避免 K 轴切分过于细碎导致搬运开销增加
330 317 
318+### 尾块优化(Batch=1 场景)
319+- 设置 `mTailCnt``nTailCnt` 提高尾块并行度
320+- 建议值:2~4
321+ 
331### 适用场景322### 适用场景
332- **小矩阵**:(m × n × k) 较小时,Basic Kernel 更高效323- **小矩阵**:(m × n × k) 较小时,Basic Kernel 更高效
333- **简单计算**:无复杂后处理需求时,Basic Kernel 足够324- **简单计算**:无复杂后处理需求时,Basic Kernel 足够
@@ -47,24 +47,30 @@ BlockEpilogueStreamK<float, bfloat16_t, ...>
47- **ON_THE_FLY**:实时输出模式47- **ON_THE_FLY**:实时输出模式
48- **ND_FIXPIPE_1_2**:ND 1v2 优化模式(stride 对齐到 32B)48- **ND_FIXPIPE_1_2**:ND 1v2 优化模式(stride 对齐到 32B)
49 49 
50+### L2 Cache 配置
51+可选禁用 A/B 矩阵的 L2 Cache,避免大矩阵场景下的缓存污染:
52+```
53+SetL2Cache(gmA, gmB, params.schParams.l2CacheMode);
54+```
55+ 
50## 特殊静态常量56## 特殊静态常量
51 57 
52| 常量 | 说明 |58| 常量 | 说明 |
53|------|------|59|------|------|
54| AIC_SYNC_AIV_MODE_4 | 同步模式(MODE_4) |60| AIC_SYNC_AIV_MODE_4 | 同步模式(MODE_4) |
55-| AIV_SYNC_AIC_FLAG | AIV 同步 AIC 标志 ID |61+| AIC_SYNC_AIV_FLAG | AIC 同步 AIV 标志 ID(8) |
56-| AIC_SYNC_AIV_FLAG | AIC 同步 AIV 标志 ID |
57| FLAG_ID_MAX | 标志 ID 最大值(16) |62| FLAG_ID_MAX | 标志 ID 最大值(16) |
58| BLOCK_BASE_M | Block 基础 M 维度(256) |63| BLOCK_BASE_M | Block 基础 M 维度(256) |
59| BLOCK_BASE_N | Block 基础 N 维度(256) |64| BLOCK_BASE_N | Block 基础 N 维度(256) |
65+| BLOCK_BYTE_SIZE | Block 字节对齐大小(32) |
60 66 
61## 特殊类型别名67## 特殊类型别名
62 68 
63| 类型 | 说明 |69| 类型 | 说明 |
64|------|------|70|------|------|
65-| BlockMmadOp | BlockMmadStreamK 组件 |71+| BlockMmad | BlockMmadStreamK 组件 |
66| BlockEpilogueParams | BlockEpilogueStreamK 参数 |72| BlockEpilogueParams | BlockEpilogueStreamK 参数 |
67-| WorkspaceType | Workspace 数据类型(float) |73+| BlockMmadParams | BlockMmad::Params |
68 74 
69## 特殊数据结构75## 特殊数据结构
70 76 
@@ -80,7 +86,7 @@ struct Params {
80 86 
81### BlockMmadParams(StreamK 特有)87### BlockMmadParams(StreamK 特有)
82```88```
83-struct GmParams {89+struct Params { // BlockMmad::Params
84 GM_ADDR aGmAddr; // A 矩阵 GM 地址90 GM_ADDR aGmAddr; // A 矩阵 GM 地址
85 GM_ADDR bGmAddr; // B 矩阵 GM 地址91 GM_ADDR bGmAddr; // B 矩阵 GM 地址
86 GM_ADDR cGmAddr; // C 矩阵 GM 地址(可选,DP 模式)92 GM_ADDR cGmAddr; // C 矩阵 GM 地址(可选,DP 模式)
@@ -95,15 +101,15 @@ struct GmParams {
95 101 
96### 构造函数102### 构造函数
97```103```
98-__aicore__ inline KernelMatmulStreamK()104+__aicore__ inline GemmUniversal()
99```105```
100-功能:构造 KernelMatmulStreamK 对象。106+功能:构造 GemmUniversal(KernelMatmulStreamK对象。
101 107 
102### 析构函数108### 析构函数
103```109```
104-__aicore__ inline ~KernelMatmulStreamK()110+__aicore__ inline ~GemmUniversal()
105```111```
106-功能:析构 KernelMatmulStreamK 对象。112+功能:析构 GemmUniversal(KernelMatmulStreamK对象。
107 113 
108### Init函数114### Init函数
109```115```
@@ -111,10 +117,28 @@ __aicore__ inline void Init(Params const& params)
111```117```
112功能:初始化 Kernel,提取问题规模、GM 地址、workspace 地址。118功能:初始化 Kernel,提取问题规模、GM 地址、workspace 地址。
113执行流程:119执行流程:
114-1. 设置问题规模 `problemShape_`120+1. 提取 BlockMmad 参数(包含 workspace 地址)
115-2. 提取 BlockMmad 参数(包含 workspace 地址121+2. 设置 A、B、C、workspace GM 地址
116-3. 设置 A、B、C、workspace 的 GM 地址122+3. 判断 bias 地址是否为 nullptr
117-4. 判断 bias 地址是否为 nullptr123+ 
124+### SetL2Cache函数
125+```
126+template <typename TensorA, typename TensorB>
127+__aicore__ inline void SetL2Cache(TensorA& gmA, TensorB& gmB, uint32_t l2CacheMode)
128+```
129+功能:根据 L2CacheMode 配置 A/B 矩阵的 L2 Cache。
130+参数说明:
131+| 参数 | 类型 | 说明 |
132+|------|------|------|
133+| gmA | TensorA | A 矩阵 GM Tensor |
134+| gmB | TensorB | B 矩阵 GM Tensor |
135+| l2CacheMode | uint32_t | L2 Cache 配置模式 |
136+ 
137+支持的 L2CacheMode:
138+- `L2_CACHE_DEFAULT`:L2 Cache 使能(默认)
139+- `A_L2_CACHE_DISABLE`:禁用 A 矩阵 L2 Cache
140+- `B_L2_CACHE_DISABLE`:禁用 B 矩阵 L2 Cache
141+- `ALL_L2_CACHE_DISABLE`:禁用所有 L2 Cache
118 142 
119### operator函数143### operator函数
120```144```
@@ -133,12 +157,13 @@ __aicore__ inline void operator()(Params const& params)
1333. BlockMmadStreamK 初始化1573. BlockMmadStreamK 初始化
1344. Layout 构建:A、B、C、Bias1584. Layout 构建:A、B、C、Bias
1355. GM Tensor 创建1595. GM Tensor 创建
136-6. Tile 循环处理:160+6. L2 Cache 配置(通过 SetL2Cache)
161+7. Tile 循环处理:
137 - **DP 模式**:结果输出到 GM162 - **DP 模式**:结果输出到 GM
138 - **SK 模式**:结果输出到 workspace163 - **SK 模式**:结果输出到 workspace
139 - **Preload**:SK 模式下预加载下一轮 tile164 - **Preload**:SK 模式下预加载下一轮 tile
140-7. AIC-AIV 同步:设置 `AIC_SYNC_AIV_FLAG`165+8. AIC-AIV 同步:设置 `AIC_SYNC_AIV_FLAG`
141-8. 清理:关闭 HF32/MM Layout Transform166+9. 清理:关闭 HF32 模式
142 167 
143**AIV 核执行流程**168**AIV 核执行流程**
1441. Block 索引检查:超出处理范围则等待同步并返回1691. Block 索引检查:超出处理范围则等待同步并返回
@@ -165,9 +190,9 @@ __aicore__ inline void operator()(Params const& params)
165### Preload 优化190### Preload 优化
166```191```
167if (!bs.CheckIsSkScene(0)) { // SK Preload in DP+SK192if (!bs.CheckIsSkScene(0)) { // SK Preload in DP+SK
168- if (tileIdx % usedCoreNum_ < tailSKTotalTileNum &&193+ if (tileIdx % usedCoreNum < tailSKTotalTileNum &&
169- (CeilDiv(tileIdx + 1, usedCoreNum_) == (CeilDiv(tileNum, usedCoreNum_) - 1))) {194+ (CeilDiv(tileIdx + 1, usedCoreNum) == (CeilDiv(tileNum, usedCoreNum) - 1))) {
170- tmpTileIdx = tileIdx + usedCoreNum_; // Preload 下一轮 SK tile195+ tmpTileIdx = tileIdx + usedCoreNum; // Preload 下一轮 SK tile
171 }196 }
172}197}
173```198```
@@ -188,11 +213,12 @@ using BiasType = float;
188using LayoutA = AscendC::Te::NDExtLayoutPtn;213using LayoutA = AscendC::Te::NDExtLayoutPtn;
189using LayoutB = AscendC::Te::NZLayoutPtn;214using LayoutB = AscendC::Te::NZLayoutPtn;
190using LayoutC = AscendC::Te::NDExtLayoutPtn;215using LayoutC = AscendC::Te::NDExtLayoutPtn;
216+using LayoutBias = LayoutC;
191 217 
192// 定义调度策略(ON_THE_FLY 或 ND_FIXPIPE_1_2)218// 定义调度策略(ON_THE_FLY 或 ND_FIXPIPE_1_2)
193using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>;219using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>;
194 220 
195-// 定义 BlockMmadStreamK221+// 定义 BlockMmad
196using BlockMmad = Blaze::Gemm::Block::BlockMmad<222using BlockMmad = Blaze::Gemm::Block::BlockMmad<
197 DispatchPolicy, AType, LayoutA, BType, LayoutB, CType, LayoutC, BiasType, LayoutBias>;223 DispatchPolicy, AType, LayoutA, BType, LayoutB, CType, LayoutC, BiasType, LayoutBias>;
198 224 
@@ -203,7 +229,7 @@ using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueStreamK<float, half, Disp
203using BlockScheduler = Blaze::Gemm::Block::BlockSchedulerStreamK<ProblemShape>;229using BlockScheduler = Blaze::Gemm::Block::BlockSchedulerStreamK<ProblemShape>;
204 230 
205// 定义 Kernel231// 定义 Kernel
206-using StreamKKernel = Blaze::Gemm::Kernel::KernelMatmulStreamK<232+using StreamKKernel = Blaze::Gemm::Kernel::GemmUniversal<
207 ProblemShape, BlockMmad, BlockEpilogue, BlockScheduler>;233 ProblemShape, BlockMmad, BlockEpilogue, BlockScheduler>;
208```234```
209 235 
@@ -214,7 +240,7 @@ Params params = {
214 {m, n, k, batch}, // problem shape240 {m, n, k, batch}, // problem shape
215 {aGM, bGM, cGM, biasGM, workspaceGM}, // mmad params(包含 workspace)241 {aGM, bGM, cGM, biasGM, workspaceGM}, // mmad params(包含 workspace)
216 {cGM, workspaceGM}, // epilogue params242 {cGM, workspaceGM}, // epilogue params
217- {usedCoreNum, baseM, baseN, baseK, singleCoreK, kL1, isHf32} // scheduler params243+ {usedCoreNum, baseM, baseN, baseK, singleCoreK, kL1, isHf32, l2CacheMode} // scheduler params
218};244};
219```245```
220 246 
@@ -229,9 +255,9 @@ streamk(params);
229### 存储层次255### 存储层次
230```256```
231GM (A/B/Bias) → BlockScheduler (DP+SK 混合调度) → L1 → L0 → L0C257GM (A/B/Bias) → BlockScheduler (DP+SK 混合调度) → L1 → L0 → L0C
232- 258+
233- DP: → GM (C)259+ DP: → GM (C)
234- SK: → Workspace → AIV → GM (C)260+ SK: → Workspace → AIV → GM (C)
235```261```
236 262 
237### DP 模式流程263### DP 模式流程
@@ -289,6 +315,11 @@ offsetWorkspace = ((tileIdx % usedCoreNum) / skKTileNum) * skKTileNum + kCntInde
289- 使用 `CrossCoreSetFlag`(AIC 设置)和 `CrossCoreWaitFlag`(AIV 等待)315- 使用 `CrossCoreSetFlag`(AIC 设置)和 `CrossCoreWaitFlag`(AIV 等待)
290- 使用 `SyncAll` 全核同步316- 使用 `SyncAll` 全核同步
291 317 
318+### L2 Cache 配置
319+- **大矩阵场景**:建议禁用 L2 Cache 避免缓存污染
320+- **小矩阵场景**:可保留 L2 Cache 提升数据复用
321+- 使用 `ALL_L2_CACHE_DISABLE` 禁用所有 L2 Cache
322+ 
292### Workspace 配置323### Workspace 配置
293- workspace 大小:`tailMNTileNum × skKTileNum × BLOCK_BASE_M × BLOCK_BASE_N × sizeof(float)`324- workspace 大小:`tailMNTileNum × skKTileNum × BLOCK_BASE_M × BLOCK_BASE_N × sizeof(float)`
294- 建议:workspace 大小约为 `m × n × (k / skKTileNum) × sizeof(float)` 的尾块部分325- 建议:workspace 大小约为 `m × n × (k / skKTileNum) × sizeof(float)` 的尾块部分
@@ -25,10 +25,6 @@ public:
25 using BlockShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;25 using BlockShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
26 using BlockCoord = AscendC::Te::Coord<int64_t, int64_t, int64_t, int64_t>;26 using BlockCoord = AscendC::Te::Coord<int64_t, int64_t, int64_t, int64_t>;
27 27 
28- struct Arguments {
29- Arguments() = default;
30- };
31- 
32 struct Params {28 struct Params {
33 Params() = default;29 Params() = default;
34 };30 };
@@ -41,7 +37,7 @@ public:
41 return;37 return;
42 }38 }
43 39 
44- __aicore__ inline void operator()(Arguments const& params)40+ __aicore__ inline void operator()(Params const& params)
45 {41 {
46 Run();42 Run();
47 }43 }
@@ -34,15 +34,15 @@ public:
34 using BlockShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;34 using BlockShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
35 using BlockCoord = AscendC::Te::Coord<int64_t, int64_t, int64_t, int64_t>;35 using BlockCoord = AscendC::Te::Coord<int64_t, int64_t, int64_t, int64_t>;
36 36 
37- struct Arguments {37+ struct Params {
38 GM_ADDR cGmAddr{nullptr};38 GM_ADDR cGmAddr{nullptr};
39 GM_ADDR workspaceGmAddr{nullptr};39 GM_ADDR workspaceGmAddr{nullptr};
40 };40 };
41 41 
42- using Params = Arguments;42+ __aicore__ inline BlockEpilogueMatmulStreamK()
43- 43+ {}
44- __aicore__ inline BlockEpilogueMatmulStreamK() {}44+ __aicore__ inline ~BlockEpilogueMatmulStreamK()
45- __aicore__ inline ~BlockEpilogueMatmulStreamK() {}45+ {}
46 46 
47 using WorkspaceType = WorkspaceType_;47 using WorkspaceType = WorkspaceType_;
48 using OutType = OutType_;48 using OutType = OutType_;
@@ -95,8 +95,9 @@ public:
95 };95 };
96 CopyUb2GmParams copyUb2GmParams_;96 CopyUb2GmParams copyUb2GmParams_;
97 97 
98- __aicore__ inline void Init(Params const& params, BlockShape blockShapeInAiv, BlockShape tileL1ShapeInAiv,98+ __aicore__ inline void Init(
99- BlockCoord coordInAiv, uint64_t usedCoreNum, bool checkIsSkScene)99+ Params const& params, BlockShape blockShapeInAiv, BlockShape tileL1ShapeInAiv, BlockCoord coordInAiv,
100+ uint64_t usedCoreNum, bool checkIsSkScene)
100 {101 {
101 m_ = Get<MNK_M>(blockShapeInAiv);102 m_ = Get<MNK_M>(blockShapeInAiv);
102 n_ = Get<MNK_N>(blockShapeInAiv);103 n_ = Get<MNK_N>(blockShapeInAiv);
@@ -125,47 +126,53 @@ public:
125 for (uint64_t index = 0; index < aivMte2Num_; ++index) {126 for (uint64_t index = 0; index < aivMte2Num_; ++index) {
126 UpdateAivParams(index);127 UpdateAivParams(index);
127 LocalTensor<float> ubAddTensor{AscendC::TPosition::VECIN, 0, AscendC::TOTAL_UB_SIZE};128 LocalTensor<float> ubAddTensor{AscendC::TPosition::VECIN, 0, AscendC::TOTAL_UB_SIZE};
128- DataCopyExtParams dataCopyExtParams{static_cast<uint16_t>(copyGm2UbParams_.kCnt),129+ DataCopyExtParams dataCopyExtParams{
129- static_cast<uint32_t>(copyGm2UbParams_.burstLen * sizeof(float)),130+ static_cast<uint16_t>(copyGm2UbParams_.kCnt),
130- static_cast<uint32_t>(copyGm2UbParams_.srcGap * sizeof(float)),131+ static_cast<uint32_t>(copyGm2UbParams_.burstLen * sizeof(float)),
131- 0, 0};132+ static_cast<uint32_t>(copyGm2UbParams_.srcGap * sizeof(float)), 0, 0};
132- if (copyGm2UbParams_.mBurst == 0) {return;}133+ if (copyGm2UbParams_.mBurst == 0) {
133- DataCopyPad<float>(ubAddTensor, workspaceGlobal_[copyGm2UbParams_.offsetWorkspaceGM], dataCopyExtParams,134+ return;
134- {false, 0, 0, 0});135+ }
136+ DataCopyPad<float>(
137+ ubAddTensor, workspaceGlobal_[copyGm2UbParams_.offsetWorkspaceGM], dataCopyExtParams, {false, 0, 0, 0});
135 AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(ZERO_FLAG);138 AscendC::SetFlag<AscendC::HardEvent::MTE2_V>(ZERO_FLAG);
136 AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(ZERO_FLAG);139 AscendC::WaitFlag<AscendC::HardEvent::MTE2_V>(ZERO_FLAG);
137 140 
138 for (uint64_t i = 1; i < copyGm2UbParams_.kCnt; ++i) {141 for (uint64_t i = 1; i < copyGm2UbParams_.kCnt; ++i) {
139- Add(ubAddTensor, ubAddTensor, ubAddTensor[i * copyGm2UbParams_.burstLen],142+ Add(ubAddTensor, ubAddTensor, ubAddTensor[i * copyGm2UbParams_.burstLen], copyGm2UbParams_.burstLen);
140- copyGm2UbParams_.burstLen);
141 }143 }
142 144 
143- DataCopyExtParams ub2gmExtParams{static_cast<uint16_t>(copyUb2GmParams_.mLength),145+ DataCopyExtParams ub2gmExtParams{
146+ static_cast<uint16_t>(copyUb2GmParams_.mLength),
144 static_cast<uint32_t>(copyUb2GmParams_.burstLen * sizeof(OutType)),147 static_cast<uint32_t>(copyUb2GmParams_.burstLen * sizeof(OutType)),
145 static_cast<uint32_t>(copyUb2GmParams_.srcGap * sizeof(OutType) / UB2GM_SRCGAP_UNIT),148 static_cast<uint32_t>(copyUb2GmParams_.srcGap * sizeof(OutType) / UB2GM_SRCGAP_UNIT),
146 static_cast<uint32_t>(copyUb2GmParams_.dstGap * sizeof(OutType)), 0};149 static_cast<uint32_t>(copyUb2GmParams_.dstGap * sizeof(OutType)), 0};
147 150 
148- if constexpr (DispatchPolicy::enableRelu &&151+ if constexpr (
149- (sizeof(OutType) != sizeof(half) || AscendC::IsSameType<OutType, bfloat16_t>::value)) {152+ DispatchPolicy::fusedOpType == OP_TYPE_RELU &&
153+ (sizeof(OutType) != sizeof(half) || AscendC::IsSameType<OutType, bfloat16_t>::value)) {
150 AscendC::Relu(ubAddTensor, ubAddTensor, copyGm2UbParams_.burstLen);154 AscendC::Relu(ubAddTensor, ubAddTensor, copyGm2UbParams_.burstLen);
151 }155 }
152 if constexpr (sizeof(OutType) == sizeof(half)) {156 if constexpr (sizeof(OutType) == sizeof(half)) {
153 LocalTensor<OutType> ubCastDst{AscendC::TPosition::VECIN, 0, AscendC::TOTAL_UB_SIZE};157 LocalTensor<OutType> ubCastDst{AscendC::TPosition::VECIN, 0, AscendC::TOTAL_UB_SIZE};
154 Cast(ubCastDst, ubAddTensor, RoundMode::CAST_RINT, copyGm2UbParams_.burstLen);158 Cast(ubCastDst, ubAddTensor, RoundMode::CAST_RINT, copyGm2UbParams_.burstLen);
155- if constexpr (DispatchPolicy::enableRelu && !AscendC::IsSameType<OutType, bfloat16_t>::value) {159+ if constexpr (
160+ DispatchPolicy::fusedOpType == OP_TYPE_RELU && !AscendC::IsSameType<OutType, bfloat16_t>::value) {
156 // Relu not support bfloat16_t161 // Relu not support bfloat16_t
157 AscendC::Relu(ubCastDst, ubCastDst, copyGm2UbParams_.burstLen);162 AscendC::Relu(ubCastDst, ubCastDst, copyGm2UbParams_.burstLen);
158 }163 }
159 AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);164 AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);
160 AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);165 AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);
161- DataCopyPad<OutType, (DispatchPolicy::fixpOpti_ == MatMulL0C2Out::ND_FIXPIPE_1_2) ?166+ DataCopyPad<
162- PaddingMode::Normal : PaddingMode::Compact>(167+ OutType, (DispatchPolicy::fixpOpti == MatMulL0C2Out::ND_FIXPIPE_1_2) ? PaddingMode::Normal :
168+ PaddingMode::Compact>(
163 cGlobal_[copyUb2GmParams_.offsetCGm], ubCastDst, ub2gmExtParams);169 cGlobal_[copyUb2GmParams_.offsetCGm], ubCastDst, ub2gmExtParams);
164 } else {170 } else {
165 AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);171 AscendC::SetFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);
166 AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);172 AscendC::WaitFlag<AscendC::HardEvent::V_MTE3>(ZERO_FLAG);
167- DataCopyPad<OutType, (DispatchPolicy::fixpOpti_ == MatMulL0C2Out::ND_FIXPIPE_1_2) ?173+ DataCopyPad<
168- PaddingMode::Normal : PaddingMode::Compact>(174+ OutType, (DispatchPolicy::fixpOpti == MatMulL0C2Out::ND_FIXPIPE_1_2) ? PaddingMode::Normal :
175+ PaddingMode::Compact>(
169 cGlobal_[copyUb2GmParams_.offsetCGm], ubAddTensor, ub2gmExtParams);176 cGlobal_[copyUb2GmParams_.offsetCGm], ubAddTensor, ub2gmExtParams);
170 }177 }
171 }178 }
@@ -202,9 +209,9 @@ public:
202 if (round_ < NUM_TWO) {209 if (round_ < NUM_TWO) {
203 aivParams_.curML1InAiv = aivParams_.mCntIndex != (mCnt_ - 1) ? mL1_ : (m_ - (mCnt_ - 1) * mL1_);210 aivParams_.curML1InAiv = aivParams_.mCntIndex != (mCnt_ - 1) ? mL1_ : (m_ - (mCnt_ - 1) * mL1_);
204 aivParams_.curNL1InAiv = aivParams_.nCntIndex != (nCnt_ - 1) ? nL1_ : (n_ - (nCnt_ - 1) * nL1_);211 aivParams_.curNL1InAiv = aivParams_.nCntIndex != (nCnt_ - 1) ? nL1_ : (n_ - (nCnt_ - 1) * nL1_);
205- if constexpr(DispatchPolicy::fixpOpti_ == MatMulL0C2Out::ND_FIXPIPE_1_2) {212+ if constexpr (DispatchPolicy::fixpOpti == MatMulL0C2Out::ND_FIXPIPE_1_2) {
206 aivParams_.curAlignedNInAiv =213 aivParams_.curAlignedNInAiv =
207- CeilAlign(aivParams_.curNL1InAiv, static_cast<uint64_t>(AscendC::ONE_BLK_SIZE));214+ Blaze::Gemm::CeilAlign(aivParams_.curNL1InAiv, static_cast<uint64_t>(AscendC::ONE_BLK_SIZE));
208 } else {215 } else {
209 aivParams_.curAlignedNInAiv = aivParams_.curNL1InAiv;216 aivParams_.curAlignedNInAiv = aivParams_.curNL1InAiv;
210 }217 }
@@ -213,9 +220,10 @@ public:
213 220 
214 __aicore__ inline void UpdateAivParams(uint64_t index)221 __aicore__ inline void UpdateAivParams(uint64_t index)
215 {222 {
216- mBurstBase_ = CeilAlign(CeilDiv(aivParams_.curML1InAiv, kCnt_ * AscendC::GetTaskRation()),223+ mBurstBase_ = Blaze::Gemm::CeilAlign(
217- CeilDiv(UB2GM_SRCGAP_UNIT, aivParams_.curAlignedNInAiv));224+ Blaze::Gemm::CeilDiv(aivParams_.curML1InAiv, kCnt_ * AscendC::GetTaskRation()),
218- uint64_t mBurstCnt = CeilDiv(aivParams_.curML1InAiv, mBurstBase_);225+ Blaze::Gemm::CeilDiv(UB2GM_SRCGAP_UNIT, aivParams_.curAlignedNInAiv));
226+ uint64_t mBurstCnt = Blaze::Gemm::CeilDiv(aivParams_.curML1InAiv, mBurstBase_);
219 uint64_t mBurstTail = aivParams_.curML1InAiv - (mBurstCnt - 1) * mBurstBase_;227 uint64_t mBurstTail = aivParams_.curML1InAiv - (mBurstCnt - 1) * mBurstBase_;
220 if (aivParams_.kCntIndex >= mBurstCnt) {228 if (aivParams_.kCntIndex >= mBurstCnt) {
221 copyGm2UbParams_.mBurstOri = 0;229 copyGm2UbParams_.mBurstOri = 0;
@@ -224,18 +232,14 @@ public:
224 }232 }
225 233 
226 copyGm2UbParams_.kCnt = kCnt_;234 copyGm2UbParams_.kCnt = kCnt_;
227- copyGm2UbParams_.mBurst = CeilDiv(copyGm2UbParams_.mBurstOri, aivMte2Num_);235+ copyGm2UbParams_.mBurst = Blaze::Gemm::CeilDiv(copyGm2UbParams_.mBurstOri, aivMte2Num_);
228 // Calculate init address of workspace for moving into UB.236 // Calculate init address of workspace for moving into UB.
229 copyGm2UbParams_.offsetWorkspaceGM =237 copyGm2UbParams_.offsetWorkspaceGM =
230- (aivParams_.indexParams) * kCnt_ *238+ (aivParams_.indexParams) * kCnt_ * BLOCK_BASE_M * BLOCK_BASE_N +
231- BLOCK_BASE_M * BLOCK_BASE_N +239+ (aivParams_.kCntIndex * mBurstBase_ + copyGm2UbParams_.mBurst * index) * aivParams_.curAlignedNInAiv;
232- (aivParams_.kCntIndex * mBurstBase_ + copyGm2UbParams_.mBurst * index) *
233- aivParams_.curAlignedNInAiv;
234 // Calculate init address of GM for moving out to GM.240 // Calculate init address of GM for moving out to GM.
235- copyUb2GmParams_.offsetCGm =241+ copyUb2GmParams_.offsetCGm = aivParams_.nCntIndex * nL1_ + aivParams_.mCntIndex * mL1_ * n_ +
236- aivParams_.nCntIndex * nL1_ +242+ (aivParams_.kCntIndex * mBurstBase_ + copyGm2UbParams_.mBurst * index) * n_;
237- aivParams_.mCntIndex * mL1_ * n_ +
238- (aivParams_.kCntIndex * mBurstBase_ + copyGm2UbParams_.mBurst * index) * n_;
239 uint64_t singleCnt = 1;243 uint64_t singleCnt = 1;
240 if (index == singleCnt - 1) {244 if (index == singleCnt - 1) {
241 copyGm2UbParams_.mBurst = copyGm2UbParams_.mBurstOri - (singleCnt - 1) * copyGm2UbParams_.mBurst;245 copyGm2UbParams_.mBurst = copyGm2UbParams_.mBurstOri - (singleCnt - 1) * copyGm2UbParams_.mBurst;
@@ -243,7 +247,8 @@ public:
243 copyGm2UbParams_.mBurst = 0;247 copyGm2UbParams_.mBurst = 0;
244 }248 }
245 // datasize for moving in ub, align to 32B249 // datasize for moving in ub, align to 32B
246- copyGm2UbParams_.burstLen = CeilAlign(copyGm2UbParams_.mBurst * aivParams_.curAlignedNInAiv, BLOCK_SIZE);250+ copyGm2UbParams_.burstLen =
251+ Blaze::Gemm::CeilAlign(copyGm2UbParams_.mBurst * aivParams_.curAlignedNInAiv, BLOCK_SIZE);
247 // gap of src between cur burst and next burst252 // gap of src between cur burst and next burst
248 copyGm2UbParams_.srcGap = BLOCK_BASE_M * BLOCK_BASE_N - copyGm2UbParams_.burstLen;253 copyGm2UbParams_.srcGap = BLOCK_BASE_M * BLOCK_BASE_N - copyGm2UbParams_.burstLen;
249 254 
@@ -269,4 +274,3 @@ private:
269} // namespace Block274} // namespace Block
270} // namespace Gemm275} // namespace Gemm
271} // namespace Blaze276} // namespace Blaze
272- 
@@ -31,8 +31,6 @@ public:
31 using DataTypeIn = DataTypeIn_;31 using DataTypeIn = DataTypeIn_;
32 __aicore__ inline DefaultFusion(){};32 __aicore__ inline DefaultFusion(){};
33 33 
34- struct Arguments {};
35- 
36 struct Params {};34 struct Params {};
37 35 
38 __aicore__ inline void Init(Params const& params, int64_t calcM, int64_t calcN, int64_t n) {}36 __aicore__ inline void Init(Params const& params, int64_t calcM, int64_t calcN, int64_t n) {}
@@ -63,7 +63,7 @@ public:
63 static constexpr bool weightNz = IsWeightNz<LayoutB>::value;63 static constexpr bool weightNz = IsWeightNz<LayoutB>::value;
64 static constexpr bool transA = IsTrans<LayoutA>::value;64 static constexpr bool transA = IsTrans<LayoutA>::value;
65 static constexpr bool transB = IsTrans<LayoutB>::value;65 static constexpr bool transB = IsTrans<LayoutB>::value;
66- static constexpr int32_t C0_SIZE = AscendC::AuxGetC0Size<AType>();66+ static constexpr int32_t C0_SIZE = AscendC::Te::C0_ELEMENT<AType>;
67 static constexpr uint16_t L0C_C0 = 16;67 static constexpr uint16_t L0C_C0 = 16;
68 static constexpr uint16_t SCALE_BUFFER_NUM = 2;68 static constexpr uint16_t SCALE_BUFFER_NUM = 2;
69 static constexpr uint16_t AB_L1_TWO_BUFFER = 2;69 static constexpr uint16_t AB_L1_TWO_BUFFER = 2;
@@ -43,6 +43,7 @@ public:
43 using DispatchPolicy = MatmulMultiBlockBasic<FULL_LOAD_MODE_, FUSED_OP_TYPE_, KernelSchedule_>;43 using DispatchPolicy = MatmulMultiBlockBasic<FULL_LOAD_MODE_, FUSED_OP_TYPE_, KernelSchedule_>;
44 using TupleShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;44 using TupleShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
45 using TupleL1L0Shape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t, int64_t, int64_t>;45 using TupleL1L0Shape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t, int64_t, int64_t>;
46+ using TileShape = AscendC::Te::Shape<int64_t, int64_t, int64_t>;
46 uint64_t m_{1};47 uint64_t m_{1};
47 uint64_t n_{1};48 uint64_t n_{1};
48 uint64_t k_{1};49 uint64_t k_{1};
@@ -53,12 +54,6 @@ public:
53 uint64_t baseN_{16};54 uint64_t baseN_{16};
54 uint64_t baseK_{16};55 uint64_t baseK_{16};
55 56 
56- constexpr static uint64_t HALF_L0_SIZE = AscendC::TOTAL_L0A_SIZE / DOUBLE_BUFFER_COUNT / sizeof(AType);
57- constexpr static uint64_t HALF_L0C_SIZE = AscendC::TOTAL_L0C_SIZE / DOUBLE_BUFFER_COUNT / sizeof(float);
58- constexpr static uint64_t HALF_L1_SIZE = AscendC::TOTAL_L1_SIZE / DOUBLE_BUFFER_COUNT;
59- constexpr static uint64_t QUARTER_L1_SIZE = AscendC::TOTAL_L1_SIZE / QUADRUPLE_BUFFER_COUNT;
60- constexpr static uint16_t MTE1_MTE2_EVENT_ID_NUM = 4;
61- 
62 // transA and transB57 // transA and transB
63 static constexpr bool transA = IsTrans<LayoutA>::value;58 static constexpr bool transA = IsTrans<LayoutA>::value;
64 static constexpr bool transB = IsTrans<LayoutB>::value;59 static constexpr bool transB = IsTrans<LayoutB>::value;
@@ -72,28 +67,24 @@ public:
72 transB, AscendC::Te::FrameLayoutFormat<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>,67 transB, AscendC::Te::FrameLayoutFormat<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>,
73 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>>;68 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>>;
74 69 
75- // host side kernel arguments70+ // kernel params
76- struct Arguments {71+ struct Params {
77 GM_ADDR aGmAddr{nullptr};72 GM_ADDR aGmAddr{nullptr};
78 GM_ADDR bGmAddr{nullptr};73 GM_ADDR bGmAddr{nullptr};
79 GM_ADDR cGmAddr{nullptr};74 GM_ADDR cGmAddr{nullptr};
80 GM_ADDR biasGmAddr{nullptr};75 GM_ADDR biasGmAddr{nullptr};
81 GM_ADDR groupListGmAddr{nullptr};76 GM_ADDR groupListGmAddr{nullptr};
82 GM_ADDR workspaceGmAddr{nullptr};77 GM_ADDR workspaceGmAddr{nullptr};
78+ uint64_t ml1{0};
79+ uint64_t nl1{0};
80+ uint64_t kl1{0};
81+ uint32_t ml0{0};
82+ uint32_t nl0{0};
83+ uint32_t kl0{0};
84+ uint32_t l1Stages{1};
85+ uint16_t l0cStages{1};
83 };86 };
84 87 
85- // params
86- using Params = Arguments;
87- 
88-private:
89- uint64_t kL1Iter_{0};
90- uint64_t l1BufNum_{1};
91- uint64_t abL1LoopCnt_{0};
92- uint64_t l0PingPong_{0};
93- uint64_t l0cPingPong_{0};
94- bool isBias_{false};
95- bool enableL0cPingPong_{false};
96- 
97public:88public:
98 __aicore__ inline BlockMmad()89 __aicore__ inline BlockMmad()
99 {90 {
@@ -105,6 +96,7 @@ public:
105 AscendC::SetFlag<AscendC::HardEvent::FIX_M>(FIRST_FLAG);96 AscendC::SetFlag<AscendC::HardEvent::FIX_M>(FIRST_FLAG);
106 AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(SIXTH_FLAG);97 AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(SIXTH_FLAG);
107 AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(SEVENTH_FLAG);98 AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(SEVENTH_FLAG);
99+ SetMMLayoutTransform(true);
108 }100 }
109 }101 }
110 102 
@@ -118,99 +110,74 @@ public:
118 AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(FIRST_FLAG);110 AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(FIRST_FLAG);
119 AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(SIXTH_FLAG);111 AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(SIXTH_FLAG);
120 AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(SEVENTH_FLAG);112 AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(SEVENTH_FLAG);
113+ SetMMLayoutTransform(false);
121 }114 }
122 }115 }
123 116 
124- __aicore__ inline void Init(117+ __aicore__ inline void Init(const TupleShape& shape, const Params& params)
125- const TupleShape& shape, const TupleShape& tileL1, const TupleShape& tileL0, bool isBias, uint64_t l1BufNum,
126- bool l0cDB)
127 {118 {
128 m_ = AscendC::Te::Get<DIMENSION_M>(shape);119 m_ = AscendC::Te::Get<DIMENSION_M>(shape);
129 n_ = AscendC::Te::Get<DIMENSION_N>(shape);120 n_ = AscendC::Te::Get<DIMENSION_N>(shape);
130 k_ = AscendC::Te::Get<DIMENSION_K>(shape);121 k_ = AscendC::Te::Get<DIMENSION_K>(shape);
131- mL1_ = AscendC::Te::Get<DIMENSION_M>(tileL1);122+ mL1_ = params.ml1;
132- nL1_ = AscendC::Te::Get<DIMENSION_N>(tileL1);123+ nL1_ = params.nl1;
133- kL1_ = AscendC::Te::Get<DIMENSION_K>(tileL1);124+ kL1_ = params.kl1;
134- baseM_ = AscendC::Te::Get<DIMENSION_M>(tileL0);125+ baseM_ = params.ml0;
135- baseN_ = AscendC::Te::Get<DIMENSION_N>(tileL0);126+ baseN_ = params.nl0;
136- baseK_ = AscendC::Te::Get<DIMENSION_K>(tileL0);127+ baseK_ = params.kl0;
137- isBias_ = isBias;128+ isBias_ = params.biasGmAddr != nullptr;
138- l1BufNum_ = l1BufNum;129+ l1Stages_ = params.l1Stages;
139- enableL0cPingPong_ = l0cDB;130+ enableL0cPingPong_ = params.l0cStages > 1;
140 // 非全载131 // 非全载
141 aL1OneBuffer_ = mL1_ * kL1_ * sizeof(AType);132 aL1OneBuffer_ = mL1_ * kL1_ * sizeof(AType);
142 bL1OneBuffer_ = nL1_ * kL1_ * sizeof(BType);133 bL1OneBuffer_ = nL1_ * kL1_ * sizeof(BType);
143- kL1Iter_ = CeilDiv(k_, kL1_);
144 l0PingPong_ = 0;134 l0PingPong_ = 0;
145 abL1LoopCnt_ = 0;135 abL1LoopCnt_ = 0;
146 l0cPingPong_ = 0;136 l0cPingPong_ = 0;
137+ constexpr static uint64_t QUARTER_L1_SIZE = AscendC::TOTAL_L1_SIZE / QUADRUPLE_BUFFER_COUNT;
138+ // 2 or 4 buffer
139+ for (auto i = 0; i < l1Stages_; ++i) {
140+ aL1Buffer_[i] = QUARTER_L1_SIZE * (QUADRUPLE_BUFFER_COUNT / l1Stages_) * i;
141+ bL1Buffer_[i] = aL1Buffer_[i] + aL1OneBuffer_;
142+ biasL1Buffer_[i] = bL1Buffer_[i] + bL1OneBuffer_;
143+ }
147 }144 }
148 145 
149- template <typename TensorC, typename TensorA, typename TensorB, typename TensorBias>146+ template <typename TensorA, typename TensorB, typename TensorBias, typename TensorC>
150 __aicore__ inline void operator()(147 __aicore__ inline void operator()(
151- TensorC gmC, TensorA gmA, TensorB gmB, TensorBias gmBias, TupleL1L0Shape tileShape)148+ TensorA& gmA, TensorB& gmB, TensorBias& gmBias, TensorC& gmC, TupleL1L0Shape& tileShape)
152- {149+ {
150+ constexpr static uint64_t HALF_L0C_SIZE = AscendC::TOTAL_L0C_SIZE / DOUBLE_BUFFER_COUNT;
151+ constexpr static uint64_t HALF_L0_SIZE = AscendC::TOTAL_L0A_SIZE / DOUBLE_BUFFER_COUNT;
153 // m0 n0152 // m0 n0
154 uint64_t curM = AscendC::Te::Get<MNK_M0>(tileShape);153 uint64_t curM = AscendC::Te::Get<MNK_M0>(tileShape);
155 uint64_t curN = AscendC::Te::Get<MNK_N0>(tileShape);154 uint64_t curN = AscendC::Te::Get<MNK_N0>(tileShape);
156- uint64_t ml1Align = Blaze::Gemm::CeilAlign(curM, static_cast<uint64_t>(AscendC::BLOCK_CUBE));155+ uint64_t l0cOffset = (l0cPingPong_ & 0x1) * HALF_L0C_SIZE;
157- uint64_t nl1Align = Blaze::Gemm::CeilAlign(curN, static_cast<uint64_t>(AscendC::BLOCK_CUBE));
158- uint64_t l0cOffset = (l0cPingPong_ & 0x1) * HALF_L0C_SIZE;
159- if (enableL0cPingPong_) {
160- AscendC::WaitFlag<AscendC::HardEvent::FIX_M>(l0cPingPong_ & 0x1);
161- }
162- kL1_ = Min(k_, kL1_);
163- 
164 // LoC搬出156 // LoC搬出
165 auto layoutL0C = AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Std::Int<16>>{}(curM, curN);157 auto layoutL0C = AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Std::Int<16>>{}(curM, curN);
166 auto tensorL0C = AscendC::Te::MakeTensor(158 auto tensorL0C = AscendC::Te::MakeTensor(
167- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0C, float>(l0cOffset * sizeof(float)), layoutL0C);159+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0C, float>(l0cOffset), layoutL0C);
168 160 
161+ kL1_ = Min(k_, kL1_);
169 kL1Iter_ = CeilDiv(k_, kL1_);162 kL1Iter_ = CeilDiv(k_, kL1_);
170- uint64_t kL1OffsetLength = 0;
171 for (uint64_t iter0 = 0; iter0 < kL1Iter_; ++iter0) {163 for (uint64_t iter0 = 0; iter0 < kL1Iter_; ++iter0) {
172- auto curKL1 = (iter0 + 1 == kL1Iter_) ? (k_ - kL1OffsetLength) : kL1_;164+ auto curKL1 = (iter0 + 1 == kL1Iter_) ? (k_ - kL1_ * iter0) : kL1_;
173 // 普通模板-2buffer-AL1搬入偏移位置:*AL1Ping*-BL1Ping-BiasPing|*AL1Pong*-BL1Pong-BiasPong165 // 普通模板-2buffer-AL1搬入偏移位置:*AL1Ping*-BL1Ping-BiasPing|*AL1Pong*-BL1Pong-BiasPong
174- uint64_t l1BufId = abL1LoopCnt_ & (l1BufNum_ - 1);166+ uint64_t l1BufId = abL1LoopCnt_ & (l1Stages_ - 1);
167+ uint64_t btBufId = abL1LoopCnt_ & 0x1;
175 AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId);168 AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId);
176 169 
177- // A GM->L1170+ // GM->L1
178- auto layoutAL1 = MakeLayoutAL1{}(curM, curKL1);171+ TileShape l1Shape{curM, curN, curKL1};
179- auto copyGM2L1 = AscendC::Te::MakeCopy(AscendC::Te::CopyGM2L1{});172+ auto l1TensorTuple = CopyL1FromGM(gmA, gmB, gmBias, l1Shape, l1BufId, iter0);
180- uint64_t offsetAl1 =173+ auto tensorAL1 = AscendC::Te::Get<0>(l1TensorTuple);
181- (l1BufNum_ == DOUBLE_BUFFER_COUNT) ? HALF_L1_SIZE * l1BufId : QUARTER_L1_SIZE * l1BufId;174+ auto tensorBL1 = AscendC::Te::Get<1>(l1TensorTuple);
182- auto tensorAL1 = AscendC::Te::MakeTensor(175+ auto tensorBiasL1 = AscendC::Te::Get<2>(l1TensorTuple);
183- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, AType>(offsetAl1), layoutAL1);
184- auto gmTileA = gmA.Slice(AscendC::Te::MakeCoord(0, iter0 * kL1_), AscendC::Te::MakeShape(curM, curKL1));
185- AscendC::Te::Copy(copyGM2L1, tensorAL1, gmTileA);
186- 
187- // Bias GM->L1
188- uint64_t biasBufId = abL1LoopCnt_ & 0x1;
189- uint64_t offsetBiasL1 = (l1BufNum_ == DOUBLE_BUFFER_COUNT) ?
190- HALF_L1_SIZE * l1BufId + aL1OneBuffer_ + bL1OneBuffer_ :
191- QUARTER_L1_SIZE * l1BufId + aL1OneBuffer_ + bL1OneBuffer_;
192- auto layoutBiasL1 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, curN);
193- auto tensorBiasL1 = AscendC::Te::MakeTensor(
194- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BiasType>(offsetBiasL1), layoutBiasL1);
195- // 非全载
196- if (isBias_ && iter0 == 0) {
197- AscendC::Te::Copy(copyGM2L1, tensorBiasL1, gmBias);
198- }
199- 
200- // B GM->L1
201- auto layoutBL1 = MakeLayoutBL1{}(curKL1, curN);
202- uint64_t offsetBl1 = (l1BufNum_ == DOUBLE_BUFFER_COUNT) ? HALF_L1_SIZE * l1BufId + aL1OneBuffer_ :
203- QUARTER_L1_SIZE * l1BufId + aL1OneBuffer_;
204- auto tensorBL1 = AscendC::Te::MakeTensor(
205- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BType>(offsetBl1), layoutBL1);
206- auto gmTileB = gmB.Slice(AscendC::Te::MakeCoord(iter0 * kL1_, 0), AscendC::Te::MakeShape(curKL1, curN));
207- AscendC::Te::Copy(copyGM2L1, tensorBL1, gmTileB);
208 176 
209 AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);177 AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);
210 AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);178 AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);
211 179 
212- kL1OffsetLength += curKL1;180+ uint64_t kL0Iter = CeilDiv(curKL1, baseK_);
213- uint64_t kL0Iter = (curKL1 + baseK_ - 1) / baseK_;
214 for (uint64_t iter1 = 0; iter1 < kL0Iter; ++iter1) {181 for (uint64_t iter1 = 0; iter1 < kL0Iter; ++iter1) {
215 uint64_t curK0 = (iter1 + 1 == kL0Iter) ? (curKL1 - iter1 * baseK_) : baseK_;182 uint64_t curK0 = (iter1 + 1 == kL0Iter) ? (curKL1 - iter1 * baseK_) : baseK_;
216 uint64_t l0Offset = HALF_L0_SIZE * (l0PingPong_ & 0x1);183 uint64_t l0Offset = HALF_L0_SIZE * (l0PingPong_ & 0x1);
@@ -218,57 +185,19 @@ public:
218 AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(static_cast<uint16_t>(mte1Flag));185 AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(static_cast<uint16_t>(mte1Flag));
219 186 
220 // A L1->L0187 // A L1->L0
221- auto copyL12L0A = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0A{});188+ TileShape l0Shape{curM, curN, curK0};
222- auto layoutAL0 =189+ bool needBias = NeedProcessBias(iter0, iter1);
223- AscendC::Te::MakeFrameLayout<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>(190+ auto l0TensorTuple = CopyL0FromL1(tensorAL1, tensorBL1, tensorBiasL1, l0Shape, l0Offset, baseK_ * iter1, needBias, btBufId);
224- curM, curK0);191+ auto tensorAL0 = AscendC::Te::Get<0>(l0TensorTuple);
225- auto tensorAL0 = AscendC::Te::MakeTensor(192+ auto tensorBL0 = AscendC::Te::Get<1>(l0TensorTuple);
226- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0A, AType>(l0Offset * sizeof(AType)), layoutAL0);193+ auto tensorBiasL0 = AscendC::Te::Get<2>(l0TensorTuple);
227- auto tensorBlockAL1 =
228- tensorAL1.Slice(AscendC::Te::MakeCoord(0, iter1 * baseK_), AscendC::Te::MakeShape(curM, curK0));
229- AscendC::Te::Copy(copyL12L0A, tensorAL0, tensorBlockAL1);
230- 
231- // Bias L1->L0
232- uint64_t nl1Align = Blaze::Gemm::CeilAlign(curN, static_cast<uint64_t>(AscendC::BLOCK_CUBE));
233- auto layoutBiasL0 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, nl1Align);
234- auto offsetBiasL0 = baseN_ * biasBufId * sizeof(float);
235- auto tensorBiasL0 = AscendC::Te::MakeTensor(
236- AscendC::Te::MakeMemPtr<AscendC::Te::Location::BIAS, float>(offsetBiasL0), layoutBiasL0);
237- if (NeedProcessBias(iter0, iter1)) {
238- auto copyL12BT = AscendC::Te::MakeCopy(AscendC::Te::CopyL12BT{});
239- AscendC::Te::Copy(copyL12BT, tensorBiasL0, tensorBiasL1);
240- }
241- 
242- // B L1->L0
243- auto copyL12L0B = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0B{});
244- auto layoutBL0 =
245- AscendC::Te::MakeFrameLayout<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>(
246- curK0, curN);
247- auto tensorBL0 = AscendC::Te::MakeTensor(
248- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0B, BType>(l0Offset * sizeof(BType)), layoutBL0);
249- auto tensorBlockBL1 =
250- tensorBL1.Slice(AscendC::Te::MakeCoord(iter1 * baseK_, 0), AscendC::Te::MakeShape(curK0, curN));
251- AscendC::Te::Copy(copyL12L0B, tensorBL0, tensorBlockBL1);
252 194 
253 AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(static_cast<uint16_t>(mte1Flag));195 AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(static_cast<uint16_t>(mte1Flag));
254 AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(static_cast<uint16_t>(mte1Flag));196 AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(static_cast<uint16_t>(mte1Flag));
255 197 
256- constexpr auto mmadAtom =198+ bool initCmatrix = iter0 == 0 && iter1 == 0 && !isBias_;
257- AscendC::Te::MakeMmad(AscendC::Te::MmadOperation{}, AscendC::Te::MmadTraitDefault{});199+ uint8_t unitFlag = ((iter0 + 1 == kL1Iter_ && iter1 + 1 == kL0Iter) ? FINAL_ACCUMULATION : NON_FINAL_ACCUMULATION);
258- 200+ Compute(tensorAL0, tensorBL0, tensorBiasL0, tensorL0C, l0Shape, needBias, unitFlag, initCmatrix);
259- // Mmad参数
260- AscendC::Te::MmadParams mmadParams(
261- curM, curN, curK0,
262- (enableL0cPingPong_ ? 0 :
263- ((iter0 + 1 == kL1Iter_ && iter1 + 1 == kL0Iter) ? FINAL_ACCUMULATION :
264- NON_FINAL_ACCUMULATION)),
265- (iter0 == 0 && iter1 == 0 && !isBias_));
266- // 传入自定义Trait类型
267- if (NeedProcessBias(iter0, iter1)) {
268- AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0, tensorBiasL0);
269- } else {
270- AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0);
271- }
272 201 
273 AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(static_cast<uint16_t>(mte1Flag));202 AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(static_cast<uint16_t>(mte1Flag));
274 l0PingPong_++;203 l0PingPong_++;
@@ -276,18 +205,13 @@ public:
276 AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId);205 AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId);
277 abL1LoopCnt_++;206 abL1LoopCnt_++;
278 }207 }
279- if (enableL0cPingPong_) {
280- AscendC::SetFlag<AscendC::HardEvent::M_FIX>(l0cPingPong_ & 0x1);
281- AscendC::WaitFlag<AscendC::HardEvent::M_FIX>(l0cPingPong_ & 0x1);
282- }
283 208 
284 // 数据搬出到GM209 // 数据搬出到GM
285- AscendC::Te::FixpipeParams fixpParams(enableL0cPingPong_ ? 0 : FINAL_ACCUMULATION);210+ AscendC::Te::FixpipeParams fixpParams{FINAL_ACCUMULATION};
286 auto copyL0C2GM = AscendC::Te::MakeCopy(AscendC::Te::CopyL0C2GM{});211 auto copyL0C2GM = AscendC::Te::MakeCopy(AscendC::Te::CopyL0C2GM{});
287 AscendC::Te::Copy(copyL0C2GM.with(fixpParams), gmC, tensorL0C);212 AscendC::Te::Copy(copyL0C2GM.with(fixpParams), gmC, tensorL0C);
288 213 
289 if (enableL0cPingPong_) {214 if (enableL0cPingPong_) {
290- AscendC::SetFlag<AscendC::HardEvent::FIX_M>(l0cPingPong_ & 0x1);
291 l0cPingPong_++;215 l0cPingPong_++;
292 }216 }
293 }217 }
@@ -298,21 +222,119 @@ private:
298 return isBias_ && kIter0 == 0 && kIter1 == 0;222 return isBias_ && kIter0 == 0 && kIter1 == 0;
299 }223 }
300 224 
225+ template <typename TensorA, typename TensorB, typename TensorBias>
226+ __aicore__ inline auto CopyL1FromGM(
227+ const TensorA& tensorA, const TensorB& tensorB, const TensorBias& tensorBias,
228+ const TileShape& l1Shape, uint64_t l1BufId, uint64_t kIdx)
229+ {
230+ uint64_t curM = AscendC::Te::Get<0>(l1Shape);
231+ uint64_t curN = AscendC::Te::Get<1>(l1Shape);
232+ uint64_t curKL1 = AscendC::Te::Get<2>(l1Shape);
233+ 
234+ // A GM->L1
235+ auto layoutAL1 = MakeLayoutAL1{}(curM, curKL1);
236+ auto copyGM2L1 = AscendC::Te::MakeCopy(AscendC::Te::CopyGM2L1{});
237+ auto tensorAL1 = AscendC::Te::MakeTensor(
238+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, AType>(aL1Buffer_[l1BufId]), layoutAL1);
239+ auto gmTileA = tensorA.Slice(AscendC::Te::MakeCoord(0, kIdx * kL1_), AscendC::Te::MakeShape(curM, curKL1));
240+ AscendC::Te::Copy(copyGM2L1, tensorAL1, gmTileA);
241+ 
242+ // B GM->L1
243+ auto layoutBL1 = MakeLayoutBL1{}(curKL1, curN);
244+ auto tensorBL1 = AscendC::Te::MakeTensor(
245+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BType>(bL1Buffer_[l1BufId]), layoutBL1);
246+ auto gmTileB = tensorB.Slice(AscendC::Te::MakeCoord(kIdx * kL1_, 0), AscendC::Te::MakeShape(curKL1, curN));
247+ AscendC::Te::Copy(copyGM2L1, tensorBL1, gmTileB);
248+ 
249+ // Bias GM->L1 TODO bias不开启4buffer?
250+ auto layoutBiasL1 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, curN);
251+ auto tensorBiasL1 = AscendC::Te::MakeTensor(
252+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BiasType>(biasL1Buffer_[l1BufId]), layoutBiasL1);
253+ if (isBias_ && kIdx == 0) {
254+ AscendC::Te::Copy(copyGM2L1, tensorBiasL1, tensorBias);
255+ }
256+ 
257+ return AscendC::Std::make_tuple(tensorAL1, tensorBL1, tensorBiasL1);
258+ }
259+ 
260+ template <typename TensorA, typename TensorB, typename TensorBias>
261+ __aicore__ inline auto CopyL0FromL1(
262+ const TensorA& tensorAL1, const TensorB& tensorBL1, const TensorBias& tensorBiasL1,
263+ const TileShape& l0Shape, uint64_t l0Offset, uint64_t kIdx, bool needBias, uint64_t btBufId) {
264+ auto curM = AscendC::Te::Get<0>(l0Shape);
265+ auto curN = AscendC::Te::Get<1>(l0Shape);
266+ auto curK0 = AscendC::Te::Get<2>(l0Shape);
267+ 
268+ // A L1->L0A
269+ auto copyL12L0A = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0A{});
270+ auto layoutAL0 =
271+ AscendC::Te::MakeFrameLayout<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>(
272+ curM, curK0);
273+ auto tensorAL0 = AscendC::Te::MakeTensor(
274+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0A, AType>(l0Offset), layoutAL0);
275+ auto tensorBlockAL1 =
276+ tensorAL1.Slice(AscendC::Te::MakeCoord(0, kIdx), AscendC::Te::MakeShape(curM, curK0));
277+ AscendC::Te::Copy(copyL12L0A, tensorAL0, tensorBlockAL1);
278+ 
279+ // B L1->L0B
280+ auto copyL12L0B = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0B{});
281+ auto layoutBL0 =
282+ AscendC::Te::MakeFrameLayout<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>(
283+ curK0, curN);
284+ auto tensorBL0 = AscendC::Te::MakeTensor(
285+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0B, BType>(l0Offset), layoutBL0);
286+ auto tensorBlockBL1 =
287+ tensorBL1.Slice(AscendC::Te::MakeCoord(kIdx, 0), AscendC::Te::MakeShape(curK0, curN));
288+ AscendC::Te::Copy(copyL12L0B, tensorBL0, tensorBlockBL1);
289+ 
290+ // Bias L1->L0
291+ uint64_t nl1Align = Blaze::Gemm::CeilAlign(curN, static_cast<int64_t>(AscendC::BLOCK_CUBE));
292+ auto layoutBiasL0 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, nl1Align);
293+ auto offsetBiasL0 = baseN_ * btBufId * sizeof(float);
294+ auto tensorBiasL0 = AscendC::Te::MakeTensor(
295+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::BIAS, float>(offsetBiasL0), layoutBiasL0);
296+ if (needBias) {
297+ auto copyL12BT = AscendC::Te::MakeCopy(AscendC::Te::CopyL12BT{});
298+ AscendC::Te::Copy(copyL12BT, tensorBiasL0, tensorBiasL1);
299+ }
300+ 
301+ return AscendC::Std::make_tuple(tensorAL0, tensorBL0, tensorBiasL0);
302+ }
303+ 
304+ template <typename TensorA, typename TensorB, typename TensorBias, typename TensorC>
305+ __aicore__ inline void Compute(const TensorA& tensorAL0, const TensorB& tensorBL0, const TensorBias& tensorBiasL0,
306+ TensorC& tensorL0C, const TileShape& l0Shape, bool needBias, uint8_t unitFlag, bool initCmatrix) {
307+ constexpr auto mmadAtom =
308+ AscendC::Te::MakeMmad(AscendC::Te::MmadOperation{}, AscendC::Te::MmadTraitDefault{});
309+ auto curM = AscendC::Te::Get<0>(l0Shape);
310+ auto curN = AscendC::Te::Get<1>(l0Shape);
311+ auto curK0 = AscendC::Te::Get<2>(l0Shape);
312+ // Mmad参数
313+ AscendC::Te::MmadParams mmadParams{
314+ static_cast<uint16_t>(curM), static_cast<uint16_t>(curN), static_cast<uint16_t>(curK0), unitFlag, initCmatrix};
315+ // 传入自定义Trait类型
316+ if (needBias) {
317+ AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0, tensorBiasL0);
318+ } else {
319+ AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0);
320+ }
321+ }
322+ 
301private:323private:
302- constexpr static uint16_t DIMENSION_M = 0;324+ constexpr static uint16_t MTE1_MTE2_EVENT_ID_NUM = 4;
303- constexpr static uint16_t DIMENSION_N = 1;325+
304- constexpr static uint16_t DIMENSION_K = 2;
305- constexpr static uint16_t ZERO_FLAG = 0;
306- constexpr static uint16_t FIRST_FLAG = 1;
307- constexpr static uint16_t SECOND_FLAG = 2;
308- constexpr static uint16_t THIRD_FLAG = 3;
309- constexpr static uint16_t FOURTH_FLAG = 4;
310- constexpr static uint16_t FIFTH_FLAG = 5;
311- constexpr static uint16_t SIXTH_FLAG = 6;
312- constexpr static uint16_t SEVENTH_FLAG = 7;
313- constexpr static int32_t BT_SIZE = 4096;
314 uint64_t aL1OneBuffer_ = 0;326 uint64_t aL1OneBuffer_ = 0;
315 uint64_t bL1OneBuffer_ = 0;327 uint64_t bL1OneBuffer_ = 0;
328+ uint64_t kL1Iter_{0};
329+ uint32_t l1Stages_{1};
330+ uint64_t abL1LoopCnt_{0};
331+ uint64_t l0PingPong_{0};
332+ uint64_t l0cPingPong_{0};
333+ bool isBias_{false};
334+ bool enableL0cPingPong_{false};
335+ uint64_t aL1Buffer_[4] = {0};
336+ uint64_t bL1Buffer_[4] = {0};
337+ uint64_t biasL1Buffer_[4] = {0};
316};338};
317} // namespace Block339} // namespace Block
318} // namespace Gemm340} // namespace Gemm
@@ -15,10 +15,11 @@
15 15 
16#pragma once16#pragma once
17 17 
18-#include "blaze/gemm/policy/dispatch_policy.h"
19#include "blaze/gemm/utils/common_utils.h"18#include "blaze/gemm/utils/common_utils.h"
20-#include "tensor_api/tensor.h"19+#include "blaze/gemm/utils/layout_utils.h"
20+#include "blaze/gemm/policy/dispatch_policy.h"
21#include "block_mmad.h"21#include "block_mmad.h"
22+#include "tensor_api/tensor.h"
22 23 
23namespace Blaze {24namespace Blaze {
24namespace Gemm {25namespace Gemm {
@@ -41,43 +42,12 @@ public:
41 using LayoutBias = LayoutBias_;42 using LayoutBias = LayoutBias_;
42 using DispatchPolicy = MatmulMultiBlockWithStreamK<FixpOpti_, FUSED_OP_TYPE_>;43 using DispatchPolicy = MatmulMultiBlockWithStreamK<FixpOpti_, FUSED_OP_TYPE_>;
43 using TupleShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;44 using TupleShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
44- static constexpr bool transA = !(AscendC::Std::is_same_v<LayoutA, AscendC::Te::NDExtLayoutPtn>);45+ using TileShape = AscendC::Te::Shape<int64_t, int64_t, int64_t>;
45- static constexpr bool transB =
46- !(AscendC::Std::is_same_v<LayoutB, AscendC::Te::NDExtLayoutPtn> ||
47- AscendC::Std::is_same_v<LayoutB, AscendC::Te::NZLayoutPtn>);
48- uint64_t m_{1};
49- uint64_t n_{1};
50- uint64_t k_{1};
51- uint64_t mL1_{1};
52- uint64_t nL1_{1};
53- uint64_t kL1_{1};
54- uint64_t baseM_{16};
55- uint64_t baseN_{16};
56- uint64_t baseK_{16};
57 46 
58- bool isBias_{false};47+ static constexpr bool transA = IsTrans<LayoutA>::value;
59- constexpr static uint64_t BUFFER_NUM = 2;48+ static constexpr bool transB = IsTrans<LayoutB>::value;
60- constexpr static uint64_t HALF_L0_SIZE = AscendC::TOTAL_L0A_SIZE / BUFFER_NUM;49+ static constexpr bool weightNZFormat = IsWeightNz<LayoutB>::value;
61- uint64_t abL1LoopCnt_{0};
62- uint64_t l0PingPong_{0};
63- struct GmParams {
64- GM_ADDR aGmAddr{nullptr};
65- GM_ADDR bGmAddr{nullptr};
66- GM_ADDR cGmAddr{nullptr};
67- GM_ADDR biasGmAddr{nullptr};
68- GM_ADDR groupListGmAddr{nullptr};
69- GM_ADDR workspaceGmAddr{nullptr};
70- };
71 50 
72-private:
73- uint64_t biasL1Offset_ = 0;
74- uint64_t bL1Init_ = 0;
75- uint64_t aL1OneBuffer_ = 0;
76- uint64_t bL1OneBuffer_ = 0;
77- constexpr static uint16_t L1_EVENT_ID_OFFSET = 2;
78- constexpr static uint16_t MTE1_MTE2_EVENT_ID_NUM = 4;
79- 
80-public:
81 using MakeLayoutAL1 = AscendC::Std::conditional_t<51 using MakeLayoutAL1 = AscendC::Std::conditional_t<
82 transA, AscendC::Te::FrameLayoutFormat<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>,52 transA, AscendC::Te::FrameLayoutFormat<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>,
83 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>>;53 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>>;
@@ -85,157 +55,143 @@ public:
85 transB, AscendC::Te::FrameLayoutFormat<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>,55 transB, AscendC::Te::FrameLayoutFormat<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>,
86 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>>;56 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>>;
87 57 
58+ struct Params {
59+ GM_ADDR aGmAddr{nullptr};
60+ GM_ADDR bGmAddr{nullptr};
61+ GM_ADDR cGmAddr{nullptr};
62+ GM_ADDR biasGmAddr{nullptr};
63+ GM_ADDR groupListGmAddr{nullptr};
64+ GM_ADDR workspaceGmAddr{nullptr};
65+ uint64_t ml1{0};
66+ uint64_t nl1{0};
67+ uint64_t kl1{0};
68+ uint32_t ml0{0};
69+ uint32_t nl0{0};
70+ uint32_t kl0{0};
71+ uint32_t l1Stages{2};
72+ uint16_t l0cStages{1};
73+ };
74+ 
75+public:
88 __aicore__ inline BlockMmad()76 __aicore__ inline BlockMmad()
89 {77 {
90- for (uint16_t i = 0; i < MTE1_MTE2_EVENT_ID_NUM; i++) {78+ if ASCEND_IS_NOT_AIV {
91- AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(i);79+ for (uint16_t i = 0; i < MTE1_MTE2_EVENT_ID_NUM; i++) {
80+ AscendC::SetFlag<AscendC::HardEvent::MTE1_MTE2>(i);
81+ }
82+ AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(ZERO_FLAG);
83+ AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(FIRST_FLAG);
84+ SetMMLayoutTransform(true);
92 }85 }
93- AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(ZERO_FLAG);
94- AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(FIRST_FLAG);
95 }86 }
96 87 
97 __aicore__ inline ~BlockMmad()88 __aicore__ inline ~BlockMmad()
98 {89 {
99- for (uint16_t i = 0; i < MTE1_MTE2_EVENT_ID_NUM; i++) {90+ if ASCEND_IS_NOT_AIV {
100- AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(i);91+ for (uint16_t i = 0; i < MTE1_MTE2_EVENT_ID_NUM; i++) {
92+ AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(i);
93+ }
94+ AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(ZERO_FLAG);
95+ AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(FIRST_FLAG);
96+ SetMMLayoutTransform(false);
101 }97 }
102- AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(ZERO_FLAG);
103- AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(FIRST_FLAG);
104 }98 }
105 99 
106-public:100+ __aicore__ inline void Init(const TupleShape& shape, const Params& params)
107- __aicore__ inline void Init(
108- const TupleShape& shape, const TupleShape& tileL1, const TupleShape& tileL0, bool isBias)
109 {101 {
110- m_ = Get<MNK_M>(shape);102+ m_ = AscendC::Te::Get<DIMENSION_M>(shape);
111- n_ = Get<MNK_N>(shape);103+ n_ = AscendC::Te::Get<DIMENSION_N>(shape);
112- k_ = Get<MNK_K>(shape);104+ k_ = AscendC::Te::Get<DIMENSION_K>(shape);
113 105 
114- mL1_ = Get<MNK_M>(tileL1);106+ mL1_ = params.ml1;
115- nL1_ = Get<MNK_N>(tileL1);107+ nL1_ = params.nl1;
116- kL1_ = Get<MNK_K>(tileL1);108+ kL1_ = params.kl1;
109+ baseM_ = params.ml0;
110+ baseN_ = params.nl0;
111+ baseK_ = params.kl0;
117 112 
118- baseM_ = Get<MNK_M>(tileL0);113+ isBias_ = params.biasGmAddr != nullptr;
119- baseN_ = Get<MNK_N>(tileL0);114+ l1Stages_ = params.l1Stages;
120- baseK_ = Get<MNK_K>(tileL0);115+ 
121- isBias_ = isBias;116+ aL1OneBuffer_ = mL1_ * kL1_ * sizeof(AType);
122- // init tensor117+ bL1OneBuffer_ = nL1_ * kL1_ * sizeof(BType);
123- if (isBias_) {118+ 
124- biasL1Offset_ = nL1_ * sizeof(BiasType) * BUFFER_NUM;119+ constexpr static uint64_t QUARTER_L1_SIZE = AscendC::TOTAL_L1_SIZE / QUADRUPLE_BUFFER_COUNT;
120+ for (auto i = 0; i < l1Stages_; ++i) {
121+ aL1Buffer_[i] = QUARTER_L1_SIZE * (QUADRUPLE_BUFFER_COUNT / l1Stages_) * i;
122+ bL1Buffer_[i] = aL1Buffer_[i] + aL1OneBuffer_;
123+ biasL1Buffer_[i] = bL1Buffer_[i] + bL1OneBuffer_;
125 }124 }
126- aL1OneBuffer_ = mL1_ * kL1_;125+ 
127- bL1Init_ = biasL1Offset_ + aL1OneBuffer_ * BUFFER_NUM;
128- bL1OneBuffer_ = nL1_ * kL1_;
129 l0PingPong_ = 0;126 l0PingPong_ = 0;
130 abL1LoopCnt_ = 0;127 abL1LoopCnt_ = 0;
131 }128 }
132 129 
133- template <typename TensorC, typename TensorA, typename TensorB, typename TensorBias, typename TensorWorkspace>130+ template <typename TensorA, typename TensorB, typename TensorBias, typename TensorC, typename TensorWorkspace>
134 __aicore__ inline void operator()(131 __aicore__ inline void operator()(
135- TensorC gmC, TensorA gmA, TensorB gmB, TensorBias gmBias, TensorWorkspace gmWorkspace, TupleShape tileShape,132+ TensorA& gmA, TensorB& gmB, TensorBias& gmBias, TensorC& gmC, TensorWorkspace gmWorkspace, TupleShape tileShape,
136 int64_t kCntIndex, bool checkIsSkScene)133 int64_t kCntIndex, bool checkIsSkScene)
137 {134 {
138- // mL1_ == ml0, nL1_ == nl0135+ constexpr static uint64_t HALF_L0_SIZE = AscendC::TOTAL_L0A_SIZE / DOUBLE_BUFFER_COUNT;
139- uint64_t curML1 = Get<MNK_M>(tileShape);136+ uint64_t curML1 = AscendC::Te::Get<MNK_M>(tileShape);
140- uint64_t curNL1 = Get<MNK_N>(tileShape);137+ uint64_t curNL1 = AscendC::Te::Get<MNK_N>(tileShape);
141- uint64_t curSingleCoreK = Get<MNK_K>(tileShape);138+ uint64_t curSingleCoreK = AscendC::Te::Get<MNK_K>(tileShape);
142- uint64_t curKL1Iter = (curSingleCoreK + kL1_ - 1) / kL1_;139+ uint64_t curKL1Iter = Blaze::Gemm::CeilDiv(curSingleCoreK, kL1_);
143- uint64_t nl1Align = CeilAlign(curNL1, static_cast<uint64_t>(AscendC::BLOCK_CUBE));140+ uint64_t nl1Align = Blaze::Gemm::CeilAlign(curNL1, static_cast<uint64_t>(AscendC::BLOCK_CUBE));
144- uint64_t l0cOffset = 0;141+ 
145 auto layoutL0C =142 auto layoutL0C =
146 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Std::Int<C0_SIZE_L0C>>{}(curML1, curNL1);143 AscendC::Te::FrameLayoutFormat<AscendC::Te::NZLayoutPtn, AscendC::Std::Int<C0_SIZE_L0C>>{}(curML1, curNL1);
147 auto tensorL0C =144 auto tensorL0C =
148- AscendC::Te::MakeTensor(AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0C, float>(l0cOffset), layoutL0C);145+ AscendC::Te::MakeTensor(AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0C, float>(0), layoutL0C);
146+ 
149 for (uint64_t iter0 = 0; iter0 < curKL1Iter; ++iter0) {147 for (uint64_t iter0 = 0; iter0 < curKL1Iter; ++iter0) {
150 uint64_t curKL1 = (iter0 + 1 == curKL1Iter) ? (curSingleCoreK - iter0 * kL1_) : kL1_;148 uint64_t curKL1 = (iter0 + 1 == curKL1Iter) ? (curSingleCoreK - iter0 * kL1_) : kL1_;
151- // switch on pingpong, now only support double buffer in streamk149+ uint64_t l1BufId = abL1LoopCnt_ & (l1Stages_ - 1);
152- uint64_t l1BufId = abL1LoopCnt_ & (BUFFER_NUM - 1);
153- uint64_t offsetAL1 = (biasL1Offset_ + aL1OneBuffer_ * l1BufId) * sizeof(AType);
154- AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId);
155- auto copyGM2L1 = AscendC::Te::MakeCopy(AscendC::Te::CopyGM2L1());
156 150 
157- // copy bias to l1151+ AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId);
158- uint64_t biasBufId = abL1LoopCnt_ & 0x1;152+ 
159- uint64_t offsetBiasL1 = nL1_ * l1BufId * sizeof(BiasType);153+ TileShape l1Shape{curML1, curNL1, curKL1};
160- auto layoutBiasL1 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, curNL1);154+ // Copy L1 From GM
161- auto tensorBiasL1 = AscendC::Te::MakeTensor(155+ auto l1TensorTuple = CopyL1FromGM(gmA, gmB, gmBias, l1Shape, l1BufId, iter0, kCntIndex);
162- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BiasType>(offsetBiasL1), layoutBiasL1);156+ auto tensorAL1 = AscendC::Te::Get<0>(l1TensorTuple);
163- if (isBias_ && iter0 == 0 && kCntIndex == 0) {157+ auto tensorBL1 = AscendC::Te::Get<1>(l1TensorTuple);
164- AscendC::Te::Copy(copyGM2L1, tensorBiasL1, gmBias);158+ auto tensorBiasL1 = AscendC::Te::Get<2>(l1TensorTuple);
165- }
166- // copy tensor a to l1
167- auto layoutAL1 = MakeLayoutAL1{}(curML1, curKL1);
168- auto tensorAL1 = AscendC::Te::MakeTensor(
169- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, AType>(offsetAL1), layoutAL1);
170- auto gmTileA = gmA.Slice(AscendC::Te::MakeCoord(0, iter0 * kL1_), AscendC::Te::MakeShape(curML1, curKL1));
171- AscendC::Te::Copy(copyGM2L1, tensorAL1, gmTileA);
172 159 
173 AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);160 AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);
174 AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);161 AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId);
175- // copy tensor b to l1162+ 
176- uint64_t offsetBL1 = (bL1Init_ + bL1OneBuffer_ * l1BufId) * sizeof(BType);
177 AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId + L1_EVENT_ID_OFFSET);163 AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId + L1_EVENT_ID_OFFSET);
178- auto layoutBL1 = MakeLayoutBL1{}(curKL1, curNL1);
179- auto tensorBL1 = AscendC::Te::MakeTensor(
180- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BType>(offsetBL1), layoutBL1);
181- auto gmTileB = gmB.Slice(AscendC::Te::MakeCoord(iter0 * kL1_, 0), AscendC::Te::MakeShape(curKL1, curNL1));
182- AscendC::Te::Copy(copyGM2L1, tensorBL1, gmTileB);
183 AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId + L1_EVENT_ID_OFFSET);164 AscendC::SetFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId + L1_EVENT_ID_OFFSET);
184 165 
185- uint64_t kL0Iter = (curKL1 + baseK_ - 1) / baseK_;166+ uint64_t kL0Iter = Blaze::Gemm::CeilDiv(curKL1, baseK_);
186 for (uint64_t iter1 = 0; iter1 < kL0Iter; ++iter1) {167 for (uint64_t iter1 = 0; iter1 < kL0Iter; ++iter1) {
187 uint64_t curK0 = (iter1 + 1 == kL0Iter) ? (curKL1 - iter1 * baseK_) : baseK_;168 uint64_t curK0 = (iter1 + 1 == kL0Iter) ? (curKL1 - iter1 * baseK_) : baseK_;
188 uint64_t l0Offset = HALF_L0_SIZE * (l0PingPong_ & 0x1);169 uint64_t l0Offset = HALF_L0_SIZE * (l0PingPong_ & 0x1);
189- // copy aL1 to l0a170+ uint64_t mte1Flag = l0PingPong_ & 0x1;
190- auto copyL12L0A = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0A{});171+ 
191- AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(l0PingPong_ & 0x1);172+ AscendC::WaitFlag<AscendC::HardEvent::M_MTE1>(static_cast<uint16_t>(mte1Flag));
192- auto layoutAL0 =173+ 
193- AscendC::Te::MakeFrameLayout<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>(174+ TileShape l0Shape{curML1, curNL1, curK0};
194- curML1, curK0);175+ bool needBias = NeedProcessBias(iter0, iter1, kCntIndex);
195- auto tensorAL0 = AscendC::Te::MakeTensor(176+ // Copy L0 From L1
196- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0A, AType>(l0Offset), layoutAL0);177+ auto l0TensorTuple = CopyL0FromL1(
197- auto tensorBlockAL1 =178+ tensorAL1, tensorBL1, tensorBiasL1, l0Shape, l0Offset, baseK_ * iter1, needBias, l1BufId, iter1,
198- tensorAL1.Slice(AscendC::Te::MakeCoord(0, iter1 * baseK_), AscendC::Te::MakeShape(curML1, curK0));179+ kCntIndex);
199- AscendC::Te::Copy(copyL12L0A, tensorAL0, tensorBlockAL1);180+ 
200- if (iter1 == 0) {181+ auto tensorAL0 = AscendC::Te::Get<0>(l0TensorTuple);
201- AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(l1BufId + L1_EVENT_ID_OFFSET);182+ auto tensorBL0 = AscendC::Te::Get<1>(l0TensorTuple);
202- }183+ auto tensorBiasL0 = AscendC::Te::Get<2>(l0TensorTuple);
203- // copy bias to biastable184+ 
204- auto layoutBiasL0 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, nl1Align);185+ AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(static_cast<uint16_t>(mte1Flag));
205- uint64_t offsetBiasL0 = nL1_ * biasBufId * sizeof(float);186+ AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(static_cast<uint16_t>(mte1Flag));
206- auto tensorBiasL0 = AscendC::Te::MakeTensor(
207- AscendC::Te::MakeMemPtr<AscendC::Te::Location::BIAS, float>(offsetBiasL0), layoutBiasL0);
208- if (isBias_ && iter0 == 0 && iter1 == 0 && kCntIndex == 0) {
209- auto copyL12BT = AscendC::Te::MakeCopy(AscendC::Te::CopyL12BT{});
210- AscendC::Te::Copy(copyL12BT, tensorBiasL0, tensorBiasL1);
211- }
212- // copy bL1 to l0b
213- auto copyL12L0B = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0B{});
214- auto layoutBL0 =
215- AscendC::Te::MakeFrameLayout<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>(
216- curK0, curNL1);
217- auto tensorBL0 = AscendC::Te::MakeTensor(
218- AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0B, BType>(l0Offset), layoutBL0);
219- auto tensorBlockBL1 =
220- tensorBL1.Slice(AscendC::Te::MakeCoord(iter1 * baseK_, 0), AscendC::Te::MakeShape(curK0, curNL1));
221- AscendC::Te::Copy(copyL12L0B, tensorBL0, tensorBlockBL1);
222 187 
223- AscendC::SetFlag<AscendC::HardEvent::MTE1_M>(l0PingPong_ & 0x1);
224- AscendC::WaitFlag<AscendC::HardEvent::MTE1_M>(l0PingPong_ & 0x1);
225 uint8_t unitFlag =188 uint8_t unitFlag =
226 (iter0 + 1 == curKL1Iter && iter1 + 1 == kL0Iter) ? FINAL_ACCUMULATION : NON_FINAL_ACCUMULATION;189 (iter0 + 1 == curKL1Iter && iter1 + 1 == kL0Iter) ? FINAL_ACCUMULATION : NON_FINAL_ACCUMULATION;
227- bool cmatrixInitVal = (iter0 == 0 && iter1 == 0 && (!isBias_ || (isBias_ && kCntIndex != 0)));190+ bool initCmatrix = iter0 == 0 && iter1 == 0 && (!isBias_ || (isBias_ && kCntIndex != 0));
228- AscendC::Te::MmadParams mmadParams(curML1, curNL1, curK0, unitFlag, cmatrixInitVal);191+ // Mmad
229- constexpr auto mmadAtom =192+ Compute(tensorAL0, tensorBL0, tensorBiasL0, tensorL0C, l0Shape, needBias, unitFlag, initCmatrix);
230- AscendC::Te::MakeMmad(AscendC::Te::MmadOperation{}, AscendC::Te::MmadTraitDefault{});
231 193 
232- if (isBias_ && iter0 == 0 && iter1 == 0 && kCntIndex == 0) {194+ AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(static_cast<uint16_t>(mte1Flag));
233- AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0, tensorBiasL0);
234- } else {
235- AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0);
236- }
237- 
238- AscendC::SetFlag<AscendC::HardEvent::M_MTE1>(l0PingPong_ & 0x1);
239 l0PingPong_++;195 l0PingPong_++;
240 }196 }
241 if (iter0 + 1 == curKL1Iter) {197 if (iter0 + 1 == curKL1Iter) {
@@ -252,7 +208,136 @@ public:
252 abL1LoopCnt_++;208 abL1LoopCnt_++;
253 }209 }
254 }210 }
211+ 
212+private:
213+ __aicore__ inline bool NeedProcessBias(uint64_t kIter0, uint64_t kIter1, int64_t kCntIndex)
214+ {
215+ return isBias_ && kIter0 == 0 && kIter1 == 0 && kCntIndex == 0;
216+ }
217+ 
218+ template <typename TensorA, typename TensorB, typename TensorBias>
219+ __aicore__ inline auto CopyL1FromGM(
220+ const TensorA& tensorA, const TensorB& tensorB, const TensorBias& tensorBias, const TileShape& l1Shape,
221+ uint64_t l1BufId, uint64_t kIdx, int64_t kCntIndex)
222+ {
223+ uint64_t curM = AscendC::Te::Get<0>(l1Shape);
224+ uint64_t curN = AscendC::Te::Get<1>(l1Shape);
225+ uint64_t curKL1 = AscendC::Te::Get<2>(l1Shape);
226+ 
227+ auto copyGM2L1 = AscendC::Te::MakeCopy(AscendC::Te::CopyGM2L1{});
228+ 
229+ auto layoutAL1 = MakeLayoutAL1{}(curM, curKL1);
230+ auto tensorAL1 = AscendC::Te::MakeTensor(
231+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, AType>(aL1Buffer_[l1BufId]), layoutAL1);
232+ auto gmTileA = tensorA.Slice(AscendC::Te::MakeCoord(0, kIdx * kL1_), AscendC::Te::MakeShape(curM, curKL1));
233+ AscendC::Te::Copy(copyGM2L1, tensorAL1, gmTileA);
234+ 
235+ 
236+ auto layoutBL1 = MakeLayoutBL1{}(curKL1, curN);
237+ auto tensorBL1 = AscendC::Te::MakeTensor(
238+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BType>(bL1Buffer_[l1BufId]), layoutBL1);
239+ auto gmTileB = tensorB.Slice(AscendC::Te::MakeCoord(kIdx * kL1_, 0), AscendC::Te::MakeShape(curKL1, curN));
240+ AscendC::Te::Copy(copyGM2L1, tensorBL1, gmTileB);
241+ 
242+ auto layoutBiasL1 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, curN);
243+ auto tensorBiasL1 = AscendC::Te::MakeTensor(
244+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::L1, BiasType>(biasL1Buffer_[l1BufId]), layoutBiasL1);
245+ if (isBias_ && kIdx == 0 && kCntIndex == 0) {
246+ AscendC::Te::Copy(copyGM2L1, tensorBiasL1, tensorBias);
247+ }
248+ 
249+ return AscendC::Std::make_tuple(tensorAL1, tensorBL1, tensorBiasL1);
250+ }
251+ 
252+ template <typename TensorA, typename TensorB, typename TensorBias>
253+ __aicore__ inline auto CopyL0FromL1(
254+ const TensorA& tensorAL1, const TensorB& tensorBL1, const TensorBias& tensorBiasL1, const TileShape& l0Shape,
255+ uint64_t l0Offset, uint64_t kIdx, bool needBias, uint64_t biasBufId, uint64_t iter1, int64_t kCntIndex)
256+ {
257+ uint64_t curM = AscendC::Te::Get<0>(l0Shape);
258+ uint64_t curN = AscendC::Te::Get<1>(l0Shape);
259+ uint64_t curK0 = AscendC::Te::Get<2>(l0Shape);
260+ 
261+ auto copyL12L0A = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0A{});
262+ auto layoutAL0 =
263+ AscendC::Te::MakeFrameLayout<AscendC::Te::NZLayoutPtn, AscendC::Te::LayoutTraitDefault<AType>>(curM, curK0);
264+ auto tensorAL0 =
265+ AscendC::Te::MakeTensor(AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0A, AType>(l0Offset), layoutAL0);
266+ auto tensorBlockAL1 = tensorAL1.Slice(AscendC::Te::MakeCoord(0, kIdx), AscendC::Te::MakeShape(curM, curK0));
267+ AscendC::Te::Copy(copyL12L0A, tensorAL0, tensorBlockAL1);
268+ 
269+ if (iter1 == 0) {
270+ AscendC::WaitFlag<AscendC::HardEvent::MTE2_MTE1>(biasBufId + L1_EVENT_ID_OFFSET);
271+ }
272+ 
273+ uint64_t nl1Align = Blaze::Gemm::CeilAlign(curN, static_cast<uint64_t>(AscendC::BLOCK_CUBE));
274+ auto layoutBiasL0 = AscendC::Te::MakeFrameLayout<AscendC::Te::NDExtLayoutPtn>(1UL, nl1Align);
275+ auto offsetBiasL0 = nL1_ * biasBufId * sizeof(float);
276+ auto tensorBiasL0 = AscendC::Te::MakeTensor(
277+ AscendC::Te::MakeMemPtr<AscendC::Te::Location::BIAS, float>(offsetBiasL0), layoutBiasL0);
278+ if (needBias) {
279+ auto copyL12BT = AscendC::Te::MakeCopy(AscendC::Te::CopyL12BT{});
280+ AscendC::Te::Copy(copyL12BT, tensorBiasL0, tensorBiasL1);
281+ }
282+ 
283+ auto copyL12L0B = AscendC::Te::MakeCopy(AscendC::Te::CopyL12L0B{});
284+ auto layoutBL0 =
285+ AscendC::Te::MakeFrameLayout<AscendC::Te::ZNLayoutPtn, AscendC::Te::LayoutTraitDefault<BType>>(curK0, curN);
286+ auto tensorBL0 =
287+ AscendC::Te::MakeTensor(AscendC::Te::MakeMemPtr<AscendC::Te::Location::L0B, BType>(l0Offset), layoutBL0);
288+ auto tensorBlockBL1 = tensorBL1.Slice(AscendC::Te::MakeCoord(kIdx, 0), AscendC::Te::MakeShape(curK0, curN));
289+ AscendC::Te::Copy(copyL12L0B, tensorBL0, tensorBlockBL1);
290+ 
291+ return AscendC::Std::make_tuple(tensorAL0, tensorBL0, tensorBiasL0);
292+ }
293+ 
294+ template <typename TensorA, typename TensorB, typename TensorBias, typename TensorC>
295+ __aicore__ inline void Compute(
296+ const TensorA& tensorAL0, const TensorB& tensorBL0, const TensorBias& tensorBiasL0, TensorC& tensorL0C,
297+ const TileShape& l0Shape, bool needBias, uint8_t unitFlag, bool initCmatrix)
298+ {
299+ constexpr auto mmadAtom = AscendC::Te::MakeMmad(AscendC::Te::MmadOperation{}, AscendC::Te::MmadTraitDefault{});
300+ auto curM = AscendC::Te::Get<0>(l0Shape);
301+ auto curN = AscendC::Te::Get<1>(l0Shape);
302+ auto curK0 = AscendC::Te::Get<2>(l0Shape);
303+ 
304+ AscendC::Te::MmadParams mmadParams{
305+ static_cast<uint16_t>(curM), static_cast<uint16_t>(curN), static_cast<uint16_t>(curK0), unitFlag,
306+ initCmatrix};
307+ 
308+ if (needBias) {
309+ AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0, tensorBiasL0);
310+ } else {
311+ AscendC::Te::Mmad(mmadAtom.with(mmadParams), tensorL0C, tensorAL0, tensorBL0);
312+ }
313+ }
314+ 
315+private:
316+ static constexpr uint16_t MTE1_MTE2_EVENT_ID_NUM = 4;
317+ static constexpr uint16_t L1_EVENT_ID_OFFSET = 2;
318+ 
319+ uint64_t m_{1};
320+ uint64_t n_{1};
321+ uint64_t k_{1};
322+ uint64_t mL1_{1};
323+ uint64_t nL1_{1};
324+ uint64_t kL1_{1};
325+ uint64_t baseM_{16};
326+ uint64_t baseN_{16};
327+ uint64_t baseK_{16};
328+ uint32_t l1Stages_{2};
329+ 
330+ uint64_t aL1OneBuffer_ = 0;
331+ uint64_t bL1OneBuffer_ = 0;
332+ uint64_t abL1LoopCnt_{0};
333+ uint64_t l0PingPong_{0};
334+ bool isBias_{false};
335+ 
336+ uint64_t aL1Buffer_[4] = {0};
337+ uint64_t bL1Buffer_[4] = {0};
338+ uint64_t biasL1Buffer_[4] = {0};
255};339};
340+ 
256} // namespace Block341} // namespace Block
257} // namespace Gemm342} // namespace Gemm
258} // namespace Blaze343} // namespace Blaze
@@ -16,81 +16,19 @@
16#pragma once16#pragma once
17 17 
18#include "blaze/gemm/utils/common_utils.h"18#include "blaze/gemm/utils/common_utils.h"
19+#include "tensor_api/tensor/layout.h"
19 20 
20namespace Blaze {21namespace Blaze {
21namespace Gemm {22namespace Gemm {
22namespace Block {23namespace Block {
23-constexpr uint16_t A_FULL_LOAD_MODE = 1;
24-constexpr uint16_t B_FULL_LOAD_MODE = 2;
25-constexpr int64_t FP32_K_SWITCH_THRESHOLD = 268435456; // 1024 * 32 * 8192
26-constexpr int64_t FP32_SPLIT_K_THRESHOLD1 = 1024;
27-constexpr int64_t FP32_SPLIT_K_THRESHOLD2 = 8192;
28 24 
29-template <class ProblemShape_, int64_t FullLoadMode_ = 0>25+template <class ProblemShape_, int64_t FullLoadMode_ = 0, bool IsFp32_ = false, bool IsNdFormat_ = true>
30class BlockSchedulerMatmulBasic {26class BlockSchedulerMatmulBasic {
31public:27public:
32- int64_t mTileNum_{0};
33- int64_t nTileNum_{0};
34- int64_t kTileNum_{0};
35- int64_t blockIdx_{0};
36- int64_t perCoreBlockNum_{0};
37- int64_t blockNum_{0};
38- int64_t batch_{0};
39- int64_t innerBatch_{0};
40- int64_t k_{0};
41- int64_t tailL1M_{0};
42- int64_t tailL1N_{0};
43- int64_t mTailCnt_{1};
44- int64_t nTailCnt_{1};
45- int64_t tailCnt_{1};
46- int64_t tileNum_{1};
47- int64_t mainWindow_{1};
48- int64_t mainRow_{1};
49- int64_t tailWindow_{1};
50- int64_t mTileIdx_{1};
51- int64_t nTileIdx_{1};
52- int64_t splitSingleKIdx_{0};
53- int64_t lastTileIdx_{-1};
54- int64_t nSplitOffset_{0};
55- int64_t mSplitOffset_{0};
56- bool isSlice_{false};
57- bool isNdFormat_{true};
58- bool isFp32_{false};
59- bool isSplitSingleK_{false};
60- int64_t blkK_{0};
61- int64_t splitSingleKRound_{0};
62- int64_t splitSingleK_{0};
63- int64_t splitSingleKTail_{0};
64- int64_t mL1_{0};
65- int64_t nL1_{0};
66- int64_t kL1_{0};
67- int64_t baseM_{0};
68- int64_t baseN_{0};
69- int64_t baseK_{0};
70- uint8_t isHf32_{0};
71- uint8_t l1BuferNum_{0};
72- uint8_t l0cDB_{1};
73- uint8_t ubDB_{1};
74- L2CacheMode l2CacheDisable_{L2CacheMode::L2_CACHE_DEFAULT};
75- int64_t sliceM_{1};
76- int64_t srcNdStride_{1};
77- int64_t mL1NormCnt_{0};
78- int64_t mL1TailSplitCnt_{1};
79- int64_t mL1TailMain_{0};
80- int64_t mL1TailLast_{0};
81- int64_t nL1NormCnt_{0};
82- int64_t nL1TailSplitCnt_{1};
83- int64_t nL1TailMain_{0};
84- int64_t nL1TailLast_{0};
85- 
86- static constexpr uint64_t WINDOW_LEN = 4UL;
87- static constexpr uint64_t BLOCK_SIZE_16 = 16UL;
88- static constexpr uint64_t BLOCK_SIZE_32 = 32UL;
89 using BlockShape = Shape<int64_t, int64_t, int64_t, int64_t>;28 using BlockShape = Shape<int64_t, int64_t, int64_t, int64_t>;
90 using BlockL1L0Shape = Shape<int64_t, int64_t, int64_t, int64_t, int64_t, int64_t>;29 using BlockL1L0Shape = Shape<int64_t, int64_t, int64_t, int64_t, int64_t, int64_t>;
91 using BlockCoord = Coord<int64_t, int64_t, int64_t, int64_t>;30 using BlockCoord = Coord<int64_t, int64_t, int64_t, int64_t>;
92 using ProblemShape = ProblemShape_;31 using ProblemShape = ProblemShape_;
93- static constexpr int64_t FullLoadMode = FullLoadMode_;
94 32 
95 struct Params {33 struct Params {
96 uint32_t mL1 = 0;34 uint32_t mL1 = 0;
@@ -105,21 +43,15 @@ public:
105 uint32_t nBaseTailSplitCnt = 1;43 uint32_t nBaseTailSplitCnt = 1;
106 uint32_t mTailMain = 1;44 uint32_t mTailMain = 1;
107 uint32_t nTailMain = 1;45 uint32_t nTailMain = 1;
108- uint8_t isHf32 = 0;46+ uint8_t isHf32 = 0; // HF32开启标志
109- uint8_t l1BufferNum = 0;47+ uint32_t l2CacheMode = L2_CACHE_DEFAULT;
110- uint8_t l0cDB = 1; // 默认不开db为1
111- uint8_t ubDB = 1; // ub默认不开db为1
112- L2CacheMode l2CacheDisable = L2CacheMode::L2_CACHE_DEFAULT; // L2Cache默认使能
113 uint32_t sliceM; // 非连续场景m轴48 uint32_t sliceM; // 非连续场景m轴
114 uint32_t srcNdStride; // 非连续场景m轴stride49 uint32_t srcNdStride; // 非连续场景m轴stride
115 uint32_t innerBatch = 1; // 非连续transpose场景内轴batch值50 uint32_t innerBatch = 1; // 非连续transpose场景内轴batch值
116 };51 };
117 52 
118public:53public:
119- __aicore__ inline BlockSchedulerMatmulBasic(54+ __aicore__ inline BlockSchedulerMatmulBasic(const ProblemShape& shape, const Params& params)
120- const ProblemShape& shape, int64_t blockIdx, int64_t blockNum, const Params& params, bool isFp32 = false,
121- bool isNdFormat = true)
122- : blockIdx_(blockIdx), blockNum_(blockNum), isFp32_(isFp32), isNdFormat_(isNdFormat)
123 {55 {
124 k_ = AscendC::Te::Get<2>(shape);56 k_ = AscendC::Te::Get<2>(shape);
125 batch_ = AscendC::Std::max(AscendC::Te::Get<3>(shape), 1L);57 batch_ = AscendC::Std::max(AscendC::Te::Get<3>(shape), 1L);
@@ -131,15 +63,17 @@ public:
131 baseN_ = params.baseN;63 baseN_ = params.baseN;
132 baseK_ = params.baseK;64 baseK_ = params.baseK;
133 isHf32_ = params.isHf32;65 isHf32_ = params.isHf32;
134- l1BuferNum_ = params.l1BufferNum;
135- l0cDB_ = params.l0cDB;
136- ubDB_ = params.ubDB;
137 int64_t m = AscendC::Te::Get<0>(shape);66 int64_t m = AscendC::Te::Get<0>(shape);
138 int64_t n = AscendC::Te::Get<1>(shape);67 int64_t n = AscendC::Te::Get<1>(shape);
139 mTileNum_ = CeilDiv(static_cast<uint32_t>(m), params.mL1);68 mTileNum_ = CeilDiv(static_cast<uint32_t>(m), params.mL1);
140 nTileNum_ = CeilDiv(static_cast<uint32_t>(n), params.nL1);69 nTileNum_ = CeilDiv(static_cast<uint32_t>(n), params.nL1);
141 kTileNum_ = CeilDiv(static_cast<uint32_t>(k_), params.kL1);70 kTileNum_ = CeilDiv(static_cast<uint32_t>(k_), params.kL1);
142- perCoreBlockNum_ = GetPerBlockNum(blockNum_, mTileNum_, nTileNum_, batch_);71+ blockNum_ = AscendC::GetBlockNum();
72+ if (blockNum_ <= 0) {
73+ return;
74+ }
75+ blockIdx_ = AscendC::GetBlockIdx() / AscendC::GetTaskRation();
76+ perCoreBlockNum_ = CeilDiv(mTileNum_ * nTileNum_ * batch_, blockNum_);
143 tileNum_ = mTileNum_ * nTileNum_;77 tileNum_ = mTileNum_ * nTileNum_;
144 int64_t tailTileNum = tileNum_ % blockNum_;78 int64_t tailTileNum = tileNum_ % blockNum_;
145 mL1TailSplitCnt_ = params.mBaseTailSplitCnt;79 mL1TailSplitCnt_ = params.mBaseTailSplitCnt;
@@ -152,24 +86,26 @@ public:
152 mL1TailLast_ = tailL1M_ - (mL1TailSplitCnt_ - 1) * mL1TailMain_;86 mL1TailLast_ = tailL1M_ - (mL1TailSplitCnt_ - 1) * mL1TailMain_;
153 nL1TailMain_ = nL1TailSplitCnt_ == 1 ? tailL1N_ : params.nTailMain;87 nL1TailMain_ = nL1TailSplitCnt_ == 1 ? tailL1N_ : params.nTailMain;
154 nL1TailLast_ = tailL1N_ - (nL1TailSplitCnt_ - 1) * nL1TailMain_;88 nL1TailLast_ = tailL1N_ - (nL1TailSplitCnt_ - 1) * nL1TailMain_;
155- l2CacheDisable_ = params.l2CacheDisable;
156 sliceM_ = params.sliceM;89 sliceM_ = params.sliceM;
157 srcNdStride_ = params.srcNdStride;90 srcNdStride_ = params.srcNdStride;
158 isSlice_ = srcNdStride_ != 1 && sliceM_ != 0;91 isSlice_ = srcNdStride_ != 1 && sliceM_ != 0;
159 blkK_ = k_;92 blkK_ = k_;
160 int64_t fp32SplitKThreshold = k_ > FP32_K_SWITCH_THRESHOLD ? FP32_SPLIT_K_THRESHOLD2 : FP32_SPLIT_K_THRESHOLD1;93 int64_t fp32SplitKThreshold = k_ > FP32_K_SWITCH_THRESHOLD ? FP32_SPLIT_K_THRESHOLD2 : FP32_SPLIT_K_THRESHOLD1;
161 // 连续且非全载场景切K94 // 连续且非全载场景切K
162- if (!isSlice_ && isFp32_ && !isHf32_ && isNdFormat_ && k_ > fp32SplitKThreshold && FullLoadMode_ == 0) {95+ if constexpr (IS_FP32 && IS_ND_FORMAT && FullLoadMode == 0) {
163- isSplitSingleK_ = true;96+ if (!isSlice_ && !isHf32_ && k_ > fp32SplitKThreshold) {
164- splitSingleK_ = fp32SplitKThreshold;97+ isSplitSingleK_ = true;
165- if (k_ % fp32SplitKThreshold == 0) {98+ splitSingleK_ = fp32SplitKThreshold;
166- splitSingleKRound_ = k_ / fp32SplitKThreshold;99+ if (k_ % fp32SplitKThreshold == 0) {
167- splitSingleKTail_ = fp32SplitKThreshold;100+ splitSingleKRound_ = k_ / fp32SplitKThreshold;
168- } else {101+ splitSingleKTail_ = fp32SplitKThreshold;
169- splitSingleKRound_ = CeilDiv(k_, fp32SplitKThreshold) - 1;102+ } else {
170- splitSingleKTail_ = k_ % splitSingleK_ + splitSingleK_;103+ splitSingleKRound_ = CeilDiv(k_, fp32SplitKThreshold) - 1;
104+ splitSingleKTail_ = k_ % splitSingleK_ + splitSingleK_;
105+ }
171 }106 }
172 }107 }
108+ 
173 if (batch_ == 1) {109 if (batch_ == 1) {
174 mTailCnt_ = params.mTailCnt;110 mTailCnt_ = params.mTailCnt;
175 nTailCnt_ = params.nTailCnt;111 nTailCnt_ = params.nTailCnt;
@@ -185,75 +121,18 @@ public:
185 tailWindow_ = mTileNum_ - mainRow_ * mainWindow_;121 tailWindow_ = mTileNum_ - mainRow_ * mainWindow_;
186 }122 }
187 123 
188- __aicore__ inline void DisableSplitSingleK()
189- {
190- isSplitSingleK_ = false;
191- }
192- 
193 __aicore__ inline int64_t GetTileNum()124 __aicore__ inline int64_t GetTileNum()
194 {125 {
195 return tileNum_ * batch_;126 return tileNum_ * batch_;
196 }127 }
197 128 
198- __aicore__ inline bool Gethf32Flag()129+ __aicore__ inline int64_t GetBlockNum(ProblemShape shape)
199- {
200- return isHf32_ > 0;
201- }
202- 
203- __aicore__ inline uint64_t GetL1BuferNum_()
204- {
205- return static_cast<uint64_t>(l1BuferNum_);
206- }
207- 
208- __aicore__ inline bool GetL0cDB()
209- {
210- return l0cDB_ > 1;
211- }
212- 
213- __aicore__ inline bool GetUbDB()
214- {
215- return ubDB_ > 1;
216- }
217- 
218- __aicore__ inline bool GetAL2CacheDisable()
219- {
220- return (
221- l2CacheDisable_ == L2CacheMode::ALL_L2_CACHE_DISABLE || l2CacheDisable_ == L2CacheMode::A_L2_CACHE_DISABLE);
222- }
223- 
224- __aicore__ inline bool GetBL2CacheDisable()
225- {
226- return (
227- l2CacheDisable_ == L2CacheMode::ALL_L2_CACHE_DISABLE || l2CacheDisable_ == L2CacheMode::B_L2_CACHE_DISABLE);
228- }
229- 
230- __aicore__ inline Shape<int64_t, int64_t, int64_t> GetNonContinuousParams()
231- {
232- return {sliceM_, srcNdStride_, innerBatch_};
233- }
234- 
235- __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTailParams()
236- {
237- return {mL1NormCnt_, mL1TailMain_, nL1NormCnt_, nL1TailMain_};
238- }
239- 
240- __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL1Shape()
241- {
242- return {mL1_, nL1_, kL1_, 1};
243- }
244- 
245- __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL0Shape()
246- {
247- return {baseM_, baseN_, baseK_, 1};
248- }
249- 
250- __aicore__ inline int64_t GetBlockNum(ProblemShape shape, int64_t blockNum)
251 {130 {
252 int64_t tilingBlockNum = 0;131 int64_t tilingBlockNum = 0;
253- if (tileNum_ * batch_ < blockNum) {132+ if (tileNum_ * batch_ < blockNum_) {
254 tilingBlockNum = tileNum_ * batch_;133 tilingBlockNum = tileNum_ * batch_;
255 } else {134 } else {
256- tilingBlockNum = blockNum;135+ tilingBlockNum = blockNum_;
257 }136 }
258 return tilingBlockNum;137 return tilingBlockNum;
259 }138 }
@@ -292,7 +171,7 @@ public:
292 // SplitM and SplitN171 // SplitM and SplitN
293 int64_t splitBlkM = CeilDiv(blkM, mTailCnt_);172 int64_t splitBlkM = CeilDiv(blkM, mTailCnt_);
294 int64_t splitBlkN = CeilDiv(blkN, nTailCnt_);173 int64_t splitBlkN = CeilDiv(blkN, nTailCnt_);
295- if (!isNdFormat_) {174+ if constexpr (!IsNdFormat_) {
296 splitBlkN = CeilAlign(splitBlkN, nAlignSize);175 splitBlkN = CeilAlign(splitBlkN, nAlignSize);
297 nTailCnt_ = CeilDiv(blkN, splitBlkN);176 nTailCnt_ = CeilDiv(blkN, splitBlkN);
298 }177 }
@@ -321,43 +200,18 @@ public:
321 int64_t mOffset = mTileIdx_ * mL1_ + mSplitOffset_;200 int64_t mOffset = mTileIdx_ * mL1_ + mSplitOffset_;
322 int64_t nOffset = nTileIdx_ * nL1_ + nSplitOffset_;201 int64_t nOffset = nTileIdx_ * nL1_ + nSplitOffset_;
323 int64_t ndNum = mL1_ > sliceM_ ? mL1_ / sliceM_ : 1;202 int64_t ndNum = mL1_ > sliceM_ ? mL1_ / sliceM_ : 1;
324- // 非连续计算m方向上的起点坐标203+ int64_t kOffset = 0; // 当前不切K
325- int64_t mOffsetNonContiguous = mTileIdx_ * (ndNum * (srcNdStride_ / k_)) + mSplitOffset_;
326- if (mTileIdx_ > mL1NormCnt_) {
327- mOffset = mL1NormCnt_ * mL1_ + (mTileIdx_ - mL1NormCnt_) * mL1TailMain_ + mSplitOffset_;
328- }
329- if (nTileIdx_ > nL1NormCnt_) {
330- nOffset = nL1NormCnt_ * nL1_ + (nTileIdx_ - nL1NormCnt_) * nL1TailMain_ + nSplitOffset_;
331- }
332- // 当前不切k, 使用kOffset传递非连续场景mOffset
333- return {mOffset, nOffset, mOffsetNonContiguous, batchIdx};
334- }
335 204 
336- __aicore__ inline BlockCoord GetSplitKBlockCoord(int tileIdx)
337- {
338- UpdateMNTileIdx(tileIdx);
339- int64_t batchIdx = 0;
340- if (batch_ > 1) {
341- batchIdx = tileIdx / tileNum_;
342- }
343- int64_t mOffset = mTileIdx_ * mL1_ + mSplitOffset_;
344- int64_t nOffset = nTileIdx_ * nL1_ + nSplitOffset_;
345- int64_t kOffset = splitSingleKIdx_ * splitSingleK_;
346 if (mTileIdx_ > mL1NormCnt_) {205 if (mTileIdx_ > mL1NormCnt_) {
347 mOffset = mL1NormCnt_ * mL1_ + (mTileIdx_ - mL1NormCnt_) * mL1TailMain_ + mSplitOffset_;206 mOffset = mL1NormCnt_ * mL1_ + (mTileIdx_ - mL1NormCnt_) * mL1TailMain_ + mSplitOffset_;
348 }207 }
349 if (nTileIdx_ > nL1NormCnt_) {208 if (nTileIdx_ > nL1NormCnt_) {
350 nOffset = nL1NormCnt_ * nL1_ + (nTileIdx_ - nL1NormCnt_) * nL1TailMain_ + nSplitOffset_;209 nOffset = nL1NormCnt_ * nL1_ + (nTileIdx_ - nL1NormCnt_) * nL1TailMain_ + nSplitOffset_;
351 }210 }
352- // 连续场景切K211+ 
353 return {mOffset, nOffset, kOffset, batchIdx};212 return {mOffset, nOffset, kOffset, batchIdx};
354 }213 }
355 214 
356- __aicore__ inline Shape<int64_t, int64_t> GetSplitOffset()
357- {
358- return {mSplitOffset_, nSplitOffset_};
359- }
360- 
361private:215private:
362 __aicore__ inline void UpdateMNTileIdx(int64_t tmpIdx)216 __aicore__ inline void UpdateMNTileIdx(int64_t tmpIdx)
363 {217 {
@@ -384,6 +238,64 @@ private:
384 nTileIdx_ = nTileNum_ - 1 - nTileIdx_;238 nTileIdx_ = nTileNum_ - 1 - nTileIdx_;
385 }239 }
386 }240 }
241+ 
242+private:
243+ static constexpr uint64_t BLOCK_SIZE_16 = 16UL;
244+ static constexpr uint64_t BLOCK_SIZE_32 = 32UL;
245+ static constexpr int64_t FullLoadMode = FullLoadMode_;
246+ static constexpr bool IS_FP32 = IsFp32_;
247+ static constexpr bool IS_ND_FORMAT = IsNdFormat_;
248+ static constexpr int64_t FP32_K_SWITCH_THRESHOLD = 268435456; // 1024 * 32 * 8192
249+ static constexpr int64_t FP32_SPLIT_K_THRESHOLD1 = 1024;
250+ static constexpr int64_t FP32_SPLIT_K_THRESHOLD2 = 8192;
251+ 
252+ int64_t mTileNum_{0};
253+ int64_t nTileNum_{0};
254+ int64_t kTileNum_{0};
255+ int64_t blockIdx_{0};
256+ int64_t perCoreBlockNum_{0};
257+ int64_t blockNum_{0};
258+ int64_t batch_{0};
259+ int64_t innerBatch_{0};
260+ int64_t k_{0};
261+ int64_t tailL1M_{0};
262+ int64_t tailL1N_{0};
263+ int64_t mTailCnt_{1};
264+ int64_t nTailCnt_{1};
265+ int64_t tailCnt_{1};
266+ int64_t tileNum_{1};
267+ int64_t mainWindow_{1};
268+ int64_t mainRow_{1};
269+ int64_t tailWindow_{1};
270+ int64_t mTileIdx_{1};
271+ int64_t nTileIdx_{1};
272+ int64_t splitSingleKIdx_{0};
273+ int64_t lastTileIdx_{-1};
274+ int64_t nSplitOffset_{0};
275+ int64_t mSplitOffset_{0};
276+ bool isSlice_{false};
277+ bool isSplitSingleK_{false};
278+ int64_t blkK_{0};
279+ int64_t splitSingleKRound_{0};
280+ int64_t splitSingleK_{0};
281+ int64_t splitSingleKTail_{0};
282+ int64_t mL1_{0};
283+ int64_t nL1_{0};
284+ int64_t kL1_{0};
285+ int64_t baseM_{0};
286+ int64_t baseN_{0};
287+ int64_t baseK_{0};
288+ uint8_t isHf32_{0};
289+ int64_t sliceM_{1};
290+ int64_t srcNdStride_{1};
291+ int64_t mL1NormCnt_{0};
292+ int64_t mL1TailSplitCnt_{1};
293+ int64_t mL1TailMain_{0};
294+ int64_t mL1TailLast_{0};
295+ int64_t nL1NormCnt_{0};
296+ int64_t nL1TailSplitCnt_{1};
297+ int64_t nL1TailMain_{0};
298+ int64_t nL1TailLast_{0};
387};299};
388 300 
389} // namespace Block301} // namespace Block
@@ -21,38 +21,10 @@
21namespace Blaze {21namespace Blaze {
22namespace Gemm {22namespace Gemm {
23namespace Block {23namespace Block {
24+ 
24template <class ProblemShape_>25template <class ProblemShape_>
25class BlockSchedulerMatmulStreamK {26class BlockSchedulerMatmulStreamK {
26public:27public:
27- int64_t usedCoreNum_{0};
28- int64_t mTileNum_{0};
29- int64_t nTileNum_{0};
30- int64_t skKTileNum_{0};
31- int64_t tileNum_{1};
32- int64_t totalMNTileNumInDP_{0};
33- 
34- int64_t batch_{0};
35- int64_t m_{0};
36- int64_t n_{0};
37- int64_t k_{0};
38- 
39- int64_t mTileIdx_{1};
40- int64_t nTileIdx_{1};
41- int64_t kTileIdx_{1};
42- int64_t curKTileNum_{1};
43- 
44- int64_t mL1_{0};
45- int64_t nL1_{0};
46- int64_t kL1_{0};
47- // streamK singleCoreK
48- int64_t skSingleCoreK_{0};
49- int64_t baseM_{0};
50- int64_t baseN_{0};
51- int64_t baseK_{0};
52- 
53- int64_t isHf32_{0};
54- 
55- static constexpr int64_t WINDOW_LEN = 4UL;
56 using BlockShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;28 using BlockShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
57 using BlockCoord = AscendC::Te::Coord<int64_t, int64_t, int64_t, int64_t>;29 using BlockCoord = AscendC::Te::Coord<int64_t, int64_t, int64_t, int64_t>;
58 using ProblemShape = ProblemShape_;30 using ProblemShape = ProblemShape_;
@@ -64,50 +36,49 @@ public:
64 int64_t baseK{0};36 int64_t baseK{0};
65 int64_t singleCoreK{0};37 int64_t singleCoreK{0};
66 int64_t kL1{0};38 int64_t kL1{0};
67- int64_t isHf32{0};39+ uint8_t isHf32{0};
40+ uint32_t l2CacheMode = L2_CACHE_DEFAULT;
68 };41 };
69 42 
70public:43public:
71 __aicore__ inline BlockSchedulerMatmulStreamK(const ProblemShape& shape, const Params& params)44 __aicore__ inline BlockSchedulerMatmulStreamK(const ProblemShape& shape, const Params& params)
72 {45 {
73 usedCoreNum_ = params.usedCoreNum;46 usedCoreNum_ = params.usedCoreNum;
74- m_ = Get<MNK_M>(shape);47+ if (usedCoreNum_ <= 0) {
75- n_ = Get<MNK_N>(shape);48+ return;
76- k_ = Get<MNK_K>(shape);49+ }
77- batch_ = AscendC::Std::max(Get<MNK_B>(shape), 1L);50+ m_ = AscendC::Te::Get<MNK_M>(shape);
78- baseM_ = params.baseM;51+ n_ = AscendC::Te::Get<MNK_N>(shape);
79- baseN_ = params.baseN;52+ k_ = AscendC::Te::Get<MNK_K>(shape);
80- mL1_ = baseM_; // size of m in L1 & L0 & singlecore, per core use L1 once in stream k53+ batch_ = AscendC::Std::max(AscendC::Te::Get<MNK_B>(shape), 1L);
81- nL1_ = baseN_; // size of n in L1 & L0 & singlecore, per core use L1 once in stream k
82 54 
55+ mL1_ = params.baseM; // size of m in L1 & L0 & singlecore, per core use L1 once in stream k
56+ nL1_ = params.baseN; // size of n in L1 & L0 & singlecore, per core use L1 once in stream k
83 skSingleCoreK_ = params.singleCoreK; // size of k in singlecore57 skSingleCoreK_ = params.singleCoreK; // size of k in singlecore
84- baseK_ = params.baseK; // fix basek to 32, need to be adjusted by baseM, baseN, L0
85- kL1_ = params.kL1;
86 58 
87- isHf32_ = params.isHf32;
88 mTileNum_ = CeilDiv(m_, mL1_);59 mTileNum_ = CeilDiv(m_, mL1_);
89 nTileNum_ = CeilDiv(n_, nL1_);60 nTileNum_ = CeilDiv(n_, nL1_);
90 skKTileNum_ = CeilDiv(k_, skSingleCoreK_);61 skKTileNum_ = CeilDiv(k_, skSingleCoreK_);
91- 
92 int64_t tailMNTileNum = (mTileNum_ * nTileNum_) % usedCoreNum_; // tail mCnt * nCnt num of SK62 int64_t tailMNTileNum = (mTileNum_ * nTileNum_) % usedCoreNum_; // tail mCnt * nCnt num of SK
93- // totaltilenum = core num of DP (m*n) + tail core num of SK (m*n*k)63+ // core num of DP (m*n) + tail core num of SK (m*n*k)
94 tileNum_ = (mTileNum_ * nTileNum_ - tailMNTileNum) + tailMNTileNum * skKTileNum_;64 tileNum_ = (mTileNum_ * nTileNum_ - tailMNTileNum) + tailMNTileNum * skKTileNum_;
95 totalMNTileNumInDP_ = mTileNum_ * nTileNum_ - tailMNTileNum;65 totalMNTileNumInDP_ = mTileNum_ * nTileNum_ - tailMNTileNum;
96 }66 }
97 67 
98- __aicore__ inline int64_t GetTotalTileNum()68+ __aicore__ inline int64_t GetTileNum()
99 {69 {
100 return tileNum_ * batch_;70 return tileNum_ * batch_;
101 }71 }
102 72 
103- __aicore__ inline int64_t GetHf32Flag()73+ __aicore__ inline int64_t GetBlockNum(ProblemShape shape)
104 {74 {
105- return isHf32_;75+ int64_t tilingBlockNum = 0;
106- }76+ if (tileNum_ * batch_ < AscendC::GetBlockNum()) {
107- 77+ tilingBlockNum = tileNum_ * batch_;
108- __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL1Shape()78+ } else {
109- {79+ tilingBlockNum = AscendC::GetBlockNum();
110- return {mL1_, nL1_, kL1_, 1};80+ }
81+ return tilingBlockNum;
111 }82 }
112 83 
113 __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetMNKTileNum()84 __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetMNKTileNum()
@@ -115,28 +86,7 @@ public:
115 return {mTileNum_, nTileNum_, skKTileNum_, 1};86 return {mTileNum_, nTileNum_, skKTileNum_, 1};
116 }87 }
117 88 
118- __aicore__ inline int64_t GetCurKSingleCore(int64_t tileIdx)89+ __aicore__ inline BlockShape GetBlockShape(int64_t tileIdx)
119- {
120- return (CheckIsSkScene(tileIdx) ? skSingleCoreK_ : k_);
121- }
122- 
123- __aicore__ inline int64_t GetBlockNum(int64_t blockNum)
124- {
125- int64_t tilingBlockNum = 0;
126- if (tileNum_ * batch_ < blockNum) {
127- tilingBlockNum = tileNum_ * batch_;
128- } else {
129- tilingBlockNum = blockNum;
130- }
131- return tilingBlockNum;
132- }
133- 
134- __aicore__ inline Shape<int64_t, int64_t, int64_t, int64_t> GetTileL0Shape()
135- {
136- return {baseM_, baseN_, baseK_, 1};
137- }
138- 
139- __aicore__ inline BlockShape GetSingleCoreShape(int64_t tileIdx)
140 {90 {
141 UpdateMNTileIdx(tileIdx);91 UpdateMNTileIdx(tileIdx);
142 int64_t tailL1M = m_ - (mTileNum_ - 1) * mL1_;92 int64_t tailL1M = m_ - (mTileNum_ - 1) * mL1_;
@@ -148,17 +98,23 @@ public:
148 return {blkM, blkN, blkK, 0};98 return {blkM, blkN, blkK, 0};
149 }99 }
150 100 
151- __aicore__ inline BlockCoord GetSingleCoreCoord(int64_t tileIdx)101+ __aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx)
152 {102 {
153 UpdateMNTileIdx(tileIdx);103 UpdateMNTileIdx(tileIdx);
154 return {mTileIdx_, nTileIdx_, kTileIdx_, 0};104 return {mTileIdx_, nTileIdx_, kTileIdx_, 0};
155 }105 }
156 106 
107+ __aicore__ inline int64_t GetCurKSingleCore(int64_t tileIdx)
108+ {
109+ return (CheckIsSkScene(tileIdx) ? skSingleCoreK_ : k_);
110+ }
111+ 
157 __aicore__ inline bool CheckIsSkScene(int64_t tileIdx)112 __aicore__ inline bool CheckIsSkScene(int64_t tileIdx)
158 {113 {
159 return CeilDiv((tileIdx + 1), usedCoreNum_) == CeilDiv(tileNum_, usedCoreNum_); // true is sk, false is dp114 return CeilDiv((tileIdx + 1), usedCoreNum_) == CeilDiv(tileNum_, usedCoreNum_); // true is sk, false is dp
160 }115 }
161 116 
117+private:
162 __aicore__ inline void UpdateMNTileIdx(int64_t tileIdx)118 __aicore__ inline void UpdateMNTileIdx(int64_t tileIdx)
163 {119 {
164 // judge now in dp loop (kTileNum = 1) or in sk loop120 // judge now in dp loop (kTileNum = 1) or in sk loop
@@ -189,8 +145,30 @@ public:
189 nTileIdx_ = nTileNum_ - 1UL - nTileIdx_;145 nTileIdx_ = nTileNum_ - 1UL - nTileIdx_;
190 }146 }
191 }147 }
148+ 
149+private:
150+ int64_t usedCoreNum_{0};
151+ int64_t mTileNum_{0};
152+ int64_t nTileNum_{0};
153+ int64_t skKTileNum_{0};
154+ int64_t tileNum_{1};
155+ int64_t totalMNTileNumInDP_{0};
156+ 
157+ int64_t batch_{0};
158+ int64_t m_{0};
159+ int64_t n_{0};
160+ int64_t k_{0};
161+ 
162+ int64_t mTileIdx_{1};
163+ int64_t nTileIdx_{1};
164+ int64_t kTileIdx_{1};
165+ int64_t curKTileNum_{1};
166+ 
167+ int64_t mL1_{0};
168+ int64_t nL1_{0};
169+ int64_t skSingleCoreK_{0};
192};170};
193 171 
194} // namespace Block172} // namespace Block
195} // namespace Gemm173} // namespace Gemm
196-} // namespace Blaze174+} // namespace Blaze
@@ -59,8 +59,6 @@ public:
59 59 
60 static constexpr bool transA = IsTrans<LayoutA_>::value;60 static constexpr bool transA = IsTrans<LayoutA_>::value;
61 static constexpr bool transB = IsTrans<LayoutB_>::value;61 static constexpr bool transB = IsTrans<LayoutB_>::value;
62- static constexpr int64_t WINDOW_LEN = 4;
63- 
64 struct Params {62 struct Params {
65 int64_t baseM;63 int64_t baseM;
66 int64_t baseN;64 int64_t baseN;
@@ -82,6 +80,9 @@ public:
82 mCnt_ = Blaze::Gemm::CeilDiv(m, baseM_);80 mCnt_ = Blaze::Gemm::CeilDiv(m, baseM_);
83 nCnt_ = Blaze::Gemm::CeilDiv(n, baseN_);81 nCnt_ = Blaze::Gemm::CeilDiv(n, baseN_);
84 totalCnt_ = mCnt_ * nCnt_;82 totalCnt_ = mCnt_ * nCnt_;
83+ if (blockNum_ <= 0) {
84+ return;
85+ }
85 mCoreNum_ = Blaze::Gemm::Min(WINDOW_LEN, mCnt_);86 mCoreNum_ = Blaze::Gemm::Min(WINDOW_LEN, mCnt_);
86 if (mCoreNum_ != 0) {87 if (mCoreNum_ != 0) {
87 mainRow_ = mCnt_ / mCoreNum_ - 1;88 mainRow_ = mCnt_ / mCoreNum_ - 1;
@@ -15,14 +15,8 @@
15 15 
16#pragma once16#pragma once
17 17 
18-#define ASCENDC_CUBE_ONLY
19 18 
20-#if ASC_DEVKIT_MAJOR >= 9
21#include "kernel_basic_intf.h"19#include "kernel_basic_intf.h"
22-#else
23-#include "kernel_operator.h"
24-#include "kernel_operator_intf.h"
25-#endif
26 20 
27#include "blaze/epilogue/block/block_epilogue_empty.h"21#include "blaze/epilogue/block/block_epilogue_empty.h"
28#include "blaze/gemm/block/block_mmad.h"22#include "blaze/gemm/block/block_mmad.h"
@@ -50,9 +44,7 @@ public:
50 using ProblemShape = ProblemShape_;44 using ProblemShape = ProblemShape_;
51 using BlockScheduler = BlockScheduler_;45 using BlockScheduler = BlockScheduler_;
52 using BlockEpilogue = BlockEpilogue_;46 using BlockEpilogue = BlockEpilogue_;
53- static constexpr bool transA = BlockMmad::transA;47+ 
54- static constexpr bool transB = BlockMmad::transB;
55- static constexpr bool weightNZFormat = BlockMmad::weightNZFormat;
56 // mmad48 // mmad
57 using BlockMmadParams = typename BlockMmad::Params;49 using BlockMmadParams = typename BlockMmad::Params;
58 using BlockEpilogueParams = typename BlockEpilogue::Params;50 using BlockEpilogueParams = typename BlockEpilogue::Params;
@@ -66,30 +58,11 @@ public:
66 using LayoutC = typename BlockMmad::LayoutC;58 using LayoutC = typename BlockMmad::LayoutC;
67 using LayoutBias = typename BlockMmad::LayoutBias;59 using LayoutBias = typename BlockMmad::LayoutBias;
68 using TupleShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;60 using TupleShape = AscendC::Te::Shape<int64_t, int64_t, int64_t, int64_t>;
69- using MakeLayoutA = AscendC::Te::FrameLayoutFormat<LayoutA, AscendC::Std::Int<AscendC::AuxGetC0Size<AType>()>>;61+ using MakeLayoutA = AscendC::Te::FrameLayoutFormat<LayoutA, AscendC::Std::Int<AscendC::Te::C0_ELEMENT<AType>>>;
70- using MakeLayoutB = AscendC::Te::FrameLayoutFormat<LayoutB, AscendC::Std::Int<AscendC::AuxGetC0Size<BType>()>>;62+ using MakeLayoutB = AscendC::Te::FrameLayoutFormat<LayoutB, AscendC::Std::Int<AscendC::Te::C0_ELEMENT<BType>>>;
71- using MakeLayoutC = AscendC::Te::FrameLayoutFormat<LayoutC, AscendC::Std::Int<AscendC::AuxGetC0Size<CType>()>>;63+ using MakeLayoutC = AscendC::Te::FrameLayoutFormat<LayoutC, AscendC::Std::Int<AscendC::Te::C0_ELEMENT<CType>>>;
72 using MakeLayoutBias =64 using MakeLayoutBias =
73- AscendC::Te::FrameLayoutFormat<LayoutBias, AscendC::Std::Int<AscendC::AuxGetC0Size<BiasType>()>>;65+ AscendC::Te::FrameLayoutFormat<LayoutBias, AscendC::Std::Int<AscendC::Te::C0_ELEMENT<BiasType>>>;
74- static constexpr bool isFp32 = (std::is_same_v<BType, float>);
75- static constexpr int64_t C0_SIZE = isFp32 ? C0_SIZE_fp32 : C0_SIZE_fp16;
76- 
77- // shape
78- TupleShape problemShape_{};
79- BlockMmadParams blockMmadParams_{};
80- bool isBias_ = false;
81- 
82- __gm__ AType* aGmAddr_;
83- __gm__ BType* bGmAddr_;
84- __gm__ CType* cGmAddr_;
85- __gm__ BiasType* biasGmAddr_ = nullptr; // 可选输入,直接初始化
86- 
87- uint64_t curBatchIdx_ = {0};
88- uint64_t batchAIndex_ = {0};
89- uint64_t batchBIndex_ = {0};
90- uint64_t m_{1};
91- uint64_t n_{1};
92- uint64_t k_{1};
93 66 
94 struct BatchInfo {67 struct BatchInfo {
95 uint32_t aBatchDim0 = 1UL;68 uint32_t aBatchDim0 = 1UL;
@@ -110,77 +83,33 @@ public:
110 ProblemShape problemShape;83 ProblemShape problemShape;
111 BlockMmadParams mmadParams;84 BlockMmadParams mmadParams;
112 BlockEpilogueParams epilogueParams;85 BlockEpilogueParams epilogueParams;
113- BlockSchedulerParams schedulerParams;86+ BlockSchedulerParams schParams;
114 BatchInfo batchInfo;87 BatchInfo batchInfo;
115 Params() = default;88 Params() = default;
116 };89 };
117 90 
118- __aicore__ inline void Init(Params const& params)
119- {
120- problemShape_ = params.problemShape;
121- blockMmadParams_ = params.mmadParams;
122- m_ = static_cast<uint64_t>(AscendC::Te::Get<MNK_M>(problemShape_));
123- n_ = static_cast<uint64_t>(AscendC::Te::Get<MNK_N>(problemShape_));
124- k_ = static_cast<uint64_t>(AscendC::Te::Get<MNK_K>(problemShape_));
125- aGmAddr_ = reinterpret_cast<__gm__ AType*>(params.mmadParams.aGmAddr);
126- bGmAddr_ = reinterpret_cast<__gm__ BType*>(params.mmadParams.bGmAddr);
127- cGmAddr_ = reinterpret_cast<__gm__ CType*>(params.mmadParams.cGmAddr);
128- if (blockMmadParams_.biasGmAddr != nullptr) {
129- isBias_ = true;
130- biasGmAddr_ = reinterpret_cast<__gm__ BiasType*>(params.mmadParams.biasGmAddr);
131- }
132- }
133- 
134- __aicore__ inline void UpdateBatchOffset(Params const& params)
135- {
136- aGmAddr_ = reinterpret_cast<__gm__ AType*>(params.mmadParams.aGmAddr) + batchAIndex_ * m_ * k_;
137- if (!weightNZFormat) {
138- bGmAddr_ = reinterpret_cast<__gm__ BType*>(params.mmadParams.bGmAddr) + batchBIndex_ * k_ * n_;
139- } else {
140- bGmAddr_ = reinterpret_cast<__gm__ BType*>(params.mmadParams.bGmAddr) +
141- Blaze::Gemm::CalWeightNZGmAddrOffset(transB, batchBIndex_, n_, k_, C0_SIZE);
142- }
143- cGmAddr_ = reinterpret_cast<__gm__ CType*>(params.mmadParams.cGmAddr) + curBatchIdx_ * m_ * n_;
144- if (params.batchInfo.biasBatchDimAll != 1UL) {
145- biasGmAddr_ = reinterpret_cast<__gm__ BiasType*>(params.mmadParams.biasGmAddr) + curBatchIdx_ * n_;
146- }
147- }
148- 
149- __aicore__ inline void UnsetHf32(bool isHf32)
150- {
151- if (isHf32) {
152- AscendC::SetHF32Mode(0);
153- }
154- }
155- 
156 __aicore__ inline void operator()(Params const& params)91 __aicore__ inline void operator()(Params const& params)
157 {92 {
158 if ASCEND_IS_AIV {93 if ASCEND_IS_AIV {
159 return;94 return;
160 }95 }
161- // 初始化mmad
162- BlockMmad blockMmad;
163- int64_t curBlockIdx = AscendC::GetBlockIdx();
164- int64_t blockNum = AscendC::GetBlockNum();
165 Init(params);96 Init(params);
166 97 
167 // 初始化blockScheduler98 // 初始化blockScheduler
168- BlockScheduler bs(params.problemShape, curBlockIdx, blockNum, params.schedulerParams, isFp32, !weightNZFormat);99+ BlockScheduler bs(params.problemShape, params.schParams);
169- 100+ int64_t curBlockIdx = AscendC::GetBlockIdx();
170- int64_t tileNum = bs.GetTileNum();101+ int64_t realBlockNum = bs.GetBlockNum(params.problemShape);
171- TupleShape tileL1 = bs.GetTileL1Shape();
172- TupleShape tileL0 = bs.GetTileL0Shape();
173- int64_t realBlockNum = bs.GetBlockNum(params.problemShape, blockNum);
174 if (curBlockIdx >= realBlockNum) {102 if (curBlockIdx >= realBlockNum) {
175 return;103 return;
176 }104 }
177- bool isHf32 = bs.Gethf32Flag();105+ 
178- if (isHf32) {106+ if (params.schParams.isHf32) {
179 AscendC::SetHF32Mode(1);107 AscendC::SetHF32Mode(1);
180 AscendC::SetHF32TransMode(1);108 AscendC::SetHF32TransMode(1);
181 }109 }
182- SetMMLayoutTransform(true); // Set Mmad output as cloumn major for Fixpipe110+ 
183- blockMmad.Init(problemShape_, tileL1, tileL0, isBias_, bs.GetL1BuferNum_(), bs.GetL0cDB());111+ BlockMmad blockMmad;
112+ blockMmad.Init(params.problemShape, params.mmadParams);
184 113 
185 // 默认ND Format114 // 默认ND Format
186 auto layoutA = MakeLayoutA{}(m_, k_); // ND layout for A115 auto layoutA = MakeLayoutA{}(m_, k_); // ND layout for A
@@ -194,7 +123,13 @@ public:
194 auto gmBias =123 auto gmBias =
195 AscendC::Te::MakeTensor(AscendC::Te::MakeMemPtr<AscendC::Te::Location::GM>(biasGmAddr_), layoutBias);124 AscendC::Te::MakeTensor(AscendC::Te::MakeMemPtr<AscendC::Te::Location::GM>(biasGmAddr_), layoutBias);
196 125 
126+ // 使能双页表
127+ SetL2Cache(gmA, gmB, params.schParams.l2CacheMode);
128+ 
197 uint64_t preBatchIdx = 0;129 uint64_t preBatchIdx = 0;
130+ int64_t tileNum = bs.GetTileNum();
131+ int64_t blockNum = AscendC::GetBlockNum();
132+ // Process tiles in ping-pong mode
198 for (int64_t tileIdx = curBlockIdx; tileIdx < tileNum; tileIdx += blockNum) {133 for (int64_t tileIdx = curBlockIdx; tileIdx < tileNum; tileIdx += blockNum) {
199 auto tileShape = bs.template GetBlockShape<transB, BType>(tileIdx); // 非全载134 auto tileShape = bs.template GetBlockShape<transB, BType>(tileIdx); // 非全载
200 auto tileCoord = bs.GetBlockCoord(tileIdx); // (m, n, k, b)135 auto tileCoord = bs.GetBlockCoord(tileIdx); // (m, n, k, b)
@@ -249,13 +184,74 @@ public:
249 auto gmBlockB = gmB.Slice(AscendC::MakeCoord(0L, coordN), AscendC::MakeShape(shapeK, shapeN));184 auto gmBlockB = gmB.Slice(AscendC::MakeCoord(0L, coordN), AscendC::MakeShape(shapeK, shapeN));
250 auto gmBlockC = gmC.Slice(AscendC::MakeCoord(coordM, coordN), AscendC::MakeShape(shapeM, shapeN));185 auto gmBlockC = gmC.Slice(AscendC::MakeCoord(coordM, coordN), AscendC::MakeShape(shapeM, shapeN));
251 auto gmBlockBias = gmBias.Slice(AscendC::MakeCoord(0L, coordN), AscendC::MakeShape(1L, shapeN));186 auto gmBlockBias = gmBias.Slice(AscendC::MakeCoord(0L, coordN), AscendC::MakeShape(1L, shapeN));
252- blockMmad(gmBlockC, gmBlockA, gmBlockB, gmBlockBias, tileShape);187+ blockMmad(gmBlockA, gmBlockB, gmBlockBias, gmBlockC, tileShape);
253 }188 }
254- SetMMLayoutTransform(false);189+ 
255- UnsetHf32(isHf32);190+ UnsetHf32();
256 }191 }
192+ 
193+private:
194+ __aicore__ inline void Init(Params const& params)
195+ {
196+ auto blockMmadParams = params.mmadParams;
197+ m_ = static_cast<uint64_t>(AscendC::Te::Get<MNK_M>(params.problemShape));
198+ n_ = static_cast<uint64_t>(AscendC::Te::Get<MNK_N>(params.problemShape));
199+ k_ = static_cast<uint64_t>(AscendC::Te::Get<MNK_K>(params.problemShape));
200+ aGmAddr_ = reinterpret_cast<__gm__ AType*>(blockMmadParams.aGmAddr);
201+ bGmAddr_ = reinterpret_cast<__gm__ BType*>(blockMmadParams.bGmAddr);
202+ cGmAddr_ = reinterpret_cast<__gm__ CType*>(blockMmadParams.cGmAddr);
203+ biasGmAddr_ = reinterpret_cast<__gm__ BiasType*>(blockMmadParams.biasGmAddr);
204+ }
205+ 
206+ __aicore__ inline void UpdateBatchOffset(Params const& params)
207+ {
208+ aGmAddr_ = reinterpret_cast<__gm__ AType*>(params.mmadParams.aGmAddr) + batchAIndex_ * m_ * k_;
209+ if (!weightNZFormat) {
210+ bGmAddr_ = reinterpret_cast<__gm__ BType*>(params.mmadParams.bGmAddr) + batchBIndex_ * k_ * n_;
211+ } else {
212+ bGmAddr_ = reinterpret_cast<__gm__ BType*>(params.mmadParams.bGmAddr) +
213+ Blaze::Gemm::CalWeightNZGmAddrOffset(transB, batchBIndex_, n_, k_, C0_SIZE);
214+ }
215+ cGmAddr_ = reinterpret_cast<__gm__ CType*>(params.mmadParams.cGmAddr) + curBatchIdx_ * m_ * n_;
216+ if (params.batchInfo.biasBatchDimAll != 1UL) {
217+ biasGmAddr_ = reinterpret_cast<__gm__ BiasType*>(params.mmadParams.biasGmAddr) + curBatchIdx_ * n_;
218+ }
219+ }
220+ 
221+ __aicore__ inline void UnsetHf32()
222+ {
223+ AscendC::SetHF32Mode(0);
224+ }
225+ 
226+ template <typename TensorA, typename TensorB>
227+ __aicore__ inline void SetL2Cache(TensorA& gmA, TensorB& gmB, uint32_t l2CacheMode) {
228+ if (l2CacheMode == ALL_L2_CACHE_DISABLE || l2CacheMode == B_L2_CACHE_DISABLE) {
229+ gmB.SetL2CacheHint(AscendC::Te::CacheMode::CACHE_MODE_DISABLE);
230+ }
231+ if (l2CacheMode == ALL_L2_CACHE_DISABLE || l2CacheMode == A_L2_CACHE_DISABLE) {
232+ gmA.SetL2CacheHint(AscendC::Te::CacheMode::CACHE_MODE_DISABLE);
233+ }
234+ }
235+ 
236+private:
237+ static constexpr bool isFp32 = (AscendC::Std::is_same_v<BType, float>);
238+ static constexpr int64_t C0_SIZE = isFp32 ? C0_SIZE_fp32 : C0_SIZE_fp16;
239+ static constexpr bool transA = BlockMmad::transA;
240+ static constexpr bool transB = BlockMmad::transB;
241+ static constexpr bool weightNZFormat = BlockMmad::weightNZFormat;
242+ __gm__ AType* aGmAddr_;
243+ __gm__ BType* bGmAddr_;
244+ __gm__ CType* cGmAddr_;
245+ __gm__ BiasType* biasGmAddr_ = nullptr; // 可选输入,直接初始化
246+ 
247+ uint64_t curBatchIdx_ = {0};
248+ uint64_t batchAIndex_ = {0};
249+ uint64_t batchBIndex_ = {0};
250+ uint64_t m_{1};
251+ uint64_t n_{1};
252+ uint64_t k_{1};
257};253};
258 254 
259} // namespace Kernel255} // namespace Kernel
260} // namespace Gemm256} // namespace Gemm
261-} // namespace Blaze257+} // namespace Blaze