已合并
【社区任务】Cdotc算子设计文档 #1258
L创建于 8月30日
【社区任务】Cdotc算子设计文档 #1258
已合并
共 1 个文件变更+198-0
| @@ -0,0 +1,198 @@ | |||
| 1 | +# aclblasCdotc 算子设计文档 | ||
| 2 | + | ||
| 3 | +## 一、需求背景 | ||
| 4 | + | ||
| 5 | +### 1.1 需求来源 | ||
| 6 | + | ||
| 7 | +面向 Ascend 950PR 实现 `aclblasCdotc`,在 ops-blas 句柄和 stream 机制下完成单精度复数向量的共轭点积计算。 | ||
| 8 | + | ||
| 9 | +### 1.2 背景介绍 | ||
| 10 | + | ||
| 11 | +#### 1.2.1 aclblasCdotc 算子实现优化 | ||
| 12 | + | ||
| 13 | +`aclblasCdotc` 对向量 `x` 取共轭后与向量 `y` 做点积。对于第 `i` 个复数元素,实部累加 `x.real × y.real + x.imag × y.imag`,虚部累加 `x.real × y.imag - x.imag × y.real`,最终输出一个 COMPLEX64 标量。 | ||
| 14 | + | ||
| 15 | +输入采用实部、虚部交错存储。`incx` 和 `incy` 以复数元素为单位,可分别使用正步长或负步长。 | ||
| 16 | + | ||
| 17 | +#### 1.2.2 aclblasCdotc 算子现状分析 | ||
| 18 | + | ||
| 19 | +##### 1.2.2.1 标杆算子支持的数据类型和数据格式 | ||
| 20 | + | ||
| 21 | +| 对象 | 数据类型 | 数据排布 | 逻辑形状 | 步长 | | ||
| 22 | +| --- | --- | --- | --- | --- | | ||
| 23 | +| `x` | COMPLEX64 | 实部、虚部交错 | `[n]` | 非零整数 | | ||
| 24 | +| `y` | COMPLEX64 | 实部、虚部交错 | `[n]` | 非零整数 | | ||
| 25 | +| `result` | COMPLEX64 | 单个复数标量 | `[1]` | 不适用 | | ||
| 26 | + | ||
| 27 | +##### 1.2.2.2 标杆算子实现描述 | ||
| 28 | + | ||
| 29 | +标杆实现先校验输入参数,再将向量划分到多个 Vector Core。各核分块读取复数数据,完成共轭复乘和局部累加,将部分和写入工作空间,最后汇总为一个复数结果。 | ||
| 30 | + | ||
| 31 | +##### 1.2.2.3 标杆算子实现流程图 | ||
| 32 | + | ||
| 33 | +```mermaid | ||
| 34 | +flowchart TD | ||
| 35 | + A[参数校验] --> B[向量分片] | ||
| 36 | + B --> C[分块读取复数数据] | ||
| 37 | + C --> D[共轭复乘] | ||
| 38 | + D --> E[核内累加] | ||
| 39 | + E --> F[写入部分和] | ||
| 40 | + F --> G[汇总并输出结果] | ||
| 41 | +``` | ||
| 42 | + | ||
| 43 | +## 二、需求分析 | ||
| 44 | + | ||
| 45 | +### 2.1 外部组件依赖 | ||
| 46 | + | ||
| 47 | +| 依赖 | 使用阶段 | 用途 | | ||
| 48 | +| --- | --- | --- | | ||
| 49 | +| CANN ACL Runtime | 运行时 | 管理 handle、stream、异步清零和 Kernel 下发 | | ||
| 50 | +| Ascend C Kernel API | Kernel | 完成数据搬运、LocalMemory 管理、向量计算和归约 | | ||
| 51 | +| CPU 参考计算库 | 测试 | 生成精度参考结果 | | ||
| 52 | +| GoogleTest | 测试 | 驱动精度、边界和性能用例 | | ||
| 53 | + | ||
| 54 | +### 2.2 内部适配模块 | ||
| 55 | + | ||
| 56 | +| 模块 | 职责 | | ||
| 57 | +| --- | --- | | ||
| 58 | +| 公共接口 | 提供 `aclblasCdotc` 调用入口 | | ||
| 59 | +| Host | 校验参数、处理零长度输入、计算分核并下发 Kernel | | ||
| 60 | +| TilingData | 向 Kernel 传递长度、步长和使用核数 | | ||
| 61 | +| Kernel | 完成数据读取、共轭复乘、局部累加和最终归约 | | ||
| 62 | +| 测试 | 执行精度、边界和性能验证 | | ||
| 63 | + | ||
| 64 | +### 2.3 需求模块设计 | ||
| 65 | + | ||
| 66 | +#### 2.3.1 Ascend C 算子原型 | ||
| 67 | + | ||
| 68 | +对外接口为 `aclblasCdotc(handle, n, x, incx, y, incy, result)`,返回 `aclblasStatus_t` 状态码。 | ||
| 69 | + | ||
| 70 | +| 参数 | 含义 | | ||
| 71 | +| --- | --- | | ||
| 72 | +| `handle` | ops-blas 句柄,提供 stream 和工作空间 | | ||
| 73 | +| `n` | 参与计算的复数元素数量 | | ||
| 74 | +| `x`、`y` | Device 侧 COMPLEX64 输入向量 | | ||
| 75 | +| `incx`、`incy` | 两个输入向量的逻辑步长 | | ||
| 76 | +| `result` | Device 侧 COMPLEX64 输出标量 | | ||
| 77 | + | ||
| 78 | +计算任务异步下发到 handle 绑定的 stream。 | ||
| 79 | + | ||
| 80 | +#### 2.3.2 Ascend C 算子相关约束 | ||
| 81 | + | ||
| 82 | +- 支持 COMPLEX64 输入和输出; | ||
| 83 | +- `n` 不小于 0; | ||
| 84 | +- `n` 大于 0 时,输入、输出指针有效,`incx` 和 `incy` 不为 0; | ||
| 85 | +- 正步长按地址递增访问,负步长从对应逻辑起点反向访问; | ||
| 86 | +- `n` 等于 0 时返回零结果,不读取输入向量; | ||
| 87 | +- 仅支持单向量输入和标量输出,不支持 batch、broadcast 和原地更新。 | ||
| 88 | + | ||
| 89 | +## 三、需求详细设计 | ||
| 90 | + | ||
| 91 | +### 3.1 调用方式 | ||
| 92 | + | ||
| 93 | +用户通过 `aclblasCdotc` 发起计算。Host 完成参数校验和分核计算后,根据输入规模和步长选择执行路径,并将 Kernel 下发到 handle 绑定的 stream。连续快路径依次执行局部计算和最终归约;兼容路径直接输出结果。 | ||
| 94 | + | ||
| 95 | +### 3.2 需求总体设计 | ||
| 96 | + | ||
| 97 | +实现包含两类主要执行路径。大规模、正向单位步长输入使用多核并行计算,以提高连续访存吞吐;小规模或非单位步长输入使用顺序兼容计算,以保持稳定的累加顺序。两类路径共用相同的参数校验和输出语义。 | ||
| 98 | + | ||
| 99 | +#### 3.2.1 Host 侧设计 | ||
| 100 | + | ||
| 101 | +##### 3.2.1.1 分核策略 | ||
| 102 | + | ||
| 103 | +连续快路径使用不超过向量长度的可用 AIV 核。设使用核数为 `C`,每核处理 `n / C` 个元素,并将余数依次分配给前若干核,使各核负载差不超过一个元素。 | ||
| 104 | + | ||
| 105 | +顺序兼容路径使用单个 AIV,按输入的逻辑顺序完成计算。 | ||
| 106 | + | ||
| 107 | +##### 3.2.1.2 数据分块和内存优化策略 | ||
| 108 | + | ||
| 109 | +连续快路径根据可用 LocalMemory 容量确定分块大小。输入 `x` 和 `y` 各使用双缓冲,当前块计算时预取下一块,使数据搬运与计算重叠。每核只向工作空间写出一个复数部分和,最终归约仅需读取实际使用核产生的数据。 | ||
| 110 | + | ||
| 111 | +顺序兼容路径按固定容量分块读取数据。单位步长每块处理 4096 个复数,非单位步长每块处理 1024 个复数;输入队列和输出缓冲的总占用不超过 248 KiB LocalMemory。负步长通过调整每块起点和块内访问方向维持逻辑顺序。 | ||
| 112 | + | ||
| 113 | +工作空间保存每个核的实部和虚部部分和,大小为 `2 × align_up(C, 8) × sizeof(float)`。 | ||
| 114 | + | ||
| 115 | +##### 3.2.1.3 tilingKey 规划策略 | ||
| 116 | + | ||
| 117 | +算子采用 Kernel 直调方式,数据类型固定为 COMPLEX64,因此不设置 tilingKey。运行时根据向量长度和步长选择 Kernel,TilingData 只传递计算所需的长度、步长和核数。 | ||
| 118 | + | ||
| 119 | +#### 3.2.2 Kernel 侧设计 | ||
| 120 | + | ||
| 121 | +##### 3.2.2.1 Kernel 侧实现描述 | ||
| 122 | + | ||
| 123 | +连续快路径由多个 AIV 分别处理连续区间。各核分块搬入 `x` 和 `y`,完成共轭复乘和局部归约,再把部分和写入工作空间。随后由同一 stream 上的归约 Kernel 汇总所有部分和并写出结果。 | ||
| 124 | + | ||
| 125 | +顺序兼容路径由单个 AIV 分块读取输入,按照逻辑元素顺序执行 FP32 共轭复乘和累加,完成后直接写出结果。非单位步长通过跨步搬运压缩到连续 LocalMemory,负步长在块内恢复逻辑顺序。 | ||
| 126 | + | ||
| 127 | +##### 3.2.2.2 Ascend C 实现流程图 | ||
| 128 | + | ||
| 129 | +```mermaid | ||
| 130 | +flowchart TD | ||
| 131 | + A[Host 参数校验] --> B{零长度输入} | ||
| 132 | + B -->|是| C[异步清零并返回] | ||
| 133 | + B -->|否| D[计算核数和工作空间] | ||
| 134 | + D --> E{大规模正向单位步长} | ||
| 135 | + E -->|是| F[多核分块搬入与共轭复乘] | ||
| 136 | + F --> G[各核写出部分和] | ||
| 137 | + G --> H[归约 Kernel 汇总] | ||
| 138 | + E -->|否| I[单核顺序兼容计算] | ||
| 139 | + H --> J[写出结果] | ||
| 140 | + I --> J | ||
| 141 | +``` | ||
| 142 | + | ||
| 143 | +##### 3.2.2.3 Ascend C 实现流程图与标杆算子流程图存在的差异点和原因 | ||
| 144 | + | ||
| 145 | +| 差异点 | 本实现 | 原因 | | ||
| 146 | +| --- | --- | --- | | ||
| 147 | +| 核数选择 | 根据向量长度和可用 AIV 核数动态确定 | 提高大规模输入的并行度并兼顾小规模输入 | | ||
| 148 | +| 步长处理 | 支持正、负及混合步长 | 覆盖完整的向量访问方式 | | ||
| 149 | +| 最终归约 | 局部计算与最终归约使用两个顺序下发的 Kernel | 避免跨核同步并简化执行时序 | | ||
| 150 | +| 精度路径 | 小规模和非单位步长采用顺序累加 | 减少并行归约顺序变化带来的数值差异 | | ||
| 151 | + | ||
| 152 | +### 3.3 支持硬件 | ||
| 153 | + | ||
| 154 | +| 项目 | 说明 | | ||
| 155 | +| --- | --- | | ||
| 156 | +| 支持产品 | Ascend 950PR | | ||
| 157 | +| 编译架构 | arch35 / DAV_3510 | | ||
| 158 | +| CANN 版本 | 9.1.0 | | ||
| 159 | + | ||
| 160 | +### 3.4 算子约束限制 | ||
| 161 | + | ||
| 162 | +- 输入和输出位于 Device 内存; | ||
| 163 | +- `result` 为独立的 COMPLEX64 标量; | ||
| 164 | +- 步长单位为复数元素; | ||
| 165 | +- 并行归约受 FP32 加法顺序影响,不保证与其他实现逐位一致; | ||
| 166 | +- 接口异步执行,读取结果前需要同步对应 stream。 | ||
| 167 | + | ||
| 168 | +## 四、特性交叉分析 | ||
| 169 | + | ||
| 170 | +- 输入较大且连续时由多个计算核分段累加;输入较小或带有步长时,由一个计算核按元素原有顺序累加,减少加法顺序变化带来的误差。 | ||
| 171 | +- 步长为负时,从对应逻辑起点向低地址读取数据,保证参与计算的元素及其顺序正确。 | ||
| 172 | +- 计算当前数据块时提前读取下一块,分块大小根据 LocalMemory 容量确定,避免缓冲区超出可用空间。 | ||
| 173 | +- 每个计算核先将部分结果写入工作空间,最终归约在所有部分结果写入后执行;两步在同一 stream 中按顺序完成。 | ||
| 174 | +- 工作空间大小根据实际使用的计算核数量确定,Host 和 Kernel 采用一致的内存布局,避免越界或读取错位。 | ||
| 175 | + | ||
| 176 | +## 五、可维可测分析 | ||
| 177 | + | ||
| 178 | +### 5.1 精度标准/性能标准 | ||
| 179 | + | ||
| 180 | +精度测试分别比较结果的实部和虚部。FP32 结果采用相对误差 `2^-10`、绝对误差 `2^-16`,并限制误差不超过 `max(1e-2, 32 ULP)`;NaN 和 Inf 按特殊值类别比较。基础、步长、边界、特殊值和扩展精度用例均通过。 | ||
| 181 | + | ||
| 182 | +性能测试使用 ACL Event 采集 Kernel 耗时,预热后执行 100 次有效采样并取平均值。单位步长性能点如下: | ||
| 183 | + | ||
| 184 | +| 规模 | n | incx | incy | 实测耗时(us) | | ||
| 185 | +| --- | ---: | ---: | ---: | ---: | | ||
| 186 | +| 1M | 1048576 | 1 | 1 | 7.748610 | | ||
| 187 | +| 2M | 2097152 | 1 | 1 | 11.474650 | | ||
| 188 | +| 4M | 4194304 | 1 | 1 | 18.773500 | | ||
| 189 | +| 16M | 16777216 | 1 | 1 | 168.273582 | | ||
| 190 | + | ||
| 191 | +四个性能点均完成稳定运行和计时。 | ||
| 192 | + | ||
| 193 | +### 5.2 兼容性分析 | ||
| 194 | + | ||
| 195 | +- 保持公共 API、复数类型、handle 和 stream 使用方式不变; | ||
| 196 | +- 支持连续、非连续、正步长、负步长和混合步长输入; | ||
| 197 | +- 零长度、空指针、非法长度和零步长均按接口约束处理; | ||
| 198 | +- arch35 实现独立编译,不影响其他架构的既有实现。 | ||