已合并
【社区任务】aclblasCsymm 算子设计文档(Ascend 950PR) #1237
【社区任务】aclblasCsymm 算子设计文档(Ascend 950PR) #1237
已合并
ConanYao创建于 10 天前
1 个文件变更+378-0
@@ -0,0 +1,378 @@
1+# aclblasCsymm 算子设计文档
2+ 
3+| 项目 | 详情 |
4+|------|------|
5+| 算子名称 | aclblasCsymm |
6+| 开发语言 | Ascend C |
7+| 适配硬件 | Ascend 950PR |
8+| NPU 架构 | DAV_3510 / arch35 |
9+| CANN 版本 | CANN 9.1.0 |
10+| 对齐基准 | cuBLAS `cublasCsymm` / Netlib BLAS `csymm` |
11+| 最终合入仓 | ops-blas 开源仓,`blas/symm/arch35/` |
12+ 
13+# 1 需求背景(required)
14+ 
15+## 1.1 需求来源
16+ 
17+本任务来源于 CANN 社区任务 2026,目标是在 Ascend 950PR 上使用 Ascend C 开发单精度复数对称矩阵乘 BLAS 算子 `aclblasCsymm`,并最终合入 `cann/ops-blas` 开源仓。
18+ 
19+## 1.2 背景介绍
20+ 
21+`aclblasCsymm` 对齐 BLAS `csymm` 语义,用于计算复数对称矩阵与普通复数矩阵的乘加:
22+ 
23+- `side = ACLBLAS_SIDE_LEFT` 时,`C = alpha * A * B + beta * C`
24+- `side = ACLBLAS_SIDE_RIGHT` 时,`C = alpha * B * A + beta * C`
25+ 
26+其中 `A` 为复数对称矩阵,满足 `A = A^T`,不是 Hermitian 矩阵,不执行共轭处理,对角元素虚部也不置零。调用方只提供 `uplo` 指定的上三角或下三角有效数据,另一半由对称性隐含。
27+ 
28+本算子面向 ops-blas 句柄式接口,依赖 `aclblasHandle_t` 中绑定的 stream 进行异步 Kernel 直调。接口声明需新增到 `include/cann_ops_blas.h`,与其他产品线共享同一个 `aclblasCsymm` API,不定义 Ascend 950PR 私有接口。
29+ 
30+# 2 需求分析(required)
31+ 
32+## 2.1 需求描述
33+ 
34+使用 Ascend C kernel 直调方式实现 `aclblasCsymm`,支持 `COMPLEX64` 输入输出,支持 `side``uplo` 两个 BLAS 枚举,支持列主序矩阵和 `lda/ldb/ldc` 前导维度。算子需完整实现 BLAS quick return 和特殊标量语义,并满足任务书给出的精度、性能和异常返回要求。
35+ 
36+## 2.2 需求拆解
37+ 
38+| 序号 | 需求项 | 详细描述 | 优先级 |
39+|------|--------|----------|:------:|
40+| 1 | 接口声明 | 在 `include/cann_ops_blas.h` 新增 `aclblasCsymm` 声明,参数顺序对齐 cuBLAS | P0 |
41+| 2 | BLAS 语义 | 支持 LEFT/RIGHT,UPPER/LOWER,列主序 `lda/ldb/ldc` | P0 |
42+| 3 | 复数计算 | `aclblasComplex` 实部、虚部均为 float32,按 complex64 乘加 | P0 |
43+| 4 | 对称矩阵读取 | 仅引用 `uplo` 指定三角,另一侧按 `A = A^T` 映射,不共轭 | P0 |
44+| 5 | 标量语义 | 支持 `alpha``beta` 复数标量,处理 `alpha=0``beta=0/1` quick return | P0 |
45+| 6 | 参数校验 | 校验 handle、枚举、维度、指针和前导维,返回指定状态码 | P0 |
46+| 7 | arch35 直调 | 实现目录为 `blas/symm/arch35/`,适配 Ascend 950PR / DAV_3510 | P0 |
47+| 8 | 精度验收 | real/imag 分量按 FLOAT32 混合容差判定 | P0 |
48+| 9 | 性能验收 | 满足 256/1024 典型性能 case 标杆耗时 | P0 |
49+ 
50+## 2.3 外部组件依赖
51+ 
52+| 组件 | 说明 | 是否必需 |
53+|------|------|:--------:|
54+| CANN 9.1.0 | Ascend C 编译、运行和 BLAS 仓测试环境 | 是 |
55+| ops-blas | 句柄、状态码、公共复数类型、测试框架和合入目标仓 | 是 |
56+| cblas / Netlib BLAS | 自测 golden 生成,参考 `csymm` 行为 | 是 |
57+| Blaze / tensor_api | Ascend 950 / DAV_3510 MatMul 类算子推荐路径,可用于 Cube 矩阵乘 tile 组织 | 是 |
58+ 
59+# 3 详细设计(required)
60+ 
61+## 3.1 算子分析
62+ 
63+### 3.1.1 数学公式
64+ 
65+`A` 为对称复数矩阵,`B``C``m x n` 复数矩阵,全部按列主序存储。
66+ 
67+`side = LEFT`
68+ 
69+$$C_{i,j} = \alpha \sum_{k=0}^{m-1} A_{i,k} B_{k,j} + \beta C_{i,j}$$
70+ 
71+`side = RIGHT`
72+ 
73+$$C_{i,j} = \alpha \sum_{k=0}^{n-1} B_{i,k} A_{k,j} + \beta C_{i,j}$$
74+ 
75+复数乘法展开为:
76+ 
77+$$ (a_r + i a_i)(b_r + i b_i) = (a_r b_r - a_i b_i) + i(a_r b_i + a_i b_r) $$
78+ 
79+累加使用 float32 分量完成,不引入共轭,不对对角线虚部做特殊处理。
80+ 
81+### 3.1.2 支持数据类型
82+ 
83+| 参数 | dtype | 说明 |
84+|------|-------|------|
85+| alpha | COMPLEX64 | Host 侧复数标量 |
86+| beta | COMPLEX64 | Host 侧复数标量 |
87+| A | COMPLEX64 | Device 侧只读,对称矩阵 |
88+| B | COMPLEX64 | Device 侧只读,普通矩阵 |
89+| C | COMPLEX64 | Device 侧原地输出 |
90+ 
91+### 3.1.3 支持形状与格式
92+ 
93+| 参数 | side=LEFT | side=RIGHT | 格式 |
94+|------|-----------|------------|------|
95+| A | `m x m` | `n x n` | ND,Column-Major |
96+| B | `m x n` | `m x n` | ND,Column-Major |
97+| C | `m x n` | `m x n` | ND,Column-Major |
98+ 
99+`lda` 在 LEFT 场景要求 `lda >= max(1, m)`,在 RIGHT 场景要求 `lda >= max(1, n)``ldb >= max(1, m)``ldc >= max(1, m)`。本批次不支持超出 BLAS 前导维语义的非连续 tensor。
100+ 
101+## 3.2 使能方式
102+ 
103+| 上层框架 | 涉及勾选 | 说明 |
104+|----------|----------|------|
105+| TF训练/推理 | | 不涉及 |
106+| Pytorch训练/推理 | | 不涉及 |
107+| ATC推理 | | 不涉及 |
108+| Aclnn直调 | √ | ops-blas 句柄式 API 直调 |
109+| OPAT调优 | | 不涉及 |
110+| SGAT子图切分 | | 不涉及 |
111+ 
112+## 3.3 Host 侧设计
113+ 
114+Host 侧负责 BLAS 参数校验、quick return 判定、Tiling 计算和 Kernel launch,不承担矩阵计算。
115+ 
116+### 3.3.1 API 原型
117+ 
118+```cpp
119+aclblasStatus_t aclblasCsymm(
120+ aclblasHandle_t handle,
121+ aclblasSideMode_t side,
122+ aclblasFillMode_t uplo,
123+ int m, int n,
124+ const aclblasComplex* alpha,
125+ const aclblasComplex* A, int lda,
126+ const aclblasComplex* B, int ldb,
127+ const aclblasComplex* beta,
128+ aclblasComplex* C, int ldc);
129+```
130+ 
131+### 3.3.2 参数校验顺序
132+ 
133+| 校验项 | 条件 | 返回值 |
134+|--------|------|--------|
135+| handle | `handle == nullptr` | `ACLBLAS_STATUS_HANDLE_IS_NULLPTR` |
136+| side | 非 LEFT/RIGHT | `ACLBLAS_STATUS_INVALID_ENUM` |
137+| uplo | 非 UPPER/LOWER | `ACLBLAS_STATUS_INVALID_ENUM` |
138+| m/n | `m < 0``n < 0` | `ACLBLAS_STATUS_INVALID_VALUE` |
139+| alpha/beta | 任一为空 | `ACLBLAS_STATUS_INVALID_VALUE` |
140+| lda | LEFT: `lda < max(1,m)`;RIGHT: `lda < max(1,n)` | `ACLBLAS_STATUS_INVALID_VALUE` |
141+| ldb | `ldb < max(1,m)` | `ACLBLAS_STATUS_INVALID_VALUE` |
142+| ldc | `ldc < max(1,m)` | `ACLBLAS_STATUS_INVALID_VALUE` |
143+| A/B | `m > 0 && n > 0` 且为空 | `ACLBLAS_STATUS_INVALID_VALUE` |
144+| C | `m > 0 && n > 0 && beta != 0` 且为空 | `ACLBLAS_STATUS_INVALID_VALUE` |
145+ 
146+校验通过后,若 `m == 0 || n == 0`,直接返回 `ACLBLAS_STATUS_SUCCESS`。若 `alpha == (0,0) && beta == (1,0)`,直接返回成功,不启动 Kernel。若 `alpha == (0,0)``beta != (1,0)`,进入 C 缩放/清零分支。
147+ 
148+### 3.3.3 TilingKey 规划
149+ 
150+TilingKey 按以下维度编码,便于 Kernel 侧选择轻量分支:
151+ 
152+| 字段 | 取值 | 说明 |
153+|------|------|------|
154+| side | LEFT / RIGHT | 决定 K 维为 m 或 n,以及 A 的物理寻址方式 |
155+| uplo | UPPER / LOWER | 决定读取 A 上三角或下三角 |
156+| alphaBetaMode | GENERAL / ALPHA_ZERO / BETA_ZERO / BETA_ONE | 标量 epilogue 快路径 |
157+| shapeClass | SMALL / MEDIUM / LARGE | 小矩阵向量化路径或大矩阵 Cube 路径 |
158+| leadingDimMode | COMPACT / PADDED | `lda/ldb/ldc` 是否等于最小前导维 |
159+ 
160+### 3.3.4 Tiling 数据
161+ 
162+Host 侧生成以下核心 TilingData:
163+ 
164+| 字段 | 说明 |
165+|------|------|
166+| `m`, `n`, `k` | `k = (side == LEFT ? m : n)` |
167+| `lda`, `ldb`, `ldc` | Column-Major 前导维 |
168+| `alphaReal`, `alphaImag` | alpha 标量 |
169+| `betaReal`, `betaImag` | beta 标量 |
170+| `side`, `uplo` | BLAS 枚举 |
171+| `blockM`, `blockN`, `blockK` | 矩阵乘 tile 尺寸 |
172+| `usedCubeCoreNum`, `usedVectorCoreNum` | 实际使用核数,运行时从平台获取 |
173+| `workspaceSize` | 可选 workspace 大小,用于 A 对称 tile 展开和中间累加 |
174+| `tailM`, `tailN`, `tailK` | 尾块信息 |
175+ 
176+`blockM/blockN/blockK` 需满足 DAV_3510 Cube 阵列 16x16x16、L0A/L0B 64KB、L0C 256KB、L1 512KB、UB 248KB 等资源约束,并通过 `PlatformAscendC` 获取实际核数和 Buffer 容量,避免硬编码具体板卡核数。
177+ 
178+## 3.4 Kernel 侧设计
179+ 
180+### 3.4.1 总体方案
181+ 
182+`aclblasCsymm` 属于 MatMul 类算子。Ascend 950PR 对应 DAV_3510 / arch35,设计采用 Blaze / tensor_api 风格的矩阵乘 tile 组织作为主路径,并在同一个 Device Kernel 中完成以下步骤:
183+ 
184+1. 根据 `side/uplo` 对 A 执行对称寻址;
185+2.`COMPLEX64` 拆分为 real/imag 分量参与 float32 乘累加;
186+3. 完成 `A*B``B*A` 的分块累加;
187+4. 在 epilogue 中融合 `alpha``beta` 和 C 原地写回;
188+5. 处理尾块、padding 前导维和小尺寸场景。
189+ 
190+对称 A 不在 Host 侧展开。Kernel 侧按 tile 将所需 A 面板搬入片上存储;若当前 tile 访问到未显式存储的一侧,则根据 `uplo` 映射到显式三角中的对称位置。
191+ 
192+### 3.4.2 A 矩阵对称寻址
193+ 
194+Column-Major 下,矩阵元素地址为 `base + row + col * ld`
195+ 
196+`uplo = UPPER` 时:
197+ 
198+```text
199+A(i, k) = (i <= k) ? A_gm[i + k * lda] : A_gm[k + i * lda]
200+```
201+ 
202+`uplo = LOWER` 时:
203+ 
204+```text
205+A(i, k) = (i >= k) ? A_gm[i + k * lda] : A_gm[k + i * lda]
206+```
207+ 
208+`side = RIGHT` 时同理访问 `A(k, j)`,其中 A 的维度为 `n x n`。该映射只交换下标,不做 conjugate,不改变对角元素虚部。
209+ 
210+### 3.4.3 复数矩阵乘策略
211+ 
212+主计算可按 real/imag 分量拆成四个实数乘累加:
213+ 
214+```text
215+tmpReal = Ar * Br - Ai * Bi
216+tmpImag = Ar * Bi + Ai * Br
217+```
218+ 
219+对于每个输出 tile,Kernel 在 K 维循环累加 `tmpReal/tmpImag`,最后执行:
220+ 
221+```text
222+outReal = alphaReal * tmpReal - alphaImag * tmpImag
223+ + betaReal * oldReal - betaImag * oldImag
224+ 
225+outImag = alphaReal * tmpImag + alphaImag * tmpReal
226+ + betaReal * oldImag + betaImag * oldReal
227+```
228+ 
229+`beta == (0,0)` 时,跳过旧 C 读取;当 `beta == (1,0)` 时,旧 C 直接加到 epilogue;当 `alpha == (0,0)` 时,跳过 A/B 乘累加,仅处理 C 的缩放或清零。
230+ 
231+### 3.4.4 多核切分策略
232+ 
233+输出矩阵 C 按二维 tile 分配到 CubeCore:
234+ 
235+- LEFT 场景:输出 tile 维度为 `M x N`,K 维为 `m`
236+- RIGHT 场景:输出 tile 维度为 `M x N`,K 维为 `n`
237+- 每个 CubeCore 负责若干个输出 tile,优先按 tile 网格均匀分配;
238+- 小尺寸或 tile 数少于 CubeCore 数时,减少 `usedCubeCoreNum`,避免空核调度开销;
239+- 尾块通过 `curM/curN/curK` 表达逻辑有效范围,硬件 `blockM/blockN/blockK` 保持合法对齐粒度。
240+ 
241+对于性能典型 case:
242+ 
243+| case | 策略 |
244+|------|------|
245+| 256x256 LEFT UPPER | 使用较小 tile 增强并行度,减少 A 对称搬运重复 |
246+| 1024x1024 LEFT LOWER | 使用 full CubeCore 并行,K 维分块累加,A 面板按下三角映射 |
247+| 1024x1024 RIGHT UPPER | 输出按 N 维 tile 展开,优化 B 连续列访问和 A 上三角映射 |
248+ 
249+### 3.4.5 UB/L1/L0 Buffer 规划
250+ 
251+DAV_3510 的典型片上资源为 L1 512KB、L0A 64KB、L0B 64KB、L0C 256KB、UB 248KB。设计遵循运行时查询实际容量的原则。
252+ 
253+| Buffer | 用途 | 生命周期 |
254+|--------|------|----------|
255+| L1 A panel | 对称 A tile 展开后的 real/imag 面板 | K tile 内复用 |
256+| L1 B panel | B tile real/imag 面板 | K tile 内复用 |
257+| L0A/L0B | Cube 计算输入分块 | 单次 MMAD |
258+| L0C | real/imag 累加临时结果 | 输出 tile 生命周期 |
259+| UB tmp | A 三角到 dense tile 的重排、C epilogue、tail mask | 分阶段复用 |
260+| GM workspace | 可选,用于较大 tile 或调试路径保存中间结果 | 按 TilingData 配置 |
261+ 
262+UB 复用策略:
263+ 
264+- A 对称展开 buffer 与 C epilogue buffer 生命周期不重叠,可复用同一 TBuf;
265+- `beta == 0` 分支不申请旧 C 读入 buffer;
266+- 小矩阵路径尽量将 C tile 保持在 UB 中完成 alpha/beta epilogue;
267+- tile size 选择以不超过 `GetCoreMemSize(UB)` 返回容量为硬约束,目标是提升 UB 利用率,同时保留尾块 mask 和流水同步空间。
268+ 
269+### 3.4.6 分支场景覆盖
270+ 
271+| 分支 | 处理策略 |
272+|------|----------|
273+| LEFT + UPPER | A 访问 `A(i,k)`,当 `i > k` 时映射到 `A(k,i)` |
274+| LEFT + LOWER | A 访问 `A(i,k)`,当 `i < k` 时映射到 `A(k,i)` |
275+| RIGHT + UPPER | A 访问 `A(k,j)`,当 `k > j` 时映射到 `A(j,k)` |
276+| RIGHT + LOWER | A 访问 `A(k,j)`,当 `k < j` 时映射到 `A(j,k)` |
277+| alpha = 0, beta = 1 | Host quick return,不启动 Kernel |
278+| alpha = 0, beta = 0 | C 置零分支;若任务口径允许 C 为空,则直接成功返回 |
279+| alpha = 0, beta = general | 仅执行复数 C 缩放 |
280+| beta = 0 | 跳过旧 C 读取,直接写 `alpha * prod` |
281+| padded leading dimension | 按 `lda/ldb/ldc` 计算 GM 地址,不假设紧凑连续 |
282+| tail M/N/K | 使用逻辑 `curM/curN/curK` 和 mask 避免越界 |
283+ 
284+## 3.5 异常与边界设计
285+ 
286+| 场景 | 行为 |
287+|------|------|
288+| `m == 0 || n == 0` | 合法 no-op,返回 `ACLBLAS_STATUS_SUCCESS` |
289+| 非法枚举 | 返回 `ACLBLAS_STATUS_INVALID_ENUM` |
290+| 负维度 | 返回 `ACLBLAS_STATUS_INVALID_VALUE` |
291+| 非法前导维 | 返回 `ACLBLAS_STATUS_INVALID_VALUE` |
292+| `alpha/beta == nullptr` | 返回 `ACLBLAS_STATUS_INVALID_VALUE` |
293+| `A/B == nullptr` 且非空矩阵 | 返回 `ACLBLAS_STATUS_INVALID_VALUE` |
294+| `C == nullptr``beta != 0` | 返回 `ACLBLAS_STATUS_INVALID_VALUE` |
295+| Inf/NaN 输入 | 按 float32 复数算术自然传播,与 Netlib/cblas golden 对齐 |
296+ 
297+# 4 支持硬件
298+ 
299+| 支持的芯片版本 | 涉及勾选 |
300+|----------------|----------|
301+| Ascend 950PR | √ |
302+ 
303+# 5 算子约束限制
304+ 
305+| 约束项 | 内容 |
306+|--------|------|
307+| 数据类型 | 仅支持 `COMPLEX64` |
308+| 数据格式 | 仅支持 Column-Major ND |
309+| 对称性 | 调用方保证 A 满足 `A = A^T`,Kernel 不校验输入是否对称 |
310+| 三角读取 | 仅引用 `uplo` 指定三角,未引用三角内容不参与计算 |
311+| 共轭语义 | 不共轭,区别于 Hermitian `hemm` |
312+| 对角处理 | 对角元素虚部不置零、不修正 |
313+| 非连续 Tensor | 不支持超出 `lda/ldb/ldc` 语义的任意 stride/view |
314+| 动态 shape | `m/n` 为运行时参数,不要求图模式动态 shape |
315+| 原地语义 | C 原地覆写 |
316+| 确定性 | 不要求 bit-exact,按任务精度阈值验收 |
317+ 
318+# 6 可维可测分析
319+ 
320+## 6.1 精度标准
321+ 
322+Golden 使用 cblas / Netlib BLAS `csymm` 生成。`COMPLEX64` 的实部和虚部分别按 FLOAT32 混合容差判定:
323+ 
324+| 数据类型 | rtol | atol | required_matched_ratio | max_abs_error_limit |
325+|----------|------|------|------------------------|---------------------|
326+| COMPLEX64 分量 FLOAT32 | 2^-10 (9.77e-4) | 2^-16 (1.53e-5) | 0.99 | 1e-2 或 32 * ULP |
327+ 
328+逐元素通过条件:
329+ 
330+$$ |actual - golden| \leq atol + rtol \times |golden| $$
331+ 
332+用例级通过条件为 `matched_ratio >= 0.99``max_abs_error <= max_abs_error_limit`
333+ 
334+## 6.2 性能标准
335+ 
336+性能测试在 Ascend 950PR 上执行,先 warmup,再有效采样 50 次以上取平均。任务书给定性能门槛如下:
337+ 
338+| case | m | n | side | uplo | 标杆耗时 Avg time |
339+|------|---|---|------|------|-------------------|
340+| 1 | 256 | 256 | LEFT | UPPER | 7.53 us |
341+| 2 | 1024 | 1024 | LEFT | LOWER | 89.27 us |
342+| 3 | 1024 | 1024 | RIGHT | UPPER | 86.34 us |
343+ 
344+优化重点:
345+ 
346+- 用 Cube 路径承担主矩阵乘累加,避免纯 Vector 标量循环;
347+- 利用 `beta == 0/1``alpha == 0` 分支减少 GM 读取和复数乘法;
348+- 对紧凑前导维性能 case 使用连续 GM 访问和 tile 级 A/B 面板复用;
349+- 对 padded 前导维保持正确寻址,性能用例优先覆盖 compact 模式;
350+- 小矩阵减少启动核数,避免调度开销吞噬计算收益。
351+ 
352+## 6.3 自测设计
353+ 
354+随任务提供的 `csymm_test.csv` 覆盖 1200 条用例,其中精度 1000 条、性能/内存 200 条。设计验收时需覆盖:
355+ 
356+| 类别 | 覆盖内容 |
357+|------|----------|
358+| 基础功能 | LEFT/RIGHT 与 UPPER/LOWER 正交组合 |
359+| 尺寸扫描 | 0、1、小质数、2 的幂、2 的幂 ±1、非对齐值、大尺寸 |
360+| 标量特殊值 | `alpha/beta` 为 0、1、-1、纯虚数、大值 |
361+| 矩形矩阵 | 宽矩阵、窄矩阵 |
362+| 前导维 | `lda/ldb/ldc` 等于最小值和 padding 场景 |
363+| 输入分布 | 均匀、正态、全零、交替、极值、Inf、NaN |
364+| 负向用例 | 空指针、非法枚举、非法前导维、负维度 |
365+| 性能用例 | 任务书 3 条典型性能 case 及扩展性能扫描 |
366+ 
367+## 6.4 兼容性分析
368+ 
369+`aclblasCsymm` 是 ops-blas 中新增 API。接口声明放入公共头文件 `include/cann_ops_blas.h`,状态码和 `aclblasComplex` 复用 `include/cann_ops_blas_common.h`,不影响现有 `aclblasSsymm` 等接口。实现文件限定在 `blas/symm/arch35/`,后续如扩展其他产品线,应在同一 API 下增加对应 arch 实现,而不是新增私有接口。
370+ 
371+# 7 开发交付规划
372+ 
373+| 阶段 | 交付件 | 仓库 |
374+|------|--------|------|
375+| 设计评审 | `tasklist/08-aclblasCsymm-950/JaneConan/docs/design.md` | cann-ops-competitions |
376+| 算子实现 | `include/cann_ops_blas.h``blas/symm/arch35/` | ops-blas fork |
377+| 测试代码 | `test/symm/csymm/arch35/`、CSV 用例、README | ops-blas fork |
378+| 自测报告 | 精度、性能、内存占用和截图 | 验收系统附件 |