尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

CANN SiP 加速库 Cgemv 实战:复数矩阵-向量乘接口的 Demo 全流程与源码剖析

CANN SiP 加速库 Cgemv 实战:复数矩阵-向量乘接口的 Demo 全流程与源码剖析 CANN SiP 加速库 Cgemv 实战复数矩阵-向量乘接口的 Demo 全流程与源码剖析【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库基于华为Ascend AI处理器专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip本文围绕 CANN 信号处理加速库SiPBLAS 模块中的Cgemv算子展开。通过 Cgemv C 调用示例 及配套 example_cgemv.cpp 的完整代码讲解覆盖从环境配置、加速库编译、Demo 构建运行到asdBlasMakeCgemvPlan/asdBlasCgemv接口参数、约束条件与底层 Plan/Kernel 实现的全链路。读完后你将能够独立编译并运行 Cgemv 示例、正确构造 aclTensor 输入、理解 Plan 阶段的张量预处理机制并定位到算子参数校验与 Kernel 分发的源码位置。功能说明与计算公式Cgemv 是一个复数域上的矩阵-向量乘法算子计算复数矩阵A与复数向量x的乘积并将结果累加回复数向量y。其计算公式为$$\mathbf{y} \alpha \cdot op(A) \cdot \mathbf{x} \beta \cdot \mathbf{y}$$其中A为复数矩阵m 行 n 列x、y为复数向量alpha、beta为复数标量op(A)表示A、A^T转置或A^H共轭转置由参数trans控制取值ASDBLAS_OP_N不转置、ASDBLAS_OP_T转置、ASDBLAS_OP_C共轭转置。官方接口文档 Cgemv 给出了一个可直接手算验证的最小示例输入矩阵A [[1i, 12i], [12i, 13i]]向量x [2i, 22i]y [00i]m2n2transASDBLAS_OP_Nalpha1ibeta22ilda2incx1incy1调用asdBlasMakeCgemvPlan生成 plan 后调用asdBlasCgemv输出y [-108i, -179i]。按公式手算A·x [-19i, -413i]乘以alpha(1i)后得[-108i, -179i]此时beta·y0与文档输出一致可作为本地联调时的快速自检用例。接口定义与参数说明两个接口均在 include/blas_api.h 中声明Plan 接口 asdBlasMakeCgemvPlan用于初始化句柄对应的 Cgemv 算子配置执行接口 asdBlasCgemv执行实际的矩阵-向量乘法。AspbStatus asdBlasMakeCgemvPlan( asdBlasHandle handle, asdBlasOperation_t trans, const int64_t m, const int64_t n, aclTensor * y, const int64_t incy); AspbStatus asdBlasCgemv( asdBlasHandle handle, asdBlasOperation_t trans, const int64_t m, const int64_t n, const std::complexfloat alpha, aclTensor * A, const int64_t lda, aclTensor * x, const int64_t incx, const std::complexfloat beta, aclTensor * y, const int64_t incy);asdBlasMakeCgemvPlan 参数参数名输入/输出描述handleasdBlasHandle输入算子的句柄transasdBlasOperation_t输入指定矩阵 A 是否转置ASDBLAS_OP_N不转置ASDBLAS_OP_T转置ASDBLAS_OP_C共轭转置mint64_t输入矩阵 A 的行数向量 y 的元素个数nint64_t输入矩阵 A 的列数向量 x 的元素个数yaclTensor *输入向量 yPlan 阶段即需绑定原因见下文“Plan 阶段的张量预处理”incyint64_t输入向量 y 的步长asdBlasCgemv 参数参数名输入/输出描述handleasdBlasHandle输入算子的句柄transasdBlasOperation_t输入同上OP_N/OP_T/OP_Cm / nint64_t输入矩阵 A 的行数/列数ldaint64_t输入矩阵 A 左右相邻元素间的内存地址偏移量当前约束为 mAaclTensor *输入矩阵 A数据类型 COMPLEX64数据格式 NDshape 为 [m, n]xaclTensor *输入向量 xCOMPLEX64NDshape 为 [n]yaclTensor *输入/输出向量 yCOMPLEX64NDshape 为 [m]alphastd::complex 输入复数标量乘以矩阵与向量乘法的结果betastd::complex 输入复数标量乘以向量 yincx / incyint64_t输入向量 x / y 的步长当前约束均为 1两个接口均返回状态码具体返回码含义参见 SiP 返回码。约束说明输入元素个数m、n当前覆盖支持 [1, 8193]算子输入矩阵 A 为列主序输入 shape 为 [m, n]、[n]输出 shape 为 [m]算子实际计算时不支持 ND 高维度运算不支持维度 ≥ 3 的张量。从源码的运行时校验可以进一步确认这些约束core/blas/cgemv.cpp 中的asdBlasCgemvParamCheck、CgemvDtypeCheck、CgemvShapeCheck分别校验lda 0、incx 1、incy 1A/x/y 三者必须均为ACL_COMPLEX64以及 A 的元素个数等于m*n、x 等于n、y 等于m。任何一项不满足都会返回ACL_ERROR_INVALID_PARAM/ACL_ERROR_UNSUPPORTED_DATA_TYPE/ACL_ERROR_OP_INPUT_NOT_MATCH等状态码Demo 中的ASD_STATUS_CHECK宏会对非成功状态直接打印失败信息并返回非零码。环境配置与 SiP 编译配置 CANN 环境变量source [CANN安装路径]/set_env.sh默认路径为source /usr/local/Ascend/ascend-toolkit/set_env.sh。编译 SiP 加速库进入 SiP 根目录执行编译并设置加速库环境变量cd ${SiP_root_path} bash build.sh source output/set_env.sh特别说明该编译方式仅支持通过 git 下载的加速库以 zip 压缩包方式下载的加速库不支持编译过程需要联网下载依赖库因此编译环境必须联网编译过程包括获取 ascend-boost-comm昇腾分布式通信加速库组件并编译该组件、编译信号加速库两个步骤。编译入口脚本为 build.sh其中fn_build_mki函数负责克隆并构建 ascend-boost-comm 组件。更多编译命令说明请参考 编译与构建。运行 Cgemv Demo示例工程位于 example/A2/BLAS/cgemv/ 目录按 README 说明执行进入示例所在目录执行构建脚本cd ${示例所在目录} bash build.sh示例工程的构建由 CMake 统一管理工程级配置可参考 example/CMakeLists.txt。下面按 example_cgemv.cpp 的执行顺序拆解关键步骤。1. ACL 初始化Init函数example_cgemv.cpp#L62-L72是标准三段式aclInit(nullptr)初始化运行环境aclrtSetDevice(deviceId)绑定设备示例固定为 0 号卡aclrtCreateStream(stream)创建计算流。后续 SiP 算子会通过asdBlasSetStream绑定到该流保证与 host 侧其他任务的异步执行。2. 构造测试数据示例采用 3×3 的复数测试矩阵m n 3A[i][j] (i, i)逐行取值 (0,0)、(1,1)、(2,2)x[i] (i1, 2)y[i] (1, 1)alpha beta (1.0, 1.0)trans ASDBLAS_OP_Nlda mincx incy 1。3. 创建 aclTensorCreateAclTensor模板函数example_cgemv.cpp#L74-L96封装了三个关键动作aclrtMalloc(..., ACL_MEM_MALLOC_HUGE_FIRST)申请 device 侧内存aclrtMemcpy将 host 数据以HOST_TO_DEVICE方式拷入计算连续 tensor 的 strides 后调用aclCreateTensor以ACL_FORMAT_ND格式创建张量并传入ACL_COMPLEX64数据类型。A、x、y 分别以 shape{m, n}、{n}、{m}创建。注意 strides 按行主序计算这与算子“矩阵 A 为列主序”的约定需要区分——示例数据为满秩连续张量lda m下二者在逻辑上等价实际业务中若 A 是列主序存储的矩阵切片应确保lda与真实行距一致。4. 句柄创建与 Plan 生成asdBlasHandle handle; asdBlasCreate(handle); size_t lwork 0; void* buffer nullptr; asdBlasMakeCgemvPlan(handle, trans, m, n, inputY, incy); asdBlasGetWorkspaceSize(handle, lwork); if (lwork 0) { ret aclrtMalloc(buffer, static_castint64_t(lwork), ACL_MEM_MALLOC_HUGE_FIRST); ... } asdBlasSetWorkspace(handle, buffer); asdBlasSetStream(handle, stream);注意几个调用顺序上的要点Plan 必须在执行前完成且 Plan 参数就包含y和incy。这是因为 Plan 阶段会预先把输入 y 拷贝到 device 内部缓存张量并生成 mask 张量详见后文源码剖析workspace 先查后申请asdBlasGetWorkspaceSize查询所需大小lwork 0时才aclrtMalloc再通过asdBlasSetWorkspace绑定asdBlasSetStream将句柄绑定到前面创建的 ACL 流算子在该流上异步执行。5. 执行算子、同步与结果取回ASD_STATUS_CHECK(asdBlasCgemv(handle, trans, m, n, alpha, inputA, lda, inputX, incx, beta, inputY, incy)); asdBlasSynchronize(handle); asdBlasDestroy(handle);asdBlasCgemv是异步提交asdBlasSynchronize等待 device 侧计算完成后再通过aclrtMemcpyDEVICE_TO_HOST将y拷回 host 并打印。资源释放遵循“先销毁张量、再释放 device 内存、最后销毁流、复位设备、aclFinalize”的逆序example_cgemv.cpp#L189-L198。需要提醒示例中生成的数据不代表实际场景可根据具体使用场景进行数据修改该样例旨在快速上手、开发和调试算子不推荐直接作为生产级业务代码使用。源码剖析从 API 到 Kernel 的调用链接口层参数校验与 Plan 缓存core/blas/cgemv.cpp 实现了两个公开接口。asdBlasMakeCgemvPlanL117-L151在创建BlasCgemvPlan并写入BlasPlanCache前做了多重守卫handle 非空、m 0 n 0且不超过UINT32_MAX、y ! nullptr、incy 1源码注释中还明确指出“handle 只能初始化一次”重复调用MakePlan会因静默失败导致使用未定义行为issue #129因此对已绑定 plan 的 handle 会直接返回ACL_ERROR_INVALID_PARAM。这与 blas_api.h 中 “Any given handle can only be initialized once” 的注释一致——一个 handle 只能初始化一次需要切换算子或形状时应新建 handle。asdBlasCgemvL55-L115的执行流程为std::lock_guard加锁并从BlasPlanCache取出缓存的BlasCgemvPlan要求doesPlanExist且IsInitialized依次执行参数、dtype、shape 三级检查将trans映射为整型编码ASDBLAS_OP_N → 0、ASDBLAS_OP_T → 1、ASDBLAS_OP_C → 2与m、n、lda、incx、incy、alpha、beta一起组装成OpParam::Cgemv参数结构定义见 ops/include/params/cgemv.h输入张量集合为{A, x, yIn, mask}其中yIn是 Plan 阶段预拷贝的输入 ymask为 Plan 阶段生成的掩码张量输出张量集合为{y}通过RunAsdOpsV2提交到句柄绑定的流上执行CgemvOperation。Plan 阶段y 的预拷贝与 mask 张量core/blas/blasplan/BlasCgemvPlan.cpp 是理解 Cgemv 与库中其他 BLAS 算子差异的关键SetyInTensorL94-L145通过aclGetStorageShape计算 y 的实际存储大小申请 device 内存并以ACL_MEMCPY_DEVICE_TO_DEVICE将输入 y 整体拷贝一份作为yInTensor。这就是为什么y要在asdBlasMakeCgemvPlan就传入——算子执行时以yIn参与beta·y项计算保证 y 的 in-place 语义下输入值不被破坏SetMaskTensorL43-L92构造一个 uint32 掩码张量以realOffset 0、imagOffset 1024为基准生成交错的字节偏移序列。从源码结构看该 mask 用于 Kernel 内区分/定位复数的实部与虚部数据通道属于 plan 级一次性预处理FreeTensor与析构函数配合BlasPlan::DestroyPlanData完成 plan 级设备内存释放。Kernel 层按 trans 分流算子实现位于 ops/blas/cgemv/cgemv_operation.cpp定义宿主侧 Operationcgemv/cgemv_kernel.cpp负责 kernel 调度tiling 逻辑在cgemv/cgemv/tiling/下cgemv_tiling.cpp/cgemv_tiling.h/cgemv_tiling_data.h。从源码结构看device 侧提供了两个 kernel 文件cgemv/cgemv/kernel/cgemv_no_trans.cce与cgemv/cgemv/kernel/cgemv_do_trans.cce可以推断接口层传入的 trans 编码0 为不转置1/2 为转置/共轭转置决定了 kernel 内走“按行直接累加”还是“按转置语义读取 A”的访存路径二者共享ascblasCgemv_utils.cceh中的公共工具函数。算子的 CMake 目标定义见 ops/blas/cgemv/CMakeLists.txt。产品支持情况示例工程example/A2/BLAS/cgemv/README.md声明适用于Atlas A2/A3 训练系列产品、Atlas 800I A2 推理产品、Atlas A3 推理系列产品接口文档docs/zh/API_Reference/BLAS/Cgemv.md中更细的产品维度支持矩阵Atlas A2 训练/推理系列、Atlas A3 训练/推理系列产品支持Ascend 950PR/950DT、Atlas 200I/500 A2 推理、Atlas 推理系列、Atlas 训练系列产品不支持。小结与延伸阅读Cgemv 的典型使用范式是asdBlasCreate → asdBlasMakeCgemvPlan绑定 trans/m/n/y/incy→ asdBlasGetWorkspaceSize asdBlasSetWorkspace → asdBlasSetStream → asdBlasCgemv → asdBlasSynchronize → asdBlasDestroy。开发时重点注意三件事一个 handle 只能初始化一次y需要设备侧可访问且 Plan 阶段即可用incx、incy当前必须为 1矩阵 A 按列主序理解、lda约束为m。进一步阅读可参考官方接口文档docs/zh/API_Reference/BLAS/Cgemv.md公开头文件include/blas_api.h、include/blas_common.h接口实现core/blas/cgemv.cpp、core/blas/blasplan/BlasCgemvPlan.cpp算子工程ops/blas/cgemv/cgemv_operation.cpp 及其 kernel/tiling 子目录单元测试tests/ut/unittest/blas/ 下的 BLAS 单测工程编译流程docs/compilation_build.md【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库基于华为Ascend AI处理器专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表