news 2026/9/18 13:52:49

CANN SiP 信号处理加速库 Asum(绝对值求和)算子实战指南:从 C++ Demo 编译到源码级实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN SiP 信号处理加速库 Asum(绝对值求和)算子实战指南:从 C++ Demo 编译到源码级实现解析

CANN SiP 信号处理加速库 Asum(绝对值求和)算子实战指南:从 C++ Demo 编译到源码级实现解析

【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库,基于华为Ascend AI处理器,专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip

导读

本文以 CANN SiP(信号处理加速库)中 Asum 算子的 C++ 调用示例(example/A2/BLAS/asum/README.md)为主线,完整讲解单精度(Sasum)与复数(Scasum)绝对值求和算子的数学原理、环境配置、SiP 库编译、Demo 构建与运行全流程,并结合 core/blas/asum.cpp 与 ops/blas/asum 下的算子实现,剖析 Asum 从 Host 侧 API 到 Device 侧 Kernel 的完整调用链。读完本文,你将能够在 Atlas A2/A3 系列昇腾硬件上独立编译、运行并二次开发 Asum 算子,同时理解其多核并行、双缓冲与 Atomic Add 累加的底层实现思路。

一、算子功能与数学原理

Asum(Absolute Sum)是 BLAS Level 1 中的经典规约算子,功能为对输入向量的所有元素取绝对值后求和。SiP 提供两个接口分别对应实数与复数输入:

  • asdBlasSasum:单精度(float32)绝对值求和。

    $$\text{result} = \sum_{i=0}^{n-1} |x_i|$$

    示例:输入x = [1, 2, -3, 4],输出result = 10

  • asdBlasScasum:复数(complex64)绝对值求和,对复数的实部与虚部分别取绝对值后再累加。

    $$\text{result} = \sum_{i=0}^{n-1} (|\text{Re}(x_i)| + |\text{Im}(x_i)|)$$

    示例:输入x = [1+2i, 2-2i, -3+3i, 4-3i],输出result = (1+2)+(2+2)+(3+3)+(4+3) = 20

两者的输出均为标量(shape 为[1]),数据类型统一为 float32。

二、环境配置与 SiP 加速库编译

2.1 CANN 环境变量配置

运行示例前需要先加载 CANN(Ascend CANN 工具包)环境变量:

source [CANN安装路径]/set_env.sh

默认路径为:

source /usr/local/Ascend/ascend-toolkit/set_env.sh

该命令会为后续编译提供ASCEND_HOME_PATH等关键环境变量(详见 example/A2/BLAS/asum/build.sh 中的引用方式)。

2.2 编译 SiP 信号处理加速库

进入 SiP 仓库根目录,执行:

cd ${SiP_root_path} bash build.sh source output/set_env.sh

output/set_env.sh会设置ASDSIP_HOME_PATH等加速库环境变量,供示例编译脚本使用。原文档特别说明了三点注意事项:

  1. 上述编译方式仅支持通过 git 下载的加速库;以 zip 压缩包方式下载的加速库不支持该编译方式;
  2. 编译过程需要联网下载依赖库,因此编译环境必须可以访问外网;
  3. 该编译过程包含两个步骤:获取并编译 ascend-boost-comm(昇腾分布式通信加速库)组件,以及编译信号加速库本身。更多命令介绍可查看 SiP 仓库根目录的 build.sh 文件。

更完整的编译命令说明请参考 docs/compilation_build.md。

2.3 运行 Demo

进入示例所在目录并执行构建脚本:

cd ${示例所在目录} bash build.sh

即:

cd example/A2/BLAS/asum bash build.sh

三、示例工程结构与构建脚本解析

3.1 目录内容

example/A2/BLAS/asum 目录下包含三个文件:

文件说明
README.md本示例的使用说明
example_sasum.cppSasum(float32 绝对值求和)示例,默认编译脚本可直接编译运行
example_scasum.cppScasum(complex64 绝对值求和)示例,需将编译脚本中的源文件替换后编译运行

3.2 构建脚本核心逻辑

example/A2/BLAS/asum/build.sh 的关键流程如下:

  1. 校验环境变量:要求ASDSIP_HOME_PATH已通过source output/set_env.sh设置,且目录真实存在(兼容以latest结尾的路径写法);将$ASDSIP_HOME_PATH/lib加入LD_LIBRARY_PATH
  2. 编译链接:使用g++编译示例源码,链接 ASCEND 侧库(-lascendcl -lopapi -lnnopbase)与 SiP 侧库(-lmki -lasdsip -lasdsip_core -lasdsip_host),头文件路径分别来自$ASCEND_HOME_PATH/include$ASDSIP_HOME_PATH/include
  3. 运行并清理:执行生成的example可执行文件,运行结束后删除临时产物。

