已合并
【CANN社区任务】aclblasCcopy算子开发 #1251
mengyijia创建于 7 天前
【CANN社区任务】aclblasCcopy算子开发 #1251
已合并
共 1 个文件变更+376-0
A04_tasks/01_community-task-2026/tasklist/08-44-aclblasCcopy-950/mengyijia_2026/docs/design.md+376-0
| @@ -0,0 +1,376 @@ | |||
| 1 | +# aclblasCcopy 算子设计文档 | ||
| 2 | + | ||
| 3 | +| 项目 | 内容 | | ||
| 4 | +| --- | --- | | ||
| 5 | +| 目标硬件 | Ascend 950PR(`ascend950`,`arch35`) | | ||
| 6 | +| 目标软件 | CANN 9.1.0、ops-blas 句柄式 BLAS 接口 | | ||
| 7 | +| 实现目录 | `ops-blas/blas/copy/arch35/` | | ||
| 8 | +| 测试目录 | `ops-blas/test/copy/ccopy/` | | ||
| 9 | + | ||
| 10 | +# 需求背景(required) | ||
| 11 | + | ||
| 12 | +## 需求来源 | ||
| 13 | + | ||
| 14 | +本设计对应 2026 年 8 月社区任务第 44 项“aclblasCcopy 算子开发(950)”。任务要求参考 | ||
| 15 | +cuBLAS `cublasCcopy` 和 Netlib BLAS `ccopy` 的语义,在 Ascend 950PR 上使用 Ascend C 实现 | ||
| 16 | +单精度复数向量复制,并将实现与测试工程提交至 ops-blas 仓库。 | ||
| 17 | + | ||
| 18 | +算子复用 `include/cann_ops_blas.h` 中已有的 `aclblasCcopy` 声明和 | ||
| 19 | +`include/cann_ops_blas_common.h` 中的 `aclblasComplex` 类型,不新增 950PR 私有接口。 | ||
| 20 | + | ||
| 21 | +## 背景介绍 | ||
| 22 | + | ||
| 23 | +### 算子功能 | ||
| 24 | + | ||
| 25 | +`aclblasCcopy` 将源向量的 `n` 个逻辑复数元素复制到目标向量。单个元素定义为: | ||
| 26 | + | ||
| 27 | +```cpp | ||
| 28 | +typedef struct aclblasComplex { | ||
| 29 | + float real; | ||
| 30 | + float imag; | ||
| 31 | +} aclblasComplex; | ||
| 32 | +``` | ||
| 33 | + | ||
| 34 | +一个 `aclblasComplex` 由相邻的实部和虚部两个 FP32 组成,占 8 B。算子不执行浮点运算或 | ||
| 35 | +类型转换,按位复制这 8 B 表示。`incx`、`incy` 是以复数元素为单位的非零步长,可以为正数 | ||
| 36 | +或负数;目标向量中未被逻辑索引命中的位置必须保持原值。 | ||
| 37 | + | ||
| 38 | +### 开发范围 | ||
| 39 | + | ||
| 40 | +| 内容 | 路径 | 作用 | | ||
| 41 | +| --- | --- | --- | | ||
| 42 | +| Host 实现 | `blas/copy/arch35/ccopy_host.cpp` | 参数校验、Tiling、可选 offset 表准备和 Kernel 下发 | | ||
| 43 | +| Kernel 实现 | `blas/copy/arch35/ccopy_kernel.cpp` | 连续及离散步长复制 | | ||
| 44 | +| Tiling 定义 | `blas/copy/arch35/ccopy_tiling_data.h` | Host 与 Kernel 共享切分参数 | | ||
| 45 | +| 测试工程 | `test/copy/ccopy/` | CSV 驱动 GTest、CBLAS 参考结果及验收脚本 | | ||
| 46 | + | ||
| 47 | +# 需求分析(required) | ||
| 48 | + | ||
| 49 | +## 需求描述 | ||
| 50 | + | ||
| 51 | +公共接口如下: | ||
| 52 | + | ||
| 53 | +```cpp | ||
| 54 | +aclblasStatus_t aclblasCcopy( | ||
| 55 | + aclblasHandle_t handle, | ||
| 56 | + int n, | ||
| 57 | + const aclblasComplex* x, | ||
| 58 | + int incx, | ||
| 59 | + aclblasComplex* y, | ||
| 60 | + int incy); | ||
| 61 | +``` | ||
| 62 | + | ||
| 63 | +接口参数顺序与 `cublasCcopy` 一致。`x`、`y` 位于 Device 内存,handle 保存执行 stream。 | ||
| 64 | +Kernel 在该 stream 上异步下发;调用方在读取 `y` 或释放相关内存前负责同步。 | ||
| 65 | + | ||
| 66 | +`n` 是非负逻辑元素数;`x`、`y` 是 Device 指针;`incx`、`incy` 是以复数元素为单位的 | ||
| 67 | +非零步长。具体校验顺序和返回码见 Host 侧设计。`n == 0` 时接口直接返回成功,不访问或校验 | ||
| 68 | +handle、x、y 和步长。 | ||
| 69 | + | ||
| 70 | +## 需求拆解 | ||
| 71 | + | ||
| 72 | +1. 支持 COMPLEX64 的按位复制,保持实部、虚部顺序及 y 的非写区域; | ||
| 73 | +2. 支持 `incx`、`incy` 的所有正、负非零组合; | ||
| 74 | +3. 连续输入输出采用双缓冲搬运,其他步长采用 Compact 离散搬运; | ||
| 75 | +4. 根据运行时 AIV 数量和 UB 容量完成多核与核内切分; | ||
| 76 | +5. 使用 CSV、CBLAS 参考结果和 msprof 完成功能、正确性及性能验证。 | ||
| 77 | + | ||
| 78 | +# 详细设计(required) | ||
| 79 | + | ||
| 80 | +## 算子分析 | ||
| 81 | + | ||
| 82 | +### 数学公式 | ||
| 83 | + | ||
| 84 | +接口以缓冲区低地址为基址。对逻辑索引 `i`,其中 `0 <= i < n`,物理索引为: | ||
| 85 | + | ||
| 86 | +$$ | ||
| 87 | +P(i, inc) = | ||
| 88 | +\begin{cases} | ||
| 89 | +i \cdot inc, & inc > 0 \\ | ||
| 90 | +(n - 1 - i) \cdot |inc|, & inc < 0 | ||
| 91 | +\end{cases} | ||
| 92 | +$$ | ||
| 93 | + | ||
| 94 | +复制语义为: | ||
| 95 | + | ||
| 96 | +$$ | ||
| 97 | +y[P(i, incy)].real = x[P(i, incx)].real | ||
| 98 | +$$ | ||
| 99 | + | ||
| 100 | +$$ | ||
| 101 | +y[P(i, incy)].imag = x[P(i, incx)].imag | ||
| 102 | +$$ | ||
| 103 | + | ||
| 104 | +这里的等号表示实部和虚部均按 32 位对象表示逐位复制。`n > 0` 时,x、y 所需的物理跨度分别为 | ||
| 105 | +`1 + (n - 1) * abs(incx)` 和 `1 + (n - 1) * abs(incy)` 个复数元素。 | ||
| 106 | + | ||
| 107 | +### 支持数据类型 | ||
| 108 | + | ||
| 109 | +算子仅支持 COMPLEX64。每个逻辑元素的物理布局为 `{float real; float imag;}`,大小为 8 B; | ||
| 110 | +不支持其他数据类型或类型转换。 | ||
| 111 | + | ||
| 112 | +### 支持形状 | ||
| 113 | + | ||
| 114 | +x、y 的逻辑形状均为一维 `[n]`,不支持广播、矩阵前导维或额外 Tensor 描述。 | ||
| 115 | + | ||
| 116 | +### 计算与带宽特征 | ||
| 117 | + | ||
| 118 | +本算子是 AIV-only 数据搬移算子,不使用 Cube。连续路径主要使用 MTE2(GM 到 UB)和 | ||
| 119 | +MTE3(UB 到 GM);离散且输入输出步长符号不同时,还需要在 UB 中对实部、虚部分别逆序。 | ||
| 120 | +每个逻辑元素从 GM 读取 8 B、向 GM 写入 8 B,理论最小流量为 16 B/元素,因此大规模连续 | ||
| 121 | +用例主要受 HBM 带宽和 MTE 流水效率限制。 | ||
| 122 | + | ||
| 123 | +## 算子实现 | ||
| 124 | + | ||
| 125 | +### 实现方案 | ||
| 126 | + | ||
| 127 | +Host 负责参数校验、分核、tileSize 计算及 Kernel 下发;AIV Kernel 根据步长选择连续路径或 | ||
| 128 | +Compact 离散路径。两条路径共用一个 Kernel 入口和一份 Tiling 数据。 | ||
| 129 | + | ||
| 130 | +```text | ||
| 131 | +aclblasCcopy | ||
| 132 | + -> 参数校验 | ||
| 133 | + -> 查询 AIV 数量和 UB 容量 | ||
| 134 | + -> 计算分核、tileSize 和可选 offset 表 | ||
| 135 | + -> 在 handle stream 下发 ccopy_kernel | ||
| 136 | + |- 连续双缓冲路径 | ||
| 137 | + `- Compact 通用步长路径 | ||
| 138 | +``` | ||
| 139 | + | ||
| 140 | +### Host 侧设计 | ||
| 141 | + | ||
| 142 | +#### 参数检查 | ||
| 143 | + | ||
| 144 | +| 顺序 | 条件 | 返回值 | | ||
| 145 | +| ---: | --- | --- | | ||
| 146 | +| 1 | `n < 0` | `ACLBLAS_STATUS_INVALID_VALUE` | | ||
| 147 | +| 2 | `n == 0` | `ACLBLAS_STATUS_SUCCESS` | | ||
| 148 | +| 3 | `handle == nullptr` | `ACLBLAS_STATUS_HANDLE_IS_NULLPTR` | | ||
| 149 | +| 4 | `x == nullptr` 或 `y == nullptr` | `ACLBLAS_STATUS_INVALID_VALUE` | | ||
| 150 | +| 5 | `incx == 0` 或 `incy == 0` | `ACLBLAS_STATUS_INVALID_VALUE` | | ||
| 151 | +| 6 | 平台报告的 AIV 核数为 0 | `ACLBLAS_STATUS_EXECUTION_FAILED` | | ||
| 152 | + | ||
| 153 | +Host 不检查 Device 指针的实际分配长度、地址归属和生命周期,这些由调用方保证。 | ||
| 154 | + | ||
| 155 | +#### Tiling 数据 | ||
| 156 | + | ||
| 157 | +```cpp | ||
| 158 | +struct CcopyTilingData { | ||
| 159 | + uint32_t totalN; | ||
| 160 | + uint32_t perCoreN; | ||
| 161 | + uint32_t extraBlockCores; | ||
| 162 | + uint32_t tailElements; | ||
| 163 | + uint32_t tileSize; | ||
| 164 | + int32_t incx; | ||
| 165 | + int32_t incy; | ||
| 166 | +}; | ||
| 167 | +``` | ||
| 168 | + | ||
| 169 | +`ELEMENTS_PER_BLOCK` 为 4 个复数,即 32 B,用于计算连续搬运的整块长度。 | ||
| 170 | +`CORE_ELEMENTS_PER_BLOCK` 为 8 个复数,即 64 B,用于分配各核的逻辑区间。这里保证的是 | ||
| 171 | +每核逻辑起始偏移按 8 个复数切分。对 `(+1,+1)` 连续路径,这等价于相对 x/y 基址按 64 B | ||
| 172 | +粒度切分;只有传入基址本身满足 64 B 对齐时,各核的连续 GM 起始地址才满足 64 B 对齐。 | ||
| 173 | +该结论不用于描述负步长下的物理低地址起点。 | ||
| 174 | + | ||
| 175 | +#### 分核策略 | ||
| 176 | + | ||
| 177 | +Host 运行时查询平台 AIV 数量: | ||
| 178 | + | ||
| 179 | +```text | ||
| 180 | +numBlocks = min(n, aivCoreNum) | ||
| 181 | +``` | ||
| 182 | + | ||
| 183 | +Ascend 950PR 自测环境返回 56 个 AIV,因此大规模用例启动 56 个 AIV block;代码不写死核数。 | ||
| 184 | +令 `A = 8`、`B = numBlocks`: | ||
| 185 | + | ||
| 186 | +```text | ||
| 187 | +rawPerCore = n / B | ||
| 188 | +perCoreN = floor(rawPerCore / A) * A | ||
| 189 | +leftover = n - perCoreN * B | ||
| 190 | +extraBlockCores = leftover / A | ||
| 191 | +tailElements = leftover % A | ||
| 192 | +``` | ||
| 193 | + | ||
| 194 | +前 `extraBlockCores` 个核各增加 8 个元素,最后一个核承担剩余的 `0..7` 个元素。第 c 个核的 | ||
| 195 | +逻辑起点和任务量为: | ||
| 196 | + | ||
| 197 | +```text | ||
| 198 | +offset(c) = c * perCoreN + min(c, extraBlockCores) * 8 | ||
| 199 | +count(c) = perCoreN | ||
| 200 | + + (c < extraBlockCores ? 8 : 0) | ||
| 201 | + + (c == B - 1 ? tailElements : 0) | ||
| 202 | +``` | ||
| 203 | + | ||
| 204 | +该策略避免把不足 8 个元素的尾部拆到多个核。 | ||
| 205 | + | ||
| 206 | +#### UB 与 tileSize | ||
| 207 | + | ||
| 208 | +`ubSize` 初始值为 248 KiB;平台管理器有效时,Host 调用 `GetCoreMemSize` 获取实际 UB 容量并 | ||
| 209 | +覆盖该值。公共接口在平台管理器无效、无法取得 AIV 数量时会先返回失败,因此正常 Tiling 路径 | ||
| 210 | +使用平台查询值;当前实现假定 `GetCoreMemSize` 查询成功。计算前预留 256 B,tileSize 向下取 | ||
| 211 | +8 个复数的整数倍。下表中的数值以本次 950PR 环境的 248 KiB UB 为例: | ||
| 212 | + | ||
| 213 | +| Host 判定场景 | UB 估算或命令限制 | tileSize | 248 KiB 下的结果 | | ||
| 214 | +| --- | --- | --- | ---: | | ||
| 215 | +| `incx == 1 && incy == 1` | 两个 queue 槽位,共 16 B/元素 | `floor((UB-256)/16/8)*8` | 15,856 | | ||
| 216 | +| 仅一侧等于 `+1` | queue 16 B、逆序临时数据 8 B、offset 4 B,共 28 B/元素 | `floor((UB-256)/28/8)*8` | 9,056 | | ||
| 217 | +| 两侧均不等于 `+1` | Compact 单命令 `blockCount <= 4095` | `floor(4095/8)*8` | 4,088 | | ||
| 218 | + | ||
| 219 | +后两种分类只用于计算安全的 tileSize;Kernel 中所有非 `(+1,+1)` 组合均进入 Compact 路径。 | ||
| 220 | +15,856、9,056 和 4,088 都是单次 tile 的容量,不是单核总处理量;单核数据超过 tileSize 时 | ||
| 221 | +会循环处理多个 tile。 | ||
| 222 | + | ||
| 223 | +#### 可选 offset workspace 与 Kernel 下发 | ||
| 224 | + | ||
| 225 | +当输入、输出步长符号不同时,需要在 tile 内逆序: | ||
| 226 | + | ||
| 227 | +```text | ||
| 228 | +needReorder = (incx < 0) XOR (incy < 0) | ||
| 229 | +offset[i] = (tileSize - 1 - i) * sizeof(float) | ||
| 230 | +``` | ||
| 231 | + | ||
| 232 | +Host 优先在 Host 内存中生成 offset 表,再复制到 handle 的有效 Device workspace,所需空间为 | ||
| 233 | +`tileSize * 4 B`。以本次 248 KiB UB 为例,单边 `+1` 场景需要 36,224 B,两侧均非 `+1` 场景 | ||
| 234 | +需要 16,352 B;这些数值随平台 UB 和 tileSize 变化,不是实现的固定上限。workspace 不可用或 | ||
| 235 | +容量不足时,Kernel 在 UB 中生成同一张表。 | ||
| 236 | + | ||
| 237 | +连续路径不准备 offset 表。异号步长且 workspace 可用时,Host 先生成表并通过 `aclrtMemcpy` | ||
| 238 | +复制到 Device workspace,随后在 `handle->stream` 上异步下发 Kernel。接口不显式调用 | ||
| 239 | +`aclrtSynchronizeStream` 或 `aclrtSynchronizeDevice`;Kernel 执行期错误由调用方后续同步操作暴露。 | ||
| 240 | + | ||
| 241 | +### Kernel 侧设计 | ||
| 242 | + | ||
| 243 | +#### 初始化与路径选择 | ||
| 244 | + | ||
| 245 | +Kernel 标记为 `KERNEL_TYPE_AIV_ONLY`。每个 block 根据 Tiling 计算 `myOffset`、`myCount`,并用 | ||
| 246 | +64 位中间值计算物理跨度和 GM 偏移;步长在取绝对值前提升为 `int64_t`,避免 `INT_MIN` 直接取负 | ||
| 247 | +产生 32 位溢出。 | ||
| 248 | + | ||
| 249 | +GM 在 Kernel 中映射为 FP32 视图,每个复数对应相邻两个 float。Kernel 初始化两个槽位的 | ||
| 250 | +`TQueBind<VECIN,VECOUT>`;非连续路径额外初始化 Gather 临时缓冲区。 | ||
| 251 | + | ||
| 252 | +#### 连续路径 | ||
| 253 | + | ||
| 254 | +`incx == +1 && incy == +1` 时进入连续路径: | ||
| 255 | + | ||
| 256 | +- 长度为 32 B 整数倍的主体使用 `DataCopy`; | ||
| 257 | +- 剩余 1 至 3 个复数使用 `DataCopyPad`,只向 y 写回有效字节; | ||
| 258 | +- 完整 tile 使用两个 queue 槽位执行 Prime-Pump-Drain,使 tile i 的 MTE2 读取与 tile i-1 的 | ||
| 259 | + MTE3 写回重叠; | ||
| 260 | +- 完整 tile 写回后,尾 tile 使用 `ContinuousIteration` 处理。 | ||
| 261 | + | ||
| 262 | +```text | ||
| 263 | +Prime: 读取 tile 0 | ||
| 264 | +Pump: 读取 tile i || 写回 tile i-1 | ||
| 265 | +Drain: 写回最后一个完整 tile | ||
| 266 | +Tail: 读取尾 tile -> 写回尾 tile | ||
| 267 | +``` | ||
| 268 | + | ||
| 269 | +该路径没有 Vector Compute 阶段,队列用于管理 MTE2/MTE3 缓冲区所有权和同步。 | ||
| 270 | + | ||
| 271 | +#### 离散与负步长路径 | ||
| 272 | + | ||
| 273 | +其他步长组合使用 `DataCopyPad<..., PaddingMode::Compact>`。每个 tile 在 UB 中拆成 real 和 imag | ||
| 274 | +两个 FP32 平面。每个 Compact block 搬运一个 4 B 分量,相邻 block 之间需要跳过的字节数为: | ||
| 275 | + | ||
| 276 | +```text | ||
| 277 | +(2 * abs(inc) - 1) * sizeof(float) | ||
| 278 | +``` | ||
| 279 | + | ||
| 280 | +因此,相邻同分量起始地址之间的距离为 `2 * abs(inc) * sizeof(float)`。 | ||
| 281 | + | ||
| 282 | +单个 Compact 命令最多处理 4,088 个逻辑元素;较大的 tile 在一次 `DiscreteIteration` 中拆为 | ||
| 283 | +多个 Compact batch。写回命令分别设置 real、imag 的目标 stride,只覆盖 y 的有效逻辑位置。 | ||
| 284 | + | ||
| 285 | +对逻辑区间 `[elementOffset, elementOffset + dataCount)`,物理低地址起点为: | ||
| 286 | + | ||
| 287 | +```text | ||
| 288 | +inc > 0: elementOffset * abs(inc) | ||
| 289 | +inc < 0: (totalN - elementOffset - dataCount) * abs(inc) | ||
| 290 | +``` | ||
| 291 | + | ||
| 292 | +Compact 按物理地址递增方向访问。incx、incy 同号时,输入和输出物理顺序一致;两者异号时, | ||
| 293 | +real 和 imag 分别逆序。offset 起点满足 8 元素对齐时,当前 tile 使用 `Gather`;否则整个 tile | ||
| 294 | +使用 `GetValue/SetValue` 逐元素处理。MTE2、Vector/Scalar、MTE3 之间通过事件同步。 | ||
| 295 | + | ||
| 296 | +#### 按位复制 | ||
| 297 | + | ||
| 298 | +Kernel 不执行浮点算术、共轭或类型转换。连续路径按交错 FP32 搬运,离散路径分别搬运 real、imag | ||
| 299 | +的 32 位对象表示。 | ||
| 300 | + | ||
| 301 | +## 支持硬件 | ||
| 302 | + | ||
| 303 | +| 支持的芯片版本 | SoC/架构 | 状态 | | ||
| 304 | +| --- | --- | --- | | ||
| 305 | +| Ascend 950PR | `ascend950` / `arch35` | 支持 | | ||
| 306 | + | ||
| 307 | +当前设计不声明对其他 SoC、架构或 CANN 版本的新增支持。 | ||
| 308 | + | ||
| 309 | +## 算子约束限制 | ||
| 310 | + | ||
| 311 | +1. x、y 的实际容量、地址有效性和异步执行期生命周期由调用方保证,Host 不做检查; | ||
| 312 | +2. 负步长调用传入物理缓冲区的低地址; | ||
| 313 | +3. 部分重叠且映射不同的 x/y 区域不提供 `memmove` 顺序保证。 | ||
| 314 | + | ||
| 315 | +# 可维可测分析 | ||
| 316 | + | ||
| 317 | +## 精度标准/性能标准 | ||
| 318 | + | ||
| 319 | +| 验收项目 | 判定方式 | 标准来源 | | ||
| 320 | +| --- | --- | --- | | ||
| 321 | +| 正确性 | 通过测试环境链接的 CBLAS `cblas_ccopy` 生成参考结果;完整 y 存储区中 real、imag 分别按 4 B 比较,要求逐位相等(`max_abs_error = 0`),非写区域保持不变 | 任务书 §2.1、§3.2、§3.5 | | ||
| 322 | +| 性能 | warmup 后采集大于 50 次 `ccopy_kernel/KERNEL_AIVEC` 设备任务并取平均;当前自测按 `NPU avg_us <= gpu_ms * 1000 / 0.4` 判定 | 配套 README、`gpu_baseline.csv` 和验证脚本 | | ||
| 323 | +| 内存 | 任务书未规定硬性阈值;报告实际资源用量。连续路径不使用 workspace,异号路径按 tileSize 使用可选 offset workspace | 任务书 §3.4、§4 | | ||
| 324 | + | ||
| 325 | +本算子不包含数值计算,因此正确性采用比通用 FLOAT32 `rtol/atol` 更严格的逐位比较。 | ||
| 326 | + | ||
| 327 | +## 功能与正确性验证 | ||
| 328 | + | ||
| 329 | +`arch35/ccopy_test.csv` 驱动 C++ GTest,CPU 侧调用测试环境链接的 `cblas_ccopy` 生成参考结果。 | ||
| 330 | +测试流程为: | ||
| 331 | + | ||
| 332 | +1. 按 n 和步长计算 x、y 的完整物理跨度,并在前后设置保护区; | ||
| 333 | +2. 调用 NPU 接口并将完整 y 分配区复制回 Host; | ||
| 334 | +3. 对每个存储位置的 real、imag 分别比较 4 B; | ||
| 335 | +4. 对错误用例检查返回码,NullHandle 使用独立测试; | ||
| 336 | +5. `verify_accuracy.py` 检查 CSV schema、用例注册集合和 GTest XML,拒绝失败、错误或跳过用例。 | ||
| 337 | + | ||
| 338 | +CSV 覆盖小尺寸、尺寸边界、正负步长组合、随机值、全零、正负交替、极值、Inf、NaN、地址偏移、 | ||
| 339 | +空指针、零步长和负 n。`verify_accuracy.py` 在运行期间生成并核查临时 GTest XML;正式提交时应 | ||
| 340 | +保存与对应代码版本匹配的终端日志和自测报告,供验收复核。 | ||
| 341 | + | ||
| 342 | +## 性能验证 | ||
| 343 | + | ||
| 344 | +`verify_performance_msprof.py` 调用 CANN 官方 `msprof`,使用 `--task-time=l0` 采集设备任务, | ||
| 345 | +在导出的 `task_time_*.csv` 中筛选: | ||
| 346 | + | ||
| 347 | +```text | ||
| 348 | +kernel_name = ccopy_kernel | ||
| 349 | +kernel_type = KERNEL_AIVEC | ||
| 350 | +``` | ||
| 351 | + | ||
| 352 | +`task_time(us)` 表示 Device Kernel 任务耗时,不包含 GTest 数据生成、H2D/D2H、CBLAS 参考结果和 | ||
| 353 | +结果比较;它也不等同于指令级 on-core 时间。默认每个 case 执行 5 次 warmup 和 55 次有效采样, | ||
| 354 | +输出平均值、中位数和 P95。 | ||
| 355 | + | ||
| 356 | +配套 README、`ccopy_test.csv`、`gen_csv.py` 和 `gpu_baseline.csv` 使用 | ||
| 357 | +`n=1,048,576 / 2,097,152 / 4,194,304` 三条典型连续用例,并按 GPU 基线除以 0.4 得到 NPU | ||
| 358 | +限值。任务书与配套材料的尺寸不一致,当前自测采用配套材料口径;最终验收口径由任务发布方确认, | ||
| 359 | +性能结果以对应代码版本保存的 CSV 和 msprof 记录为准。 | ||
| 360 | + | ||
| 361 | +## 兼容性分析 | ||
| 362 | + | ||
| 363 | +- 复用已有 `aclblasCcopy` 声明、`aclblasComplex` 类型和错误码,API/ABI 不变; | ||
| 364 | +- arch35 实现与其他架构目录隔离; | ||
| 365 | +- 沿用 ops-blas 的 handle、stream、workspace、日志和构建机制; | ||
| 366 | +- 测试工程沿用 copy 族的 CSV 和 GTest 模式。 | ||
| 367 | + | ||
| 368 | +## 参考资料 | ||
| 369 | + | ||
| 370 | +1. 随社区任务发放的《aclblasCcopy 算子开发任务书》; | ||
| 371 | +2. [cuBLAS Level-1 `cublasCcopy` 接口说明](https://docs.nvidia.com/cuda/cublas/index.html#cublas-t-copy); | ||
| 372 | +3. [Netlib BLAS `ccopy.f`](https://www.netlib.org/blas/ccopy.f); | ||
| 373 | +4. [ops-blas 开源仓](https://gitcode.com/cann/ops-blas)中的 `include/cann_ops_blas.h`、 | ||
| 374 | + `include/cann_ops_blas_common.h`、`blas/copy/arch35/` 和 `test/copy/ccopy/`; | ||
| 375 | +5. [Ascend C 算子开发文档](https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/850/opdevg/Ascendcopdevg/atlas_ascendc_map_10_0002.html); | ||
| 376 | +6. [Ascend C 基础 API 文档](https://www.hiascend.com/document/detail/zh/canncommercial/850/API/ascendcopapi/atlasascendc_api_07_0003.html)。 | ||