ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CANN Runtime TDT 数据传输接口详解:Tensor 通道创建、发送与接收

CANN Runtime TDT 数据传输接口详解:Tensor 通道创建、发送与接收 CANN Runtime TDT 数据传输接口详解Tensor 通道创建、发送与接收【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime导读本文围绕 CANN Runtime 中的 TDTTensor Data Transfer通道接口展开系统讲解用于 Host 与 Device 之间 Tensor 数据通道创建、发送、接收、停止与销毁的完整接口族acltdtCreateChannel、acltdtCreateChannelWithCapacity、acltdtSendTensor、acltdtReceiveTensor、acltdtStopChannel、acltdtDestroyChannel、acltdtQueryChannelSize、acltdtGetSliceInfoFromItem与acltdtCleanChannel。读完本文后你将掌握每个接口的参数语义、超时行为、产品支持范围并能结合仓库源码理解其底层基于 TDT 进程通道与队列Memory Queue式通道的双路径实现最终可在实际业务中正确完成 Tensor 数据的收发与资源管理。一、接口总览与两种通道实现路径TDT 接口解决的核心问题是业务侧Host 侧如何把预处理好的 Tensor 数据送入 Device 侧的队列或者从 Device 侧队列取出数据。文档定义的全部接口如下接口一句话说明acltdtCreateChannel创建通道可用于向 Device 发送数据或从 Device 接收数据acltdtCreateChannelWithCapacity创建带容量的通道acltdtSendTensor从 Host 向 Device 发送预处理好的数据acltdtReceiveTensor在 Host 接收 Device 发过来的数据acltdtStopChannel唤醒阻塞在发送/接收上的线程便于安全退出acltdtDestroyChannel销毁通道句柄释放通道资源acltdtQueryChannelSize查询队列通道内的消息数量acltdtGetSliceInfoFromItem输出 Tensor 分片信息分片数量、分片索引acltdtCleanChannel清空通道中的所有数据从源码看通道句柄的双路径设计从实现看通道句柄acltdtChannelHandle内部有一个关键标志位isTdtProcess见 tensor_data_transfer.h它把通道实现区分为两条路径TDT 进程路径isTdtProcess true通过动态加载libdatatransfer.so调用TdtHostInit、TdtHostPushData、TdtHostPopData、TdtHostStop、TdtHostDestroy等符号完成收发。该路径下timeout只能取-1阻塞等待且acltdtCleanChannel、acltdtQueryChannelSize均不支持返回ACL_ERROR_FEATURE_UNSUPPORTED。队列式通道路径isTdtProcess false通过acltdtCreateChannelWithCapacity创建底层走 Runtime 的 Memory Queue 机制rtMemQueueInit、rtMemQueueCreate、rtMemQueueEnQueueBuff、rtMemQueueDeQueueBuff、rtMemQueueQueryInfo、rtMemQueueReset、rtMemQueueDestroy支持超时、容量控制、通道清理与大小查询。这两条路径的入口分别位于 acltdtSendTensor 与 acltdtReceiveTensorTDT 路径以及acl::acltdtSendTensorV2与acl::acltdtReceiveTensorV2队列路径见 tensor_data_transfer.cpp。二、先认识三个核心数据结构与配套接口在收发 Tensor 之前需要理解 TDT 的数据组织模型Tensor → DataItem → Dataset。三者关系在 acl_tdt.h 中声明实现在 tensor_data_transfer.h 中定义acltdtDataItem标识一个业务上的 Tensor携带 Tensor 类型、维度dims、数据类型、数据指针与长度以及分片信息sliceNum/sliceId。acltdtDataset一组 DataItem 的集合内部为std::vectoracltdtDataItem* blobs并维护memType数据来自 Host 还是 Device与freeSelf标志。接收路径还内置了共享内存复用字段sharedMemSize_/sharedMem_用于性能优化。acltdtChannelHandle通道句柄保存通道名name、接收通道名recvName以TF_RECEIVE_前缀识别见 tensor_data_transfer.h、Device IDdevId、队列 IDqid与路径标志isTdtProcess。acltdtTensorType枚举定义了五类 Tensor 类型见 acl_tdt.h枚举值含义ACL_TENSOR_DATA_UNDEFINED -1未定义ACL_TENSOR_DATA_TENSOR普通 TensorACL_TENSOR_DATA_END_OF_SEQUENCE序列结束标志ACL_TENSOR_DATA_ABNORMAL异常数据ACL_TENSOR_DATA_SLICE_TENSOR分片 TensorACL_TENSOR_DATA_END_TENSOR分片结束标志配套的数据组装与读取接口详见 acl_tdt.h包括acltdtCreateDataItem、acltdtDestroyDataItem、acltdtCreateDataset、acltdtDestroyDataset、acltdtAddDataItem、acltdtGetDataItem、acltdtGetDatasetSize、acltdtGetTensorTypeFromItem、acltdtGetDataTypeFromItem、acltdtGetDataAddrFromItem、acltdtGetDataSizeFromItem、acltdtGetDimNumFromItem、acltdtGetDimsFromItem、acltdtGetDatasetName。其中acltdtCreateDataItem的参数校验值得注意见 tensor_data_transfer.cppdims与dimNum必须保持一致要么同时为 0要么同时非 0dimNum不能超过MAX_DIM_CNT 128当tdtType不是ACL_TENSOR_DATA_TENSOR时dims必须为nullptr支持的数据类型包括bool/int8/uint8/half/int16/uint16/float/int32/uint32/int64/uint64/double/string与aclDataType一一映射映射表见 tensor_data_transfer.cpp。acltdtAddDataItem则会校验一个 Dataset 内的数据地址类型必须一致不能混用 Host 地址与 Device 地址且已处于freeSelf状态内部已解析出数据项的 Dataset 不允许再追加数据项见 tensor_data_transfer.cpp。三、创建通道acltdtCreateChannel 与 acltdtCreateChannelWithCapacity3.1 acltdtCreateChannelacltdtChannelHandle *acltdtCreateChannel(uint32_t deviceId, const char *name)功能说明创建acltdtChannelHandle类型的数据表示可以用于向 Device 发送数据或是从 Device 接收数据的通道。通道使用完成后需及时依次调用acltdtStopChannel、acltdtDestroyChannel接口释放通道资源。产品支持情况Ascend 950PR/Ascend 950DT不支持Atlas A3 训练系列产品/Atlas A3 推理系列产品不支持Atlas A2 训练系列产品/Atlas A2 推理系列产品不支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品支持仅支持在昇腾虚拟化实例场景下使用本接口IPV350不支持参数说明参数名输入/输出说明deviceId输入Device ID。用户调用 aclrtGetDeviceCount 接口获取可用的 Device 数量后这个 Device ID 的取值范围[0, (可用的 Device 数量-1)]name输入队列通道名称的指针。返回值返回acltdtChannelHandle类型的指针表示成功返回nullptr表示失败。源码要点该接口在实现中会先通过GetFunction(TdtHostInit)获取并调用TdtHostInit(deviceId)完成 TDT 主机侧初始化然后创建句柄若通道名以TF_RECEIVE_开头则视为接收通道并调用TdtHostPreparePopData()做接收准备最后把句柄登记到全局aclChannleMap中见 tensor_data_transfer.cpp。3.2 acltdtCreateChannelWithCapacityacltdtChannelHandle *acltdtCreateChannelWithCapacity(uint32_t deviceId, const char *name, size_t capacity)功能说明创建带容量的通道适用于需要精确控制队列积压量的场景。产品支持情况Ascend 950PR/Ascend 950DT支持Atlas A3 训练系列产品/Atlas A3 推理系列产品支持Atlas A2 训练系列产品/Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品支持IPV350不支持参数说明参数名输入/输出说明deviceId输入Device ID。用户调用 aclrtGetDeviceCount 接口获取可用的 Device 数量后这个 Device ID 的取值范围[0, (可用的 Device 数量-1)]name输入队列通道名称的指针。capacity输入队列通道容量取值范围[2, 8192]。返回值返回acltdtChannelHandle类型的指针表示成功返回nullptr表示失败。源码要点队列式通道的创建链路可以拆解为见 tensor_data_transfer.cpp校验通道名长度要求strnlen(name, RT_MQ_MAX_NAME_LEN) 1 RT_MQ_MAX_NAME_LEN即名称不能超过 Runtime 内存队列名称上限组装acltdtQueueAttr属性attr.depth capacity容量即队列深度、workMode RT_MQ_MODE_DEFAULT、flowCtrlFlag false关闭流控、overWriteFlag false禁止覆盖写调用rtMemQueueInit(deviceId)完成队列模块初始化重复初始化返回ACL_ERROR_RT_REPEATED_INIT可容忍ACL_ERROR_RT_FEATURE_NOT_SUPPORT表示产品不支持调用rtMemQueueCreate(deviceId, attr, handle-qid)真正创建队列并取得队列 ID。从depth到capacity的映射说明通道容量对应队列深度文档明确取值范围为 [2, 8192]超出该范围将创建失败。四、数据发送与接收acltdtSendTensor / acltdtReceiveTensor4.1 acltdtSendTensoraclError acltdtSendTensor(const acltdtChannelHandle *handle, const acltdtDataset *dataset, int32_t timeout)功能说明从 Host 向 Device 发送预处理好的数据。产品支持情况Ascend 950PR/Ascend 950DT、Atlas A3 训练/推理系列产品、Atlas A2 训练/推理系列产品、Atlas 训练系列产品支持Atlas 200I/500 A2 推理产品、Atlas 推理系列产品、IPV350 不支持。参数说明参数名输入/输出说明handle输入指定通道。需提前调用acltdtCreateChannel接口或acltdtCreateChannelWithCapacity接口创建acltdtChannelHandle类型的数据。dataset输入向 Device 发送的数据的指针。类型定义请参见 acltdtDataset。timeout输入等待超时时间。取值范围如下--1阻塞方式一直等待直到数据发送完成。-0非阻塞方式当通道满时直接返回通道满这个错误这时由用户自行设定重试间隔。-0配置具体的超时时间单位为毫秒。通道满时等待达到超时时间后返回报错。超时时间受操作系统影响一般偏差在操作系统的一个时间片内例如操作系统的一个时间片为 4ms用户设置的超时时间为 1ms则实际的超时时间在 1ms 到 5ms 范围内。在 CPU 负载高场景下超时时间仍可能存在波动。返回值返回 0 表示成功返回其他值表示失败错误码请参见 aclError。典型错误为ACL_ERROR_RT_QUEUE_FULL通道满。源码要点队列路径下发送过程分三步完成见 acltdtSendTensorV2序列化TensorDatasetSerializesV2把 Dataset 中的每个 DataItem 转换为aclTdtDataItemInfo携带控制信息、dims、数据指针打包TensorDataitemSerialize将控制头ItemInfo与 dims 按64 字节对齐TDT_TENSOR_ALIGNE_UNIT 64写入控制缓冲数据缓冲紧随其后形成rtMemQueueBuffInfo向量见 tensor_data_transfer.cpp入队调用rtMemQueueEnQueueBuff(handle-devId, handle-qid, queueBuf, timeout)若返回ACL_ERROR_RT_QUEUE_FULL则直接透传该错误码由上层根据 timeout 语义处理。4.2 acltdtReceiveTensoraclError acltdtReceiveTensor(const acltdtChannelHandle *handle, acltdtDataset *dataset, int32_t timeout)功能说明在 Host 接收 Device 发过来的数据。产品支持情况与acltdtSendTensor相同Ascend 950PR/DT、Atlas A3、Atlas A2、Atlas 训练系列产品支持Atlas 200I/500 A2、Atlas 推理系列、IPV350 不支持。参数说明参数名输入/输出说明handle输入指定通道。需提前调用acltdtCreateChannel接口或acltdtCreateChannelWithCapacity接口创建acltdtChannelHandle类型的数据。dataset输出接收到的 Device 数据的指针。类型定义请参见 acltdtDataset。timeout输入等待超时时间。取值范围如下--1阻塞方式一直等待直到数据接收完成。-0非阻塞方式当通道空时直接返回通道空这个错误这时由用户自行设定重试间隔。-0配置具体的超时时间单位为毫秒。通道空时等待达到超时时间后返回报错。超时时间受操作系统影响一般偏差在操作系统的一个时间片内例如操作系统的一个时间片为 4ms用户设置的超时时间为 1ms则实际的超时时间在 1ms 到 5ms 范围内。在 CPU 负载高场景下超时时间仍可能存在波动。返回值返回 0 表示成功返回其他值表示失败错误码请参见 aclError。典型错误为ACL_ERROR_RT_QUEUE_EMPTY通道空。源码要点队列路径下接收过程如下见 acltdtReceiveTensorV2rtMemQueuePeek窥视队首缓冲长度不弹栈为空时返回ACL_ERROR_RT_QUEUE_EMPTYGetOrMallocHostMem申请 Host 侧接收缓冲并做内存复用优化申请大小按档位1MB / 10MB / 100MB / 500MB定义于 tensor_data_transfer.cpp向上取整并保存在dataset-sharedMem_中后续接收若所需长度不超过已申请大小则直接复用避免反复rtMallocHost/rtFreeHost同时该函数会通过EnsureCurrentThreadHasContext确保当前线程有可用的 Runtime ContextrtMemQueueDeQueueBuff弹出队首数据到 Host 缓冲UnpackageRecvDataInfo解析控制头与 dims还原出aclTdtDataItemInfo向量TensorDatasetDeserializesV2反序列化为acltdtDataItem并装入用户传入的 Dataset注意接收后 Dataset 处于freeSelf true状态析构时会自动释放内部 DataItem。五、通道生命周期停止、销毁与清理5.1 acltdtStopChannel —— 唤醒阻塞线程aclError acltdtStopChannel(acltdtChannelHandle *handle)功能说明调用acltdtSendTensor接口发送数据时或调用acltdtReceiveTensor接口接收数据时用户线程可能在没有数据时会卡住此时如果需要退出的话需要先将线程唤醒该接口用于唤醒处于阻塞状态的线程。需要用户在发送、接收线程之外的另一个线程里调用这个函数来唤醒处于阻塞状态的发送/接收线程。参数说明handle为指定通道需提前通过acltdtCreateChannel或acltdtCreateChannelWithCapacity创建。返回值返回 0 表示成功返回其他值表示失败。源码要点TDT 进程路径下对以TF_RECEIVE_开头的接收通道调用TdtHostStop(handle-recvName)以唤醒阻塞线程见 tensor_data_transfer.cpp队列式通道路径下该接口直接返回成功new process, stop channel is no use。5.2 acltdtDestroyChannel —— 销毁通道aclError acltdtDestroyChannel(acltdtChannelHandle *handle)功能说明销毁acltdtChannelHandle类型的数据只能销毁通过acltdtCreateChannel接口或acltdtCreateChannelWithCapacity接口创建的acltdtChannelHandle类型数据。参数说明handle为待销毁的acltdtChannelHandle类型的指针。返回值返回 0 表示成功返回其他值表示失败。源码要点队列式通道路径调用rtMemQueueDestroy销毁底层队列并释放句柄见 tensor_data_transfer.cppTDT 进程路径则从全局aclChannleMap中移除该通道当 map 为空时调用TdtHostDestroy()做全局清理随后释放句柄。5.3 acltdtCleanChannel —— 清空通道数据aclError acltdtCleanChannel(acltdtChannelHandle *handle)功能说明清空通道中的所有数据。参数说明handle为指定通道需提前通过acltdtCreateChannelWithCapacity接口创建。返回值返回 0 表示成功返回其他值表示失败。源码要点队列式通道路径通过rtMemQueueReset(handle-devId, handle-qid)复位队列实现清空TDT 进程路径不支持该操作返回ACL_ERROR_FEATURE_UNSUPPORTED见 tensor_data_transfer.cpp。六、通道状态查询acltdtQueryChannelSizeaclError acltdtQueryChannelSize(const acltdtChannelHandle *handle, size_t *size)功能说明查询队列通道内的消息数量。参数说明参数名输入/输出说明handle输入指定通道。需提前通过acltdtCreateChannelWithCapacity接口创建acltdtChannelHandle类型的数据。size输出消息数量的指针。返回值返回 0 表示成功返回其他值表示失败。源码要点队列式通道路径通过rtMemQueueQueryInfo获取rtMemQueueInfo_t并返回info.size见 tensor_data_transfer.cppTDT 进程路径不支持返回ACL_ERROR_FEATURE_UNSUPPORTED。结合文档可知该接口与acltdtCreateChannelWithCapacity配套使用——只有带容量的队列式通道才有消息数量这一概念。七、Tensor 分片信息acltdtGetSliceInfoFromItemaclError acltdtGetSliceInfoFromItem(const acltdtDataItem *dataItem, size_t *sliceNum, size_t *sliceId)功能说明用于输出 Tensor 分片信息。使用场景OutfeedEnqueueOpV2 算子由于其功能要求需申请 Device 上的大块内存存放数据在 Device 内存不足时可能会导致内存申请失败进而导致某些算子无法正常执行。该场景下用户可以调用本接口获取 Tensor 分片信息分片数量、分片索引再根据分片信息拼接算子的 Tensor 数据。参数说明参数名输入/输出说明dataItem输入acltdtDataItem类型的指针。acltdtDataItem用于标识一个业务上的 Tensor。类型定义请参见 acltdtDataItem。需提前调用 acltdtCreateDataItem 接口创建acltdtDataItem类型的数据。sliceNum输出单个 Tensor 被切片的数量。sliceId输出被切片 Tensor 的数据段索引。返回值返回 0 表示成功返回其他值表示失败。源码要点分片信息在数据项内部以uint16_t存储acltdtDataItem::sliceNum与acltdtDataItem::sliceId该接口对三个入参做空指针校验后直接输出见 tensor_data_transfer.cpp。分片信息随ItemInfo控制头在收发路径中传递见 tensor_data_transfer.h 中的sliceNum/sliceId字段并在反序列化时回填到acltdtDataItem上。产品支持情况Ascend 950PR/Ascend 950DT、Atlas A3 训练/推理系列产品、Atlas A2 训练/推理系列产品、Atlas 训练系列产品支持Atlas 200I/500 A2 推理产品、Atlas 推理系列产品、IPV350 不支持。八、实战示例基于仓库样例打通收发全流程仓库 example/2_advanced_features/tdt_channel 目录提供了两个可直接编译运行的 TDT 样例是理解上述接口用法的权威参考。8.1 示例一0_simple_channel —— 单进程内发送与接收主流程位于 main.cpp其关键步骤如下初始化调用aclInit(nullptr)初始化 AscendCLaclrtSetDevice(0)指定 Device创建通道acltdtCreateChannelWithCapacity(0, simple_tdt_channel, 2)容量取 2构造发送 Dataset通过tdt::CreateFloatDataset见 tdt_common_utils.h把std::vectorfloat构造成 DataItemACL_TENSOR_DATA_TENSOR类型、dims {1, N}、ACL_FLOAT再放入 DatasetacltdtDataItem* item acltdtCreateDataItem( ACL_TENSOR_DATA_TENSOR, dims, sizeof(dims) / sizeof(dims[0]), ACL_FLOAT, values.data(), values.size() * sizeof(float)); acltdtDataset* dataset acltdtCreateDataset(); acltdtAddDataItem(dataset, item);发送acltdtSendTensor(channel, sendDataset, 1000)超时 1000ms查询acltdtQueryChannelSize(channel, channelSize)发送后通道大小为 1接收acltdtReceiveTensor(channel, recvDataset, 1000)校验用acltdtGetDatasetSize、acltdtGetDataItem、acltdtGetDimNumFromItem、acltdtGetDimsFromItem、acltdtGetDataAddrFromItem、acltdtGetDataTypeFromItem、acltdtGetTensorTypeFromItem、acltdtGetDataSizeFromItem读取并打印接收到的 Tensor 元信息接收后通道大小恢复为 0清理依次调用acltdtCleanChannel、acltdtStopChannel、acltdtDestroyChannel释放通道再销毁 Dataset/DataItem最后aclrtResetDeviceForce与aclFinalize退出。运行方式详见 README.md# ${install_root} 替换为 CANN 安装根目录默认安装在 /usr/local/Ascend 目录 source ${install_root}/cann/set_env.sh export ASCEND_INSTALL_PATH${install_root}/cann bash run.sh典型输出[INFO] Dataset size: 1 [INFO] Tensor type..., data type..., bytes16, dims(2, 2), firstValue1.000 [INFO] Channel size after send: 1 [INFO] Dataset size: 1 [INFO] Tensor type..., data type..., bytes16, dims(2, 2), firstValue1.000 [INFO] Channel size after receive: 0 [INFO] Run the simple_channel sample successfully.若当前运行环境未启用队列式 TDT Channel 能力acltdtCreateChannelWithCapacity会返回nullptr样例打印告警后正常结束——这也再次印证了队列式通道能力取决于产品与构建形态的结论。8.2 示例二1_channel_capacity —— 容量压力测试该样例见 main.cpp演示容量上限与通道满错误处理通道容量固定为 2连续以timeout0非阻塞发送三个 Dataset当队列被占满时acltdtSendTensor立即返回ACL_ERROR_RT_QUEUE_FULL样例据此打印容量压力告警而不是卡死同时演示了acltdtGetSliceInfoFromItem与acltdtGetDatasetName的调用方式以及acltdtCleanChannel/acltdtStopChannel/acltdtDestroyChannel的清理顺序。这个样例恰好对应本文第四章 timeout 语义中0非阻塞的典型用法通道满时直接返回错误由用户自行设定重试间隔或采取降级策略。九、使用建议与注意事项接口配对使用通道创建后释放顺序务必是acltdtStopChannel→acltdtDestroyChannelacltdtDestroyChannel只能销毁由acltdtCreateChannel/acltdtCreateChannelWithCapacity创建的句柄不能混用。超时语义差异TDT 进程路径acltdtCreateChannel创建的通道下acltdtSendTensor/acltdtReceiveTensor的 timeout 只能为-1而队列式通道acltdtCreateChannelWithCapacity支持 -1 / 0 / 正数三种语义正数超时存在约一个操作系统时间片的偏差CPU 高负载下仍可能有波动。通道命名规范若通道用于接收数据通道名建议以TF_RECEIVE_开头这样句柄会识别出recvName在 TDT 进程路径下才能正确执行接收与停止唤醒详见 tensor_data_transfer.h。Dataset 内存类型一致同一个 Dataset 内的 DataItem 数据地址必须全部来自 Host 侧或全部来自 Device 侧混合使用会返回ACL_ERROR_INVALID_PARAM。接收缓冲复用acltdtReceiveTensor会在 Dataset 内按 1MB/10MB/100MB/500MB 档位缓存 Host 缓冲高频接收相同量级数据时可显著降低内存申请开销如果数据集大小波动较大可关注档位机制以预估内存峰值。产品支持差异acltdtCreateChannel目前仅 Atlas 训练系列产品昇腾虚拟化实例场景支持acltdtCreateChannelWithCapacity等其余接口在 Ascend 950PR/DT、Atlas A3、Atlas A2、Atlas 训练系列产品上支持。编码时建议按产品能力做条件编译或运行时探测。十、总结TDT 数据传输接口是 CANN Runtime 中 Host-Device 间 Tensor 数据通道的标准入口。本文从接口契约、参数语义、产品支持矩阵到源码实现完整覆盖了通道创建acltdtCreateChannel/acltdtCreateChannelWithCapacity、收发acltdtSendTensor/acltdtReceiveTensor、生命周期管理acltdtStopChannel/acltdtDestroyChannel/acltdtCleanChannel、状态查询acltdtQueryChannelSize与分片处理acltdtGetSliceInfoFromItem九大接口并结合 src/acl/acl_tdt_channel/tensor_data_transfer.cpp、include/external/acl/acl_tdt.h 与 example/2_advanced_features/tdt_channel 示例给出了可验证的底层依据。开发者可在此基础上直接构建可靠的 Tensor 数据传输链路并在遇到通道满/通道空等典型错误时依据 timeout 语义与错误码快速定位。【免费下载链接】runtime本项目提供CANN运行时组件和维测功能组件。项目地址: https://gitcode.com/cann/runtime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表