从编译参数可以看出,示例程序同时依赖两个层面的组件:ACL(Ascend Compute Language)Runtime 层负责设备管理、内存管理与流管理;SiP 库(asdsip/asdsip_core/asdsip_host)提供asdBlas*高层 BLAS 接口;mki 库提供底层算子执行框架。

四、示例代码走读:从 ACL 初始化到算子调用

example_sasum.cpp 与 example_scasum.cpp 结构完全一致,仅输入数据类型与调用的算子接口不同。整个执行流程可划分为五个阶段:

4.1 ACL 初始化与流创建

Init()函数按固定写法完成 ACL 初始化:aclInit初始化 ACL 运行环境 →aclrtSetDevice(deviceId)指定设备(示例默认deviceId = 0)→aclrtCreateStream创建计算流stream。任一环节失败都会通过CHECK_RET宏打印错误并返回。

4.2 构造 Device 侧 Tensor

CreateAclTensor<T>()模板函数封装了"三段式"建张量流程:

  1. 申请 Device 内存aclrtMallocshape元素总数 × 元素大小申请显存(示例元素个数xSize = 8);
  2. 拷贝 Host 数据aclrtMemcpyACL_MEMCPY_HOST_TO_DEVICE方向将输入数据搬入 Device;
  3. 创建 aclTensor:计算连续 tensor 的 strides 后调用aclCreateTensor,声明数据格式为ACL_FORMAT_ND

数据格式方面:

  • example_sasum 输入使用std::vector<float>aclDataType::ACL_FLOAT
  • example_scasum 输入使用std::vector<std::complex<float>>aclDataType::ACL_COMPLEX64,输出result均为 float32。

4.3 Handle 生命周期与 Workspace 管理

示例完整展示了 SiP BLAS 算子"创建 → 绑 Plan → 申请 Workspace → 设置 Stream → 执行 → 同步 → 销毁"的标准流程(详见 docs/zh/API_Reference/BLAS/BLAS公共接口.md):

asdBlasHandle handle; asdBlasCreate(handle); // ① 创建全局唯一的 handle asdBlasMakeAsumPlan(handle); // ② 初始化 Asum 算子配置并绑定到 handle asdBlasGetWorkspaceSize(handle, lwork); // ③ 获取计算所需 workspace 大小 if (lwork > 0) { aclrtMalloc(&buffer, lwork, ACL_MEM_MALLOC_HUGE_FIRST); // 申请 workspace } asdBlasSetWorkspace(handle, buffer); // ④ 给 plan 设置 workspace asdBlasSetStream(handle, stream); // ⑤ 绑定运行流 ASD_STATUS_CHECK(asdBlasSasum(handle, n, inputX, incx, inputY)); // ⑥ 执行计算 asdBlasSynchronize(handle); // ⑦ 同步等待算子执行完成 asdBlasDestroy(handle); // ⑧ 销毁 plan 并释放资源,避免内存泄漏

要点说明:

  • n = 8表示参与计算的元素个数,incx = 1表示相邻元素的内存地址偏移量(当前约束为 1);
  • Workspace 是算子计算所需的临时缓冲,示例先通过asdBlasGetWorkspaceSize查询大小(示例场景下lwork通常为 0,即无需额外 workspace),再按需申请;
  • ASD_STATUS_CHECK宏将返回值与AsdSip::ErrorType::ACL_SUCCESS比较,失败即打印 "Execute failed." 并退出,用于快速定位接口调用错误。

4.4 结果回读与资源释放

计算完成后,通过aclrtMemcpyACL_MEMCPY_DEVICE_TO_HOST方向将result从 Device 拷回 Host,打印计算结果;随后依次执行aclDestroyTensoraclrtFree释放张量与显存,aclrtDestroyStream销毁流,aclrtResetDevice复位设备,最后aclFinalize结束 ACL 环境。

4.5 预期运行结果

  • example_sasum:输入x[i] = 1.0 + i(i = 0..7,即 1~8),输出result = 36
  • example_scasum:输入x[i] = {1+i, 3+i}(i = 0..7,即实部 1~8、虚部 3~10),输出result = 88

