| @@ -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 @@ | |||
| 22 | BlockEpilogue | 22 | BlockEpilogue |
| 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 | #### Params | 19 | #### Params |
| 30 | ``` | 20 | ``` |
| 31 | struct Params { | 21 | struct 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 | ### Params | 34 | ### Params |
| 43 | ``` | 35 | ``` |
| 44 | struct Params { | 36 | struct 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 示例(伪代码) |
| 142 | class BlockEpilogueRelu { | 134 | class BlockEpilogueRelu { |
| 143 | public: | 135 | public: |
| 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 | -### Arguments | 65 | +### 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 | ### AivParams | 73 | ### AivParams |
| 79 | ``` | 74 | ``` |
| 80 | struct AivParams { | 75 | struct 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 / GmParams | 56 | +#### 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 矩阵输入 Tensor | 100 | TensorA gmA, // A 矩阵输入 Tensor |
| 105 | TensorB gmB, // B 矩阵输入 Tensor | 101 | TensorB gmB, // B 矩阵输入 Tensor |
| 106 | TensorBias gmBias, // Bias 输入 Tensor | 102 | 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 | ``` |
| 160 | BlockMmad blockMmad; | 157 | BlockMmad blockMmad; |
| 161 | TupleShape problemShape{m, n, k, batch}; | 158 | TupleShape 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 | -### weightNZFormat | 25 | +### 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 Tensor | 184 | + TensorA& gmA, // A 矩阵 GM Tensor |
| 89 | - TensorA gmA, // A 矩阵 GM Tensor | 185 | + TensorB& gmB, // B 矩阵 GM Tensor |
| 90 | - TensorB gmB, // B 矩阵 GM Tensor | 186 | + TensorBias& gmBias, // Bias GM Tensor |
| 91 | - TensorBias gmBias, // Bias GM Tensor | 187 | + 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 / Params | 208 | +## 事件同步 |
| 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 |
| 137 | using AType = half; | 222 | using AType = half; |
| 138 | using BType = half; | 223 | using BType = half; |
| 139 | using CType = float; | 224 | using CType = float; |
| 140 | using BiasType = float; | 225 | using 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; |
| 144 | using LayoutBias = LayoutC; | 229 | using LayoutBias = LayoutC; |
| 145 | 230 | ||
| 146 | -using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockBasic<B_FULL_LOAD_MODE>; | 231 | +using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockBasic<0>; // 非全载 |
| 147 | using BlockMmad = Blaze::Gemm::Block::BlockMmad< | 232 | using 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 | ||
| 153 | BlockMmad blockMmad; | 256 | BlockMmad blockMmad; |
| 154 | ``` | 257 | ``` |
| 155 | 258 | ||
| 156 | ### 组件初始化 | 259 | ### 组件初始化 |
| 157 | -``` | 260 | +```cpp |
| 158 | TupleShape problemShape{m, n, k, batch}; | 261 | TupleShape 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 层创建) |
| 170 | auto gmA = AscendC::Te::MakeTensor(...); | 268 | auto gmA = AscendC::Te::MakeTensor(...); |
| 171 | auto gmB = AscendC::Te::MakeTensor(...); | 269 | auto gmB = AscendC::Te::MakeTensor(...); |
| @@ -179,48 +277,56 @@ auto gmBlockC = gmC.Slice(AscendC::MakeCoord(coordM, coordN), AscendC::MakeShape | |||
| 179 | auto gmBlockBias = gmBias.Slice(AscendC::MakeCoord(0, coordN), AscendC::MakeShape(1, shapeN)); | 277 | auto 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 (双缓冲) → GM | 288 | +GM (A/B/Bias) → L1 (多缓冲) → L0A/L0B (双缓冲) → L0C (单缓冲或双缓冲) → GM (C) |
| 191 | - ↓ | ||
| 192 | - BIAS → L1 → BIAS Buffer | ||
| 193 | ``` | 289 | ``` |
| 194 | 290 | ||
| 195 | ### 执行流程 | 291 | ### 执行流程 |
| 196 | ``` | 292 | ``` |
| 197 | K 轴外层循环:按 kL1 切分 | 293 | K 轴外层循环:按 kL1 切分 |
| 198 | ↓ | 294 | ↓ |
| 199 | -搬运 A、B、Bias 到 L1 | 295 | +搬运 A、B、Bias 到 L1(多缓冲) |
| 200 | ↓ | 296 | ↓ |
| 201 | K 轴内层循环:按 baseK 切分 | 297 | K 轴内层循环:按 baseK 切分 |
| 202 | ↓ | 298 | ↓ |
| 203 | -搬运 A、B 到 L0 | 299 | +搬运 A、B 到 L0(双缓冲) |
| 204 | ↓ | 300 | ↓ |
| 205 | Mmad 计算:C += A × B + Bias(首次迭代) | 301 | Mmad 计算:C += A × B + Bias(首次迭代) |
| 206 | ↓ | 302 | ↓ |
| 207 | -结果搬出:L0C → GM | 303 | +结果搬出: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 处理 |
| 37 | Bias 仅在首次 K 轴切分(`kCntIndex = 0`)时加载并累加: | 49 | Bias 仅在首次 K 轴切分(`kCntIndex = 0`)时加载并累加: |
| 38 | -- 首次 `iter0 = 0` 且 `iter1 = 0` 且 `kCntIndex = 0`:加载 Bias | 50 | +- 首次迭代且 `kCntIndex = 0`:加载 Bias |
| 39 | - 后续迭代:不加载 Bias,累加计算 | 51 | - 后续迭代:不加载 Bias,累加计算 |
| 40 | 52 | ||
| 41 | ### CmatrixInitVal | 53 | ### CmatrixInitVal |
| @@ -49,15 +61,23 @@ cmatrixInitVal = (iter0 == 0 && iter1 == 0 && (!isBias_ || (isBias_ && kCntIndex | |||
| 49 | - 有 Bias 且首次 K 切分:不初始化(Bias 提供初始值) | 61 | - 有 Bias 且首次 K 切分:不初始化(Bias 提供初始值) |
| 50 | - 有 Bias 且后续 K 切分:初始化为 0 | 62 | - 有 Bias 且后续 K 切分:初始化为 0 |
| 51 | 63 | ||
| 52 | -### unitFlag | 64 | +### 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_ACCUMULATION | 67 | +- `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 | -### GmParams | 93 | +### 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 缓冲数量固定为 2 | 149 | +- 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 | ``` |
| 138 | template <typename TensorC, typename TensorA, typename TensorB, typename TensorBias, typename TensorWorkspace> | 153 | template <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 Tensor | 155 | TensorA gmA, // A 矩阵 GM Tensor |
| 142 | TensorB gmB, // B 矩阵 GM Tensor | 156 | TensorB gmB, // B 矩阵 GM Tensor |
| 143 | TensorBias gmBias, // Bias GM Tensor | 157 | 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 | 执行流程: |
| 163 | 1. **K 轴外层循环**:按 kL1 切分 | 178 | 1. **K 轴外层循环**:按 kL1 切分 |
| 164 | 2. **搬运 Bias 到 L1**:首次切分且首次迭代时搬运 | 179 | 2. **搬运 Bias 到 L1**:首次切分且首次迭代时搬运 |
| 165 | -3. **搬运 A 到 L1**:双缓冲模式 | 180 | +3. **搬运 A 到 L1**:双缓冲模式(事件 0、1) |
| 166 | -4. **搬运 B 到 L1**:双缓冲模式(事件偏移 +2) | 181 | +4. **搬运 B 到 L1**:双缓冲模式(事件 2、3,偏移 L1_EVENT_ID_OFFSET) |
| 167 | 5. **K 轴内层循环**:按 baseK 切分(Iterate) | 182 | 5. **K 轴内层循环**:按 baseK 切分(Iterate) |
| 168 | 6. **搬运 A/B/Bias 到 L0**:双缓冲模式 | 183 | 6. **搬运 A/B/Bias 到 L0**:双缓冲模式 |
| 169 | 7. **Mmad 计算**:根据 `kCntIndex` 决定是否加载 Bias | 184 | 7. **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); | ||
| 177 | AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId + L1_EVENT_ID_OFFSET); // B 使用事件 2、3 | 191 | AscendC::WaitFlag<AscendC::HardEvent::MTE1_MTE2>(l1BufId + L1_EVENT_ID_OFFSET); // B 使用事件 2、3 |
| 178 | ``` | 192 | ``` |
| 179 | 193 | ||
| @@ -202,20 +216,29 @@ using BiasType = float; | |||
| 202 | using LayoutA = AscendC::Te::NDExtLayoutPtn; | 216 | using LayoutA = AscendC::Te::NDExtLayoutPtn; |
| 203 | using LayoutB = AscendC::Te::NZLayoutPtn; | 217 | using LayoutB = AscendC::Te::NZLayoutPtn; |
| 204 | using LayoutC = AscendC::Te::NDExtLayoutPtn; | 218 | using LayoutC = AscendC::Te::NDExtLayoutPtn; |
| 219 | +using LayoutBias = LayoutC; | ||
| 205 | 220 | ||
| 206 | using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>; | 221 | using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>; |
| 207 | using BlockMmad = Blaze::Gemm::Block::BlockMmad< | 222 | using 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 | +}; | ||
| 235 | +``` | ||
| 236 | + | ||
| 211 | ### 组件初始化 | 237 | ### 组件初始化 |
| 212 | ``` | 238 | ``` |
| 213 | BlockMmad blockMmad; | 239 | BlockMmad blockMmad; |
| 214 | TupleShape problemShape{m, n, k}; | 240 | TupleShape 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(...); | |||
| 231 | auto gmBlockA = gmA.Slice(...); | 254 | auto gmBlockA = gmA.Slice(...); |
| 232 | auto gmBlockB = gmB.Slice(...); | 255 | auto gmBlockB = gmB.Slice(...); |
| 233 | auto gmBlockC = gmC.Slice(...); | 256 | auto gmBlockC = gmC.Slice(...); |
| 234 | -auto gmWorkspace = gmWorkspace.Slice(...); | 257 | +auto gmBlockWorkspace = gmWorkspace.Slice(...); |
| 235 | auto gmBlockBias = gmBias.Slice(...); | 258 | auto gmBlockBias = gmBias.Slice(...); |
| 236 | 259 | ||
| 237 | // 执行矩阵乘 | 260 | // 执行矩阵乘 |
| 238 | TupleShape tileShape{shapeM, shapeN, shapeK}; | 261 | TupleShape tileShape{shapeM, shapeN, shapeK}; |
| 239 | int64_t kCntIndex = 0; // K 轴切分索引 | 262 | int64_t kCntIndex = 0; // K 轴切分索引 |
| 240 | bool checkIsSkScene = true; // SK 模式(输出到 workspace) | 263 | bool 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/Workspace | 271 | +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 轴切分,输出到 workspace | 313 | - **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 | ### Params | 79 | ### Params |
| 80 | ``` | 80 | ``` |
| 81 | struct Params { | 81 | struct 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 { | |||
| 93 | struct L1Params { | 93 | struct 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 | ### TileL1L0Param | 100 | ### TileL1L0Param |
| 101 | ``` | 101 | ``` |
| 102 | struct TileL1L0Param { | 102 | struct 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 维大小(对齐到 64) | 106 | + 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 | ### GetBlockNum | 74 | ### GetBlockNum |
| 87 | ```cpp | 75 | ```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 / GetSingleCoreShape | 80 | +### GetBlockShape |
| 93 | ```cpp | 81 | ```cpp |
| 94 | __aicore__ inline BlockShape GetBlockShape(int64_t tileIdx, ...); // BlockSchedulerMatmulBasic | 82 | __aicore__ inline BlockShape GetBlockShape(int64_t tileIdx, ...); // BlockSchedulerMatmulBasic |
| 95 | -__aicore__ inline BlockShape GetSingleCoreShape(int64_t tileIdx); // BlockSchedulerStreamK | 83 | +__aicore__ inline BlockShape GetBlockShape(int64_t tileIdx); // BlockSchedulerStreamK |
| 96 | template <QuantMode aQuantMode, QuantMode bQuantMode, bool weightNz = false> | 84 | template <QuantMode aQuantMode, QuantMode bQuantMode, bool weightNz = false> |
| 97 | __aicore__ inline BlockShape GetBlockShape(BlockCoord blockCoord); // BlockSchedulerQuantBatchMatmulV3 | 85 | __aicore__ inline BlockShape GetBlockShape(BlockCoord blockCoord); // BlockSchedulerQuantBatchMatmulV3 |
| 98 | ``` | 86 | ``` |
| @@ -100,10 +88,10 @@ __aicore__ inline BlockShape GetBlockShape(BlockCoord blockCoord); // Block | |||
| 100 | 88 | ||
| 101 | QuantBatchMatmulV3 的 `BlockShape` 第 3、4 个字段用于携带 M/N 尾块切分偏移。 | 89 | QuantBatchMatmulV3 的 `BlockShape` 第 3、4 个字段用于携带 M/N 尾块切分偏移。 |
| 102 | 90 | ||
| 103 | -### GetBlockCoord / GetSingleCoreCoord / GetTileIdx | 91 | +### GetBlockCoord / GetTileIdx |
| 104 | ```cpp | 92 | ```cpp |
| 105 | __aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx); // BlockSchedulerMatmulBasic | 93 | __aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx); // BlockSchedulerMatmulBasic |
| 106 | -__aicore__ inline BlockCoord GetSingleCoreCoord(int64_t tileIdx); // BlockSchedulerStreamK | 94 | +__aicore__ inline BlockCoord GetBlockCoord(int64_t tileIdx); // BlockSchedulerStreamK |
| 107 | __aicore__ inline bool GetTileIdx(BlockCoord& blockCoord); // BlockSchedulerQuantBatchMatmulV3 | 95 | __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 | ||
| 200 | ProblemShape shape{m, n, k, batch}; | 188 | ProblemShape 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 | ||
| 203 | for (int64_t tileIdx = blockIdx; tileIdx < scheduler.GetTileNum(); tileIdx += blockNum) { | 194 | for (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 | ```cpp | 29 | ```cpp | ||||||||
| 28 | struct Params { | 30 | struct 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; // K 轴 L1 tile 尺寸 | 34 | + uint32_t baseM = 0; // M 轴 L0 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; // K 轴 L0 base 尺寸 | 39 | + uint32_t mBaseTailSplitCnt = 1; // M 轴 L1 尾块切分数量 | ||||||||
| 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 | ||||||||
🔵 Low Priority 变更行(第43行):Params 结构体中 证据链:
影响:读者看到 "ub默认不开db为1" 会感到困惑,不知道这个参数的真实用途。 修复方案:将注释修改为与源代码一致的 建议:将 isHf32 字段的注释修改为与源代码一致的 ![]() ![]() 不准确? | |||||||||||
| 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; // 鞧连续场景m轴stride | ||||||||
| 45 | - uint32_t nBaseTailSplitCnt = 1; // N 轴 L1 尾块切分数量 | 47 | + uint32_t innerBatch = 1; // 鞧连续transpose场景内轴batch值 | ||||||||
🟡 Medium Priority 变更行(第45-47行):Params 结构体中的注释使用了 "鞧连续"(如 证据链:
影响:用户阅读文档时无法理解 "鞧连续场景" 的含义,会误以为这是某个专用术语。由于 修复方案:将三处 "鞧连续" 替换为 "非连续"。 改动建议
![]() ![]() 不准确? | |||||||||||
| 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 | |||||||||||
| 125 | mTailCnt=2, nTailCnt=2 // 尾块切为 4 份,4 个 Block 并行处理 | 113 | mTailCnt=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 | 大矩阵场景 | | ||||||||
🟡 Medium Priority 证据链: 建议:统一 L2 Cache 在大矩阵场景下的建议。两种修复方向:(A)若大矩阵应禁用 L2 Cache(与 StreamK 文档一致),将第389行改为"禁用 L2 Cache,增大 tile 尺寸";(B)若 Basic 调度器大矩阵应启用 L2 Cache,将第148行 ALL_L2_CACHE_DISABLE 的场景恢复为"小矩阵场景"。需要结合实际代码逻辑确认正确方向。 ![]() ![]() 不准确? | |||||||||||
| 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 场景 | | ||||||||
🟡 Medium Priority 变更行(第159行):表格中 证据链:
影响:读者无法判断 修复方案:将描述修改为 "非连续场景 transpose 内轴 batch",与源代码注释含义一致。 建议:将 innerBatch 的描述从 "非 transpose 场景内轴 batch" 改为 "非连续场景 transpose 内轴 batch"。 改动建议
![]() ![]() 不准确? | |||||||||||
| 248 | 160 | ||||||||||
| 249 | **判断逻辑**: | 161 | **判断逻辑**: | ||||||||
| 250 | ``` | 162 | ``` | ||||||||
| 251 | isSlice_ = (srcNdStride != 1 && sliceM != 0) | 163 | isSlice_ = (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_ = true | 169 | +|------|------| | ||||||||
| 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 | ```cpp | 177 | ```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( | |||||||||||
| 388 | 8. 计算扫描窗口:mainWindow_, mainRow_, tailWindow_ | 198 | 8. 计算扫描窗口: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 | ### GetTileNum | 203 | ### GetTileNum | ||||||||
| 400 | ```cpp | 204 | ```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 | ### GetBlockNum | 209 | ### GetBlockNum | ||||||||
| 430 | ```cpp | 210 | ```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 | ### GetBlockShape | 216 | ### GetBlockShape | ||||||||
| 437 | ```cpp | 217 | ```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 | ### GetBlockCoord | 239 | ### GetBlockCoord | ||||||||
| 446 | ```cpp | 240 | ```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 | -### GetSplitKBlockCoord | 246 | +参数说明: | ||||||||
| 453 | -```cpp | 247 | +| 参数 | 类型 | 说明 | | ||||||||
| 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 | - // L2Cache | 286 | + // 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 | ```cpp | 297 | ```cpp | ||||||||
| 538 | ProblemShape shape{m, n, k, batch}; | 298 | ProblemShape 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 | ```cpp | 303 | ```cpp | ||||||||
| 549 | int64_t tileNum = scheduler.GetTileNum(); | 304 | int64_t tileNum = scheduler.GetTileNum(); | ||||||||
| 305 | +int64_t blockNum = scheduler.GetBlockNum(shape); | ||||||||||
| 550 | for (int64_t tileIdx = blockIdx; tileIdx < tileNum; tileIdx += blockNum) { | 306 | for (int64_t tileIdx = blockIdx; tileIdx < tileNum; tileIdx += blockNum) { | ||||||||
| 551 | // 处理 tile | 307 | // 处理 tile | ||||||||
| 552 | } | 308 | } | ||||||||
| @@ -556,27 +312,72 @@ for (int64_t tileIdx = blockIdx; tileIdx < tileNum; tileIdx += blockNum) { | |||||||||||
| 556 | ```cpp | 312 | ```cpp | ||||||||
| 557 | using B_T = half; | 313 | using B_T = half; | ||||||||
| 558 | bool TransB = false; | 314 | bool TransB = false; | ||||||||
| 559 | -auto blockShape = scheduler.GetBlockShape<TransB, B_T>(tileIdx, mOffset, nOffset, kOffset); | 315 | +auto blockShape = scheduler.GetBlockShape<TransB, B_T>(tileIdx); | ||||||||
| 560 | int64_t mL1 = Get<0>(blockShape); | 316 | int64_t mL1 = Get<0>(blockShape); | ||||||||
| 561 | int64_t nL1 = Get<1>(blockShape); | 317 | int64_t nL1 = Get<1>(blockShape); | ||||||||
| 562 | int64_t kL1 = Get<2>(blockShape); | 318 | int64_t kL1 = Get<2>(blockShape); | ||||||||
| 319 | +int64_t batch = Get<3>(blockShape); | ||||||||||
| 563 | int64_t mL0 = Get<4>(blockShape); | 320 | int64_t mL0 = Get<4>(blockShape); | ||||||||
| 564 | int64_t nL0 = Get<5>(blockShape); | 321 | int64_t nL0 = Get<5>(blockShape); | ||||||||
| 565 | ``` | 322 | ``` | ||||||||
| 566 | 323 | ||||||||||
| 567 | ### 获取 Block 坐标 | 324 | ### 获取 Block 坐标 | ||||||||
| 568 | ```cpp | 325 | ```cpp | ||||||||
| 569 | -// 正常场景 | ||||||||||
| 570 | auto blockCoord = scheduler.GetBlockCoord(tileIdx); | 326 | auto blockCoord = scheduler.GetBlockCoord(tileIdx); | ||||||||
| 571 | int64_t mOffset = Get<0>(blockCoord); | 327 | int64_t mOffset = Get<0>(blockCoord); | ||||||||
| 572 | int64_t nOffset = Get<1>(blockCoord); | 328 | int64_t nOffset = Get<1>(blockCoord); | ||||||||
| 573 | int64_t batchIdx = Get<3>(blockCoord); | 329 | int64_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 | -### Params | 70 | +### 结构定义 |
| 67 | -``` | 71 | +```cpp |
| 68 | struct Params { | 72 | struct 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 | 执行流程: |
| 113 | 1. 设置问题规模:`m_`, `n_`, `k_`, `batch_` | 123 | 1. 设置问题规模:`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 | -### GetTotalTileNum | 132 | +### 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 | ### GetHf32Flag | 138 | ### 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 | -### GetTileL1Shape | 144 | +### 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 | ### GetMNKTileNum | 151 | ### 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 | -### GetSingleCoreShape | 177 | +### 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 | -### GetSingleCoreCoord | 194 | +### 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(); |
| 269 | int64_t blockNum = scheduler.GetBlockNum(GetBlockNum()); | 276 | int64_t blockNum = scheduler.GetBlockNum(GetBlockNum()); |
| 270 | for (int64_t tileIdx = GetBlockIdx(); tileIdx < tileNum; tileIdx += blockNum) { | 277 | for (int64_t tileIdx = GetBlockIdx(); tileIdx < tileNum; tileIdx += blockNum) { |
| 271 | // 处理 tile | 278 | // 处理 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); |
| 288 | int64_t blkM = Get<0>(singleCoreShape); | 295 | int64_t blkM = Get<0>(singleCoreShape); |
| 289 | int64_t blkN = Get<1>(singleCoreShape); | 296 | int64_t blkN = Get<1>(singleCoreShape); |
| 290 | int64_t blkK = Get<2>(singleCoreShape); | 297 | int64_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); |
| 296 | int64_t mTileIdx = Get<0>(singleCoreCoord); | 303 | int64_t mTileIdx = Get<0>(singleCoreCoord); |
| 297 | int64_t nTileIdx = Get<1>(singleCoreCoord); | 304 | int64_t nTileIdx = Get<1>(singleCoreCoord); |
| 298 | int64_t kTileIdx = Get<2>(singleCoreCoord); // SK 模式有效 | 305 | int64_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(); | ||
| 313 | auto mnkTileNum = scheduler.GetMNKTileNum(); | 319 | auto mnkTileNum = scheduler.GetMNKTileNum(); |
| 314 | ``` | 320 | ``` |
| 315 | 321 | ||
| @@ -341,7 +347,7 @@ curKTileNum = 1(不切分 K) | |||
| 341 | ↓ | 347 | ↓ |
| 342 | kTileIdx = 0 | 348 | kTileIdx = 0 |
| 343 | ↓ | 349 | ↓ |
| 344 | -GetSingleCoreShape:blkK = k_(完整 K) | 350 | +GetBlockShape:blkK = k_(完整 K) |
| 345 | ↓ | 351 | ↓ |
| 346 | BlockMmad:输出到 GM | 352 | BlockMmad:输出到 GM |
| 347 | ``` | 353 | ``` |
| @@ -354,7 +360,7 @@ curKTileNum = skKTileNum(K 轴切分) | |||
| 354 | ↓ | 360 | ↓ |
| 355 | kTileIdx = (tileIdx % usedCoreNum) % curKTileNum | 361 | kTileIdx = (tileIdx % usedCoreNum) % curKTileNum |
| 356 | ↓ | 362 | ↓ |
| 357 | -GetSingleCoreShape:blkK = skSingleCoreK_ 或 tailSingleCoreK | 363 | +GetBlockShape:blkK = skSingleCoreK_ 或 tailSingleCoreK |
| 358 | ↓ | 364 | ↓ |
| 359 | BlockMmad:输出到 workspace | 365 | BlockMmad:输出到 workspace |
| 360 | ↓ | 366 | ↓ |
| @@ -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、Arguments) | 16 | +- 数据结构(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 |
| 14 | using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty; | 14 | using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty; |
| 15 | ``` | 15 | ``` |
| 16 | 16 | ||
| 17 | ### 计算模式 | 17 | ### 计算模式 |
| 18 | 仅在 AIC 核函数中执行,不支持 AIV 计算(AIV 核直接返回)。 | 18 | 仅在 AIC 核函数中执行,不支持 AIV 计算(AIV 核直接返回)。 |
| 19 | -``` | 19 | +```cpp |
| 20 | if ASCEND_IS_AIV { | 20 | if ASCEND_IS_AIV { |
| 21 | return; // AIV 核直接返回,不执行任何计算 | 21 | return; // AIV 核直接返回,不执行任何计算 |
| 22 | } | 22 | } |
| @@ -31,70 +31,113 @@ if ASCEND_IS_AIV { | |||
| 31 | ### FP32 大 K | 31 | ### 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 |
| 98 | for (int64_t tileIdx = curBlockIdx; tileIdx < tileNum; tileIdx += blockNum) { | 141 | for (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 并行处理不同 tile | 143 | // 多 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全载 |
| 146 | constexpr int64_t FULL_LOAD_MODE = 0; | 174 | constexpr 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< | |||
| 161 | using BlockEpilogue = Blaze::Gemm::Block::BlockEpilogueEmpty; | 188 | using 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 地址 | |||
| 176 | params.mmadParams.bGmAddr = bGM; // B 矩阵 GM 地址 | 203 | params.mmadParams.bGmAddr = bGM; // B 矩阵 GM 地址 |
| 177 | params.mmadParams.cGmAddr = cGM; // C 矩阵 GM 地址 | 204 | params.mmadParams.cGmAddr = cGM; // C 矩阵 GM 地址 |
| 178 | params.mmadParams.biasGmAddr = biasGM; // Bias GM 地址(可选,nullptr 表示无 bias) | 205 | params.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; // K 轴 L1 tile 尺寸 | 219 | +params.schParams.baseM = 128; // M 轴 L0 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; | |||
| 228 | mm(params); // 执行矩阵乘计算 | 233 | mm(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 | ```cpp | 239 | ```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 | ```cpp | 251 | ```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 | ```cpp | 264 | ```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 初始化 (设置缓冲策略) | |||
| 303 | ↓ | 285 | ↓ |
| 304 | 创建 GM Tensor (ND/NZ layout) | 286 | 创建 GM Tensor (ND/NZ layout) |
| 305 | ↓ | 287 | ↓ |
| 306 | -配置 L2 Cache (可选禁用) | 288 | +配置 L2 Cache (可选) |
| 307 | ↓ | 289 | ↓ |
| 308 | 遍历 tile → BlockMmad 执行 (每个 tile 独立计算) | 290 | 遍历 tile → BlockMmad 执行 (每个 tile 独立计算) |
| 309 | ↓ | 291 | ↓ |
| 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 地址是否为 nullptr | 123 | + |
| 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) | |||
| 133 | 3. BlockMmadStreamK 初始化 | 157 | 3. BlockMmadStreamK 初始化 |
| 134 | 4. Layout 构建:A、B、C、Bias | 158 | 4. Layout 构建:A、B、C、Bias |
| 135 | 5. GM Tensor 创建 | 159 | 5. GM Tensor 创建 |
| 136 | -6. Tile 循环处理: | 160 | +6. L2 Cache 配置(通过 SetL2Cache) |
| 161 | +7. Tile 循环处理: | ||
| 137 | - **DP 模式**:结果输出到 GM | 162 | - **DP 模式**:结果输出到 GM |
| 138 | - **SK 模式**:结果输出到 workspace | 163 | - **SK 模式**:结果输出到 workspace |
| 139 | - **Preload**:SK 模式下预加载下一轮 tile | 164 | - **Preload**:SK 模式下预加载下一轮 tile |
| 140 | -7. AIC-AIV 同步:设置 `AIC_SYNC_AIV_FLAG` | 165 | +8. AIC-AIV 同步:设置 `AIC_SYNC_AIV_FLAG` |
| 141 | -8. 清理:关闭 HF32/MM Layout Transform | 166 | +9. 清理:关闭 HF32 模式 |
| 142 | 167 | ||
| 143 | **AIV 核执行流程**: | 168 | **AIV 核执行流程**: |
| 144 | 1. Block 索引检查:超出处理范围则等待同步并返回 | 169 | 1. Block 索引检查:超出处理范围则等待同步并返回 |
| @@ -165,9 +190,9 @@ __aicore__ inline void operator()(Params const& params) | |||
| 165 | ### Preload 优化 | 190 | ### Preload 优化 |
| 166 | ``` | 191 | ``` |
| 167 | if (!bs.CheckIsSkScene(0)) { // SK Preload in DP+SK | 192 | if (!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 tile | 195 | + tmpTileIdx = tileIdx + usedCoreNum; // Preload 下一轮 SK tile |
| 171 | } | 196 | } |
| 172 | } | 197 | } |
| 173 | ``` | 198 | ``` |
| @@ -188,11 +213,12 @@ using BiasType = float; | |||
| 188 | using LayoutA = AscendC::Te::NDExtLayoutPtn; | 213 | using LayoutA = AscendC::Te::NDExtLayoutPtn; |
| 189 | using LayoutB = AscendC::Te::NZLayoutPtn; | 214 | using LayoutB = AscendC::Te::NZLayoutPtn; |
| 190 | using LayoutC = AscendC::Te::NDExtLayoutPtn; | 215 | using 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) |
| 193 | using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>; | 219 | using DispatchPolicy = Blaze::Gemm::MatmulMultiBlockWithStreamK<Blaze::Gemm::MatMulL0C2Out::ON_THE_FLY>; |
| 194 | 220 | ||
| 195 | -// 定义 BlockMmadStreamK | 221 | +// 定义 BlockMmad |
| 196 | using BlockMmad = Blaze::Gemm::Block::BlockMmad< | 222 | using 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 | |||
| 203 | using BlockScheduler = Blaze::Gemm::Block::BlockSchedulerStreamK<ProblemShape>; | 229 | using BlockScheduler = Blaze::Gemm::Block::BlockSchedulerStreamK<ProblemShape>; |
| 204 | 230 | ||
| 205 | // 定义 Kernel | 231 | // 定义 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 shape | 240 | {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 params | 242 | {cGM, workspaceGM}, // epilogue params |
| 217 | - {usedCoreNum, baseM, baseN, baseK, singleCoreK, kL1, isHf32} // scheduler params | 243 | + {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 | ``` |
| 231 | GM (A/B/Bias) → BlockScheduler (DP+SK 混合调度) → L1 → L0 → L0C | 257 | GM (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_t | 161 | // 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 32B | 249 | // 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 burst | 252 | // 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 Block | 274 | } // namespace Block |
| 270 | } // namespace Gemm | 275 | } // namespace Gemm |
| 271 | } // namespace Blaze | 276 | } // 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 transB | 57 | // 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 arguments | 70 | + // 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 | - | ||
| 97 | public: | 88 | public: |
| 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 n0 | 152 | // 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-BiasPong | 165 | // 普通模板-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->L1 | 170 | + // 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->L0 | 187 | // 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 | // 数据搬出到GM | 209 | // 数据搬出到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 | + | ||
| 301 | private: | 323 | private: |
| 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 Block | 339 | } // namespace Block |
| 318 | } // namespace Gemm | 340 | } // namespace Gemm |
| @@ -15,10 +15,11 @@ | |||
| 15 | 15 | ||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | - | ||
| 19 | 18 | ||
| 20 | -#include "tensor_api/tensor.h" | 19 | +#include "blaze/gemm/utils/layout_utils.h" |
| 20 | + | ||
| 21 | 21 | ||
| 22 | + | ||
| 22 | 23 | ||
| 23 | namespace Blaze { | 24 | namespace Blaze { |
| 24 | namespace Gemm { | 25 | namespace 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 tensor | 117 | + 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_ == nl0 | 135 | + 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 streamk | 149 | + 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 l1 | 151 | + 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 l1 | 162 | + |
| 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 l0a | 170 | + 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 biastable | 184 | + |
| 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 Block | 341 | } // namespace Block |
| 257 | } // namespace Gemm | 342 | } // namespace Gemm |
| 258 | } // namespace Blaze | 343 | } // namespace Blaze |
| @@ -16,81 +16,19 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | + | ||
| 19 | 20 | ||
| 20 | namespace Blaze { | 21 | namespace Blaze { |
| 21 | namespace Gemm { | 22 | namespace Gemm { |
| 22 | namespace Block { | 23 | namespace 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> |
| 30 | class BlockSchedulerMatmulBasic { | 26 | class BlockSchedulerMatmulBasic { |
| 31 | public: | 27 | public: |
| 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轴stride | 49 | uint32_t srcNdStride; // 非连续场景m轴stride |
| 115 | uint32_t innerBatch = 1; // 非连续transpose场景内轴batch值 | 50 | uint32_t innerBatch = 1; // 非连续transpose场景内轴batch值 |
| 116 | }; | 51 | }; |
| 117 | 52 | ||
| 118 | public: | 53 | public: |
| 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 | // 连续且非全载场景切K | 94 | // 连续且非全载场景切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 SplitN | 171 | // 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 | - // 连续场景切K | 211 | + |
| 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 | - | ||
| 361 | private: | 215 | private: |
| 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 Block | 301 | } // namespace Block |
| @@ -21,38 +21,10 @@ | |||
| 21 | namespace Blaze { | 21 | namespace Blaze { |
| 22 | namespace Gemm { | 22 | namespace Gemm { |
| 23 | namespace Block { | 23 | namespace Block { |
| 24 | + | ||
| 24 | template <class ProblemShape_> | 25 | template <class ProblemShape_> |
| 25 | class BlockSchedulerMatmulStreamK { | 26 | class BlockSchedulerMatmulStreamK { |
| 26 | public: | 27 | public: |
| 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 | ||
| 70 | public: | 43 | public: |
| 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 k | 53 | + 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 singlecore | 57 | 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 SK | 62 | 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 dp | 114 | 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 loop | 120 | // 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 Block | 172 | } // namespace Block |
| 195 | } // namespace Gemm | 173 | } // namespace Gemm |
| 196 | -} // namespace Blaze | 174 | +} // 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 | 16 | ||
| 17 | 17 | ||
| 18 | - | ||
| 19 | 18 | ||
| 20 | - | ||
| 21 | 19 | ||
| 22 | - | ||
| 23 | - | ||
| 24 | - | ||
| 25 | - | ||
| 26 | 20 | ||
| 27 | 21 | ||
| 28 | 22 | ||
| @@ -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 | // mmad | 48 | // 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 | // 初始化blockScheduler | 98 | // 初始化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 Fixpipe | 110 | + |
| 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 Format | 114 | // 默认ND Format |
| 186 | auto layoutA = MakeLayoutA{}(m_, k_); // ND layout for A | 115 | 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 Kernel | 255 | } // namespace Kernel |
| 260 | } // namespace Gemm | 256 | } // namespace Gemm |
| 261 | -} // namespace Blaze | 257 | +} // namespace Blaze |


🟡 Medium Priority
变更行(第228-234行):
block_mmad_matmul_streamk.md的 Params 初始化示例使用位置初始化,但参数顺序错误。证据链:
include/blaze/gemm/block/block_mmad_matmul_streamk.h第58-73行 Params 结构体字段顺序为:workspaceGM(意为 Workspace GM 地址)实际被赋给了第5个字段groupListGmAddr(GroupList 地址,预留扩展),而非预期的第6个字段workspaceGmAddrworkspaceGmAddr使用默认值nullptr,导致 StreamK 模式下 Workspace 输出目标为空影响:用户按此示例代码编写初始化逻辑后,StreamK 模式的 workspace 输出地址为 nullptr,可能导致运行时数据写入空地址,引发计算错误或程序崩溃。这是文档中的误导性代码示例,且 StreamK 场景下
workspaceGmAddr是必需的关键参数。修复方案:改用指定初始化器(designated initializers),与 Basic 文档示例风格保持一致:
建议:将示例代码从位置初始化改为指定初始化器,确保 workspaceGmAddr 字段被正确赋值:
.workspaceGmAddr = workspaceGM。