ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CANN opbase CopyNpuToNpu 接口详解:device 侧到 device 侧数据拷贝任务的创建与执行

CANN opbase CopyNpuToNpu 接口详解:device 侧到 device 侧数据拷贝任务的创建与执行 CANN opbase CopyNpuToNpu 接口详解device 侧到 device 侧数据拷贝任务的创建与执行【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbaseCopyNpuToNpu 是 CANN opbase 基础框架库 framework_op 系列接口 中用于创建 device 侧到 device 侧NPU 到 NPU数据拷贝任务的核心函数。本文将结合 接口头文件 与 底层实现源码完整讲解其函数原型、参数语义、返回值与约束并深入到源码级剖析其拷贝任务是如何计算字节数、校验 tensor 放置位置、构建 launcher 并加入 executor 任务队列的最后给出可直接套用的调用示例与单元测试验证。功能说明CopyNpuToNpu 用于创建一个device 侧到 device 侧的数据拷贝任务并将其放入 executor 的任务队列中等待 executor 执行。它属于 L2 接口如 aclnnXxx中一阶段接口所使用的框架算子开发者无需手写算子实现而是把已经位于设备侧HBM的源 tensorsrc拷贝到同样位于设备侧的目的 tensordst中常用于算子内部实现中对中间结果或缓冲区的搬移。与之配套的框架算子还包括CopyToNpuhost 侧到 device 侧的拷贝函数返回指向 device 侧数据的aclTensorCopyToNpuSynchost 侧到 device 侧的同步拷贝立即拷贝并返回指向 device 侧数据的aclTensor不进入任务队列异步执行。三者的声明统一位于 framework_op.hnamespace op { const aclTensor* CopyToNpu(const aclTensor* src, aclOpExecutor* executor); const aclTensor* CopyToNpuSync(const aclTensor* src, aclOpExecutor* executor); aclnnStatus CopyNpuToNpu(const aclTensor* src, const aclTensor* dst, aclOpExecutor* executor); } // namespace op函数原型aclnnStatus CopyNpuToNpu(const aclTensor *src, const aclTensor *dst, aclOpExecutor *executor)该接口位于op命名空间下由 src/nnopbase/composite_op/aclnn_engine/z_framework_op.cpp 实现。参数说明参数输入/输出说明src输入拷贝的源 tensor必须为 device 侧HBMtensor。dst输入拷贝的目的 tensor必须为 device 侧HBMtensor且其存储字节数不小于源 tensor。executor输入L2 接口中一阶段接口声明的算子执行器对象aclOpExecutor拷贝任务将被加入该执行器的任务队列。参数语义的源码佐证从实现源码看函数对两个 tensor 的**放置位置placement**做了强校验z_framework_op.cppOP_CHECK(src-GetPlacement() op::TensorPlacement::kOnDeviceHbm, ... return ACLNN_ERR_INNER); OP_CHECK(dst-GetPlacement() op::TensorPlacement::kOnDeviceHbm, ... return ACLNN_ERR_INNER);即src与dst都必须满足op::TensorPlacement::kOnDeviceHbm否则接口直接返回ACLNN_ERR_INNER并记录错误日志。这一点比文档中的入参指针不能为空约束更进一步不仅指针要合法其指向的 tensor 还必须确实位于设备侧高带宽内存HBM上这与device 侧到 device 侧的语义严格对应。返回值说明创建拷贝任务成功则返回ACLNN_SUCCESS状态码值 0否则返回其他 aclnn 错误码。从源码可以归纳出可能返回的错误码场景错误码触发场景源码依据ACLNN_SUCCESS任务创建成功z_framework_op.cppACLNN_ERR_INNERsrc/dst 的 placement 不是kOnDeviceHbm或AddToKernelLauncherListCopyTask构建输入输出关系失败ACLNN_ERR_RUNTIME_ERROR实际执行阶段aclrtMemcpyAsync调用失败见下方执行原理需要说明的是接口返回成功仅代表拷贝任务已成功创建并入队实际的拷贝动作是在 executor 执行如Run()时才发生。约束说明入参指针不能为空即src、dst、executor均需为有效指针。源、目的 tensor 都必须位于 device 侧 HBMTensorPlacement::kOnDeviceHbm。目的 tensordst的存储字节数必须不小于源 tensorsrc的存储字节数否则实际执行时会失败见下文执行原理中的dstNByptes srcNByptes校验。拷贝任务不可被缓存复用源码注释明确指出 because rts memcpy cannot be cached, so abandon cache when use memcpyz_framework_op.cpp即 memcpy 类型的任务不走算子缓存。调用示例以下示例直接继承自原文档创建 src 到 dst 的拷贝任务如果不成功则返回。// 创建src到dst的拷贝任务 如果不成功则返回 void Func(const aclTensor *src, const aclTensor *dst, aclOpExecutor *executor) { if (CopyNpuToNpu(src, dst, executor) ! ACLNN_SUCCESS) { return; } }结合 executor 的完整调用流程在真实的 L2 接口实现中CopyNpuToNpu通常在算子内部配合 executor 使用。参考 tests/nnopbase/ut/composite_op/test_framework_op.cpp 中的单元测试可以还原出完整的创建 tensor → 创建拷贝任务 → 执行流程auto executor CREATE_EXECUTOR(); op::Shape shape {5, 10}; // 在device侧分配src与dst两个tensor均为DT_FLOAT、FORMAT_ND auto srcTensor executor.get()-AllocTensor(shape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND); auto dstTensor executor.get()-AllocTensor(shape, op::DataType::DT_FLOAT, op::Format::FORMAT_ND); // 创建device到device的拷贝任务 auto ret op::CopyNpuToNpu(srcTensor, dstTensor, executor.get()); EXPECT_EQ(ret, ACLNN_SUCCESS); // 释放executor所有权交由底层执行 aclOpExecutor* executorPtr nullptr; executor.ReleaseTo(executorPtr); EXPECT_EQ(executorPtr-CheckLauncherRepeatable(), false); // memcpy任务不可重复 ret executorPtr-Run(); // 真正执行拷贝 EXPECT_EQ(ret, ACLNN_SUCCESS); delete executorPtr;该测试同时验证了两个关键点拷贝任务入队后返回ACLNN_SUCCESS由于 memcpy 不可缓存CheckLauncherRepeatable()返回falseRun()执行完成后返回ACLNN_SUCCESS。源码级原理拷贝任务如何被创建与执行1. 字节数计算CalcTensorNBytes实际拷贝大小通过静态工具函数CalcTensorNBytes计算z_framework_op.cpp。它会根据 tensor 的数据类型大小TypeSize(tensor-GetDataType())与存储 shape 的GetShapeSize()相乘得到总字节数并使用ge::MulOverflow做乘法溢出保护溢出时返回ACLNN_ERR_INNER对小于 1 字节的类型如 1bit 的位宽类型先按位计算再通过(nBytes 7) 3换算成字节数对应BYTE_BITS_MINUS_ONE 7、LOG_2_BYTE_BITS 3两个常量。2. Launcher 封装与执行时机CopyNpuToNpu内部创建CopyNpuToNpuKernelLauncher继承自KernelLauncher见 z_framework_op.cpp真正的拷贝逻辑在其Launch()方法中完成auto calcRet CalcTensorNBytes(src_, srcNByptes); calcRet CalcTensorNBytes(dst_, dstNByptes); // 目的tensor容量必须不小于源tensor OP_CHECK(dstNByptes srcNByptes, ..., return ACLNN_ERR_INNER); // device到device的异步拷贝绑定在executor的流上 auto ret aclrtMemcpyAsync(dst_-GetData(), dstNByptes, src_-GetData(), srcNByptes, ACL_MEMCPY_DEVICE_TO_DEVICE, executor_-GetStream()); OP_CHECK(ret ACL_SUCCESS, ..., return ACLNN_ERR_RUNTIME_ERROR);关键点使用aclrtMemcpyAsync与ACL_MEMCPY_DEVICE_TO_DEVICE拷贝类型在executor_-GetStream()指定的流上异步执行因此执行顺序与流内其他任务保持一致该 launcher 的GetBin()返回nullptr即它不携带算子二进制kernel bin纯粹是运行时RTS层的 memcpy 任务不经过算子内核下发链路CheckRepeatable()恒返回false表明此类任务不可被重复执行缓存复用。3. 任务入队AddToKernelLauncherListCopyTaskCopyNpuToNpu主体将 src、dst 封装为OpArg类型OPARG_ACLTENSOR构造输入/输出参数列表后调用executor-AddToKernelLauncherListCopyTask(CopyNpuToNpuOpTypeId(), launcher, srcArgList, dstArgList, emptyArgList)z_framework_op.cpp把拷贝任务挂到 executor 的拷贝任务列表中。该调用同时负责建立输入输出关系用于 workspace 计算失败时返回ACLNN_ERR_INNER。4. 任务类型注册源码顶部通过OP_TYPE_REGISTER(CopyNpuToNpu)z_framework_op.cpp注册任务类型CopyNpuToNpuOpTypeId()即由此宏生成的任务类型标识用于在 executor 内部区分不同类型的拷贝任务。与 CopyToNpu / CopyToNpuSync 的对比接口拷贝方向返回类型同步/异步典型用途CopyToNpuhost → deviceconst aclTensor*失败返回 nullptr异步入队算子输入数据从 host 搬入 deviceCopyToNpuSynchost → deviceconst aclTensor*失败返回 nullptr同步立即拷贝需要立即拿到 device 侧数据的场景如固定内存搬移CopyNpuToNpudevice → deviceaclnnStatus异步入队算子内部 device 侧缓冲区、中间结果搬移三者均基于运行时aclrtMemcpyAsync/aclrtMemcpy实现区别仅在于拷贝类型ACL_MEMCPY_HOST_TO_BUF_TO_DEVICE、ACL_MEMCPY_HOST_TO_DEVICE、ACL_MEMCPY_DEVICE_TO_DEVICE以及是否进入 executor 任务队列。其中CopyNpuToNpu是唯一要求输入输出均位于 device 侧 HBM 的接口也是三者中唯一以aclnnStatus返回任务创建结果的接口便于调用方在任务创建阶段即可判断成败。总结CopyNpuToNpu 是 CANN opbase 中实现 NPU 内部数据搬移的轻量框架算子它通过严格的 placement 校验、带溢出保护的字节数计算以及基于aclrtMemcpyAsync的 launcher 封装将 device 到 device 的拷贝封装为 executor 任务队列中的一个异步任务。理解其参数约束HBM 放置、dst 容量不小于 src与创建成功 ≠ 执行完成的语义差异是在算子开发中正确使用该接口、排查ACLNN_ERR_INNER与ACLNN_ERR_RUNTIME_ERROR的关键。相关实现与验证可直接参阅 z_framework_op.cpp 与 test_framework_op.cpp。【免费下载链接】opbase本项目是CANN算子库的基础框架库为算子提供公共依赖文件和基础调度能力。项目地址: https://gitcode.com/cann/opbase创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表