注:示例中生成的数据不代表实际场景,读者可根据具体使用场景修改数据(如通过参数调整nxSize或初始化数值)。

五、API 与 Host 侧实现源码解析

5.1 三个接口的函数原型

Asum 相关接口定义(详见 docs/zh/API_Reference/BLAS/Asum.md):

AspbStatus asdBlasMakeAsumPlan(asdBlasHandle handle); AspbStatus asdBlasSasum( asdBlasHandle handle, const int64_t n, aclTensor * x, const int64_t incx, aclTensor * result); AspbStatus asdBlasScasum( asdBlasHandle handle, const int64_t n, aclTensor * x, const int64_t incx, aclTensor * result);

参数说明汇总:

参数输入/输出描述
handle(asdBlasHandle)输入算子的句柄
n(int64_t)输入总的元素个数
x(aclTensor *)输入输入向量;Sasum 支持 float32,Scasum 支持 complex64;数据格式 ND,shape 为[n]
incx(int64_t)输入相邻元素间的内存地址偏移量(当前约束为 1)
result(aclTensor *)输出输出结果;数据类型 float32;数据格式 ND,shape 为[1]

所有接口均返回AspbStatus状态码,具体取值参见 docs/zh/context/SiP返回码.md。

5.2 Host 侧实现的关键细节

core/blas/asum.cpp 中asdBlasSasum/asdBlasScasum/asdBlasMakeAsumPlan的实现揭示了几个值得注意的点:

  • 类型与参数校验asdBlasSasum强制输入为ACL_FLOATasdBlasScasum强制输入为ACL_COMPLEX64,输出统一要求ACL_FLOAT;同时校验n > 0 && n <= UINT32_MAX,防止非法参数进入算子;tensor 格式必须为ACL_FORMAT_ND,否则返回格式不匹配错误码;
  • 复数按 2n 元素处理:复数 complex64 在内存中按"实部、虚部"交替存储。asdBlasScasum实际以ELEMENTS_EACH_COMPLEX64 * n(即 2n)个元素进入公共实现asdBlasSasumImpl,并传入scaSum = 1标记复数场景(core/blas/asum.cpp 据此决定存储维度的匹配方式);
  • incx 容错:当incx <= 0时实现内部将其修正为 1;
  • Plan 防重复绑定asdBlasMakeAsumPlan会检查 handle 是否已绑定 plan,防止重复初始化导致静默失败甚至 use-after-free(代码注释中提及 issue #129);
  • 执行入口:最终通过RunAsdOpsV2AsumOperation为算子名、OpParam::Asum(含nincx)为参数下发计算。

六、算子侧实现:Tiling、Kernel 与多核并行

6.1 算子注册与 Kernel 选择

ops/blas/asum/CMakeLists.txt 将 asum_operation.cpp、asum_kernel.cpp 与 sasum tiling 编译为AsumOperation,并将 sasum/kernel/sasum.cpp 注册为名为SasumF32Kernel的 ascend910b mix 内核。

  • asum_operation.cpp 中AsumOperation::GetBestKernel直接返回SasumF32Kernel,输入输出维度均为 1;
  • asum_kernel.cpp 中SasumF32Kernel::CanSupport校验输出 dtype 必须为TENSOR_DTYPE_FLOATInitImpl调用SasumTiling生成 tiling 数据,tiling 数据大小即sizeof(CommonTilingData)

6.2 Tiling:多核切分与 Workspace 申请

sasum_tiling.cpp 的SasumTiling完成了三件事:

  1. 核数决策:查询 Vector 核数量,但上限截断为DEFAULT_VECTOR_NUM = 40(即最多使用 40 个 Vector 核),核数为 0 时兜底为 1;
  2. 数据切分:调用ConfigCommonTilingData按核数将n个元素切分,为每个核生成offset(起始偏移)与calNum(计算数量),并以useCoreNum设置kernelInfo.SetBlockDim,即算子实际启动的核数;
  3. Workspace 声明:向kernelInfo注册WORKSPACE_SIZE = 16777216字节(16 MB)的 scratch 空间,供内核内ReduceSum规约使用。

6.3 Kernel:Abs + ReduceSum + 双缓冲 + Atomic Add

sasum_aiv.h 中SasumAIV<T>类实现了 Vector 核上的计算流水,其核心设计包括:

  • 数据切块:单次迭代最大搬运maxDataCount = 80 * 1024 / 4(80 KB,即 20480 个 float);Process()按整块 + 余数两段处理,余数部分走SingleIterationAligned,通过DataCopyPad补齐到 8 字节对齐再计算;
  • 双缓冲流水:输入队列inQueue与输出队列outQueue均配置BUFFER_NUM = 2,配合TPipe实现 CopyIn 与 Compute 的重叠,隐藏搬运时延;
  • 规约计算Compute()中先用Abs对输入取绝对值,再调用ReduceSum在片内完成求和,并借助workBuf暂存规约中间结果;
  • 跨核累加Process()前后分别调用SetAtomicAdd<T>()SetAtomicNone(),使多个 Vector 核的部分和通过 Atomic Add 安全累加到同一个输出地址outGM,从而得到全局总和;
  • 入口内核:sasum.cpp 中的sasum函数从 tiling 缓冲区读取ncoreNum、每个核的offsetcalNum,实例化SasumAIV<float>并调用Init/Process

综上,从源码结构看,Asum 在 Device 侧是一个"Tiling 多核切分 → 每核 Abs + 局部 ReduceSum → Atomic Add 汇总"的典型规约算子,双缓冲与 16 MB workspace 的配置为大规模向量(文档标注 n 覆盖范围 [1, 6.71e+06])提供了可扩展的执行路径。

七、约束说明与产品支持情况

7.1 参数与格式约束

  • 输入元素个数n当前覆盖支持范围[1, 6.71e+06]
  • 算子输入 shape 为[n],输出 shape 为[1]
  • 算子实际计算时,不支持 ND 高维度运算(不支持维度 ≥ 3 的运算),即当前版本仅面向一维向量场景;
  • incx当前约束为 1。

7.2 产品支持情况

根据 example/A2/BLAS/asum/README.md,Asum 示例适用于:

  • Atlas A2/A3 训练系列产品
  • Atlas 800I A2 推理产品
  • Atlas A3 推理系列产品

对应地,docs/zh/API_Reference/BLAS/Asum.md 中列出了更细粒度的支持矩阵:Atlas A2 训练/推理系列产品与 Atlas A3 训练/推理系列产品支持该算子;Ascend 950PR/Ascend 950DT、Atlas 200I/500 A2 推理产品、Atlas 推理系列产品(310p)、Atlas 训练系列产品(910)均不支持。在使用前请根据实际硬件型号确认支持情况。

八、实践小结

本文围绕 CANN SiP 的 Asum 算子示例,覆盖了从环境搭建、库编译、Demo 运行到 Host/Device 双侧源码实现的完整链路。作为开发者,你可以:

  1. 直接复用 example/A2/BLAS/asum 下的两个示例,快速验证硬件与库环境是否就绪;
  2. 参考示例中的 handle/plan/workspace 三段式流程,迁移到 SiP 其他 BLAS 算子的调用(如 example/A2/BLAS 目录下的 caxpy、cgemm、dot 等);
  3. 若要深入定制性能,可从 ops/blas/asum/sasum/tiling/sasum_tiling.cpp 的核数与切分策略、sasum_aiv.h 的缓冲与规约方式入手,结合 docs/zh/API_Reference/BLAS/Asum.md 的参数约束进行针对性调优。

注意:示例代码定位为快速上手的最小化实现,不提供生产级安全保障,不建议直接作为业务代码使用;若将其应用于真实业务场景,安全责任需自行承担。

【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库,基于华为Ascend AI处理器,专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 13:52:25

容器技术演进:从内核隔离到Docker镜像与Kubernetes编排

简介&#xff1a;一份系统梳理容器发展历史的Word文档&#xff0c;适合正在学习容器与Kubernetes的开发者、运维人员及架构师阅读&#xff0c;帮助理解容器技术真正要解决的问题及其在软件工程演进中的历史定位。资源围绕开发过程&#xff08;瀑布式、敏捷式、DevOps&#xff0…

作者头像 李华
网站建设 2026/9/18 13:51:56

如何十分钟把公众号搬进 RSS 阅读器?WeWe RSS 开源部署指南

如何十分钟把公众号搬进 RSS 阅读器&#xff1f;WeWe RSS 开源部署指南 【免费下载链接】wewe-rss &#x1f917;更优雅的微信公众号订阅方式&#xff0c;支持私有化部署、微信公众号RSS生成&#xff08;基于微信读书&#xff09; 项目地址: https://gitcode.com/GitHub_Tren…

作者头像 李华