LCOV - code coverage report
Current view: top level - legacy/ascend910/platform/remote_access - transport_remote_access.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 202 0
Test Date: 2026-08-04 10:52:23 Functions: 0.0 % 15 0

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #include "transport_remote_access.h"
      12              : #include "externalinput_pub.h"
      13              : 
      14              : namespace hccl {
      15              : using namespace std;
      16              : std::array<DeviceMem, MAX_MODULE_DEVICE_NUM> TransportRemoteAccess::notifyValueMem_;
      17              : std::array<std::mutex, MAX_MODULE_DEVICE_NUM> TransportRemoteAccess::notifyValueMutex_;
      18              : std::array<Referenced, MAX_MODULE_DEVICE_NUM> TransportRemoteAccess::instanceRef_; // 实例计数,用于释放静态资源
      19            0 : TransportRemoteAccess::TransportRemoteAccess(const std::string tag, const HcclDispatcher dispatcher,
      20              :     const std::unique_ptr<NotifyPool> &notifyPool,
      21            0 :     const RemoteAccessPara &remoteAccessPara, const std::vector<MemRegisterAddr> &memRegistInfos, s32 deviceLogicId)
      22            0 :     : dispatcher_(dispatcher), notifyPool_(notifyPool), MemRegistInfos_(memRegistInfos),
      23            0 :       RemoteAccessPara_(remoteAccessPara), handle_(nullptr), ackNotify_(nullptr),
      24            0 :       access_(RA_ACCESS_LOCAL_WRITE | RA_ACCESS_REMOTE_WRITE | RA_ACCESS_REMOTE_READ),
      25            0 :       notifySize_(NOTIFY_BUFFER_SIZE), tag_(tag), timeout_(HCCL_LINK_TIME_OUT_S), deviceLogicId_(deviceLogicId)
      26              : {
      27            0 :     instanceRef_[deviceLogicId_].Ref();
      28            0 : }
      29              : 
      30            0 : TransportRemoteAccess::~TransportRemoteAccess()
      31              : {
      32            0 :     HCCL_DEBUG("~TransportRemoteAccess Enter!");
      33              :     HcclResult ret;
      34            0 :     struct MrInfoT mrInfo = {nullptr};
      35              :     /* 销毁本端mr */
      36            0 :     for (u32 idx = 0; idx < localRegMem_.size(); idx++) {
      37            0 :         mrInfo.addr = localRegMem_[idx];
      38            0 :         ret = HrtRaMrDereg(handle_, &mrInfo);
      39            0 :         if (ret != HCCL_SUCCESS) {
      40            0 :             HCCL_WARNING("errNo[0x%016llx] in TransportRemoteAccess deconstruct, mr dereg failed. ",
      41              :                 HCCL_ERROR_CODE(ret));
      42              :         }
      43              :     }
      44              : 
      45            0 :     ackNotify_ = nullptr;
      46            0 :     if (handle_ != nullptr) {
      47            0 :         ret = HrtRaQpDestroy(handle_);
      48            0 :         if (ret != HCCL_SUCCESS) {
      49            0 :             HCCL_WARNING("errNo[0x%016llx] in TransportRemoteAccess deconstruct, qp destroy failed. ",
      50              :                 HCCL_ERROR_CODE(ret));
      51              :         }
      52              :     }
      53            0 :     if (instanceRef_[deviceLogicId_].Unref() == 0) {
      54            0 :         std::unique_lock<std::mutex> lock(notifyValueMutex_[deviceLogicId_]);
      55            0 :         notifyValueMem_[deviceLogicId_].free();
      56            0 :     }
      57            0 :     HCCL_DEBUG("~TransportRemoteAccess Success!");
      58            0 : }
      59            0 : HcclResult TransportRemoteAccess::Init()
      60              : {
      61            0 :     HCCL_DEBUG("TransportRemoteAccess Init start");
      62              :     // 创建QP操作句柄
      63            0 :     CHK_RET(CreateQp());
      64              :     // 本端host/device内存地址注册
      65            0 :     CHK_RET(MrRegister());
      66              :     // notify注册,用于rdma消息同步
      67            0 :     CHK_RET(NotifyRegister());
      68            0 :     CHK_RET(ConnectQp());
      69              : 
      70            0 :     HCCL_DEBUG("TransportRemoteAccess Init end");
      71            0 :     return HCCL_SUCCESS;
      72              : }
      73              : 
      74            0 : HcclResult TransportRemoteAccess::CreateQp()
      75              : {
      76              :     // 创建qp handle, mode:普通qp
      77            0 :     HcclResult ret = HrtRaQpCreate(RemoteAccessPara_.nicRdmaHandle, QP_FLAG_RC, NORMAL_QP_MODE, handle_);
      78            0 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[Create][Qp]create qp mode failed, handle is null, "\
      79              :         "localRank[%u], qpMode[%d]", RemoteAccessPara_.localRank, NORMAL_QP_MODE), HCCL_E_ROCE_CONNECT);
      80            0 :     CHK_RET(SetQpAttrQos(handle_));
      81              :     // 配置RDMA Timeout时间
      82            0 :     CHK_RET(SetQpAttrTimeOut(handle_));
      83              :     // 配置RDMA Retry Cnt重传次数
      84            0 :     CHK_RET(SetQpAttrRetryCnt(handle_));
      85            0 :     return HCCL_SUCCESS;
      86              : }
      87              : 
      88            0 : HcclResult TransportRemoteAccess::NotifyRegister()
      89              : {
      90              :     // notify内存注册
      91            0 :     CHK_RET(SetLocalNotify());
      92              :     // 获取对端notify
      93            0 :     CHK_RET(GetRemoteNotifyInfo());
      94            0 :     return HCCL_SUCCESS;
      95              : }
      96              : 
      97            0 : HcclResult TransportRemoteAccess::MrRegister()
      98              : {
      99            0 :     void* memPtr = nullptr;
     100            0 :     if (MemRegistInfos_.size() == 0) {
     101            0 :         HCCL_ERROR("[Register][Mr]local mem info to register is empty!");
     102            0 :         return HCCL_E_PARA;
     103              :     }
     104            0 :     struct MrInfoT mrInfo = {nullptr};
     105            0 :     mrInfo.access = access_;
     106            0 :     for (size_t idx = 0; idx < MemRegistInfos_.size(); idx++) {
     107            0 :         memPtr = reinterpret_cast<void *>(static_cast<uintptr_t>(MemRegistInfos_[idx].addr));
     108            0 :         mrInfo.addr = memPtr;
     109            0 :         mrInfo.size = MemRegistInfos_[idx].length;
     110              : 
     111            0 :         CHK_RET(HrtRaMrReg(handle_, &mrInfo));
     112            0 :         localRegMem_.push_back(memPtr);
     113              :     }
     114            0 :     return HCCL_SUCCESS;
     115              : }
     116              : 
     117            0 : HcclResult TransportRemoteAccess::SetLocalNotify()
     118              : {
     119              :     // 申请ack notify,并发送至对端
     120            0 :     CHK_RET(CreateNotify());
     121              :     // 注册notify 内存信息
     122            0 :     CHK_RET(CreateNotifyValueBuffer());
     123            0 :     return HCCL_SUCCESS;
     124              : }
     125              : 
     126            0 : HcclResult TransportRemoteAccess::CreateNotify()
     127              : {
     128            0 :     u64 offset = 0;
     129            0 :     u64 notifyBaseVa = 0;  // notify寄存器虚拟地址
     130            0 :     u64 notifyTotalSize = 0;
     131              : 
     132              :     /* 申请Notify Group ID */
     133            0 :     RemoteRankInfo info(deviceLogicId_, RemoteAccessPara_.remoteRank);
     134            0 :     CHK_RET(SalGetBareTgid(&info.remotePid)); // 当前进程id
     135            0 :     CHK_RET(notifyPool_->Alloc(tag_, info, ackNotify_));
     136              :     // 设置remote id
     137            0 :     s64 recvId = 0xFFFFFFFF00000000 | (static_cast<s64>(info.remotePid) & 0xFFFFFFFF);
     138            0 :     CHK_RET(ackNotify_->Grant(recvId));
     139              : 
     140              :     /* 获取notify寄存器虚拟基地址、大小, 物理地址回传值为空 */
     141            0 :     CHK_RET(HrtRaGetNotifyBaseAddr(RemoteAccessPara_.nicRdmaHandle, &notifyBaseVa, &notifyTotalSize));
     142              : 
     143              :     /* 获取notify虚拟地址 */
     144            0 :     CHK_RET(ackNotify_->GetNotifyOffset(offset));
     145              : 
     146              :     // notify寄存器的虚拟地址与物理地址偏移相同,所以虚拟地址为虚拟基地址加偏移
     147            0 :     u64 notifyVa = notifyBaseVa + offset;
     148              : 
     149            0 :     HCCL_INFO(
     150              :         "notifyBaseVa=0x%llx, notifyTotalSize=0x%x, offset=0x%llx, notifyVa=0x%llx ",
     151              :         notifyBaseVa, notifyTotalSize, offset, notifyVa);
     152              : 
     153              :     /* notify地址注册为mr, 在roce驱动中注册 */
     154            0 :     ackNotifyMsg_.mrRegFlag = 0; // mem注册给网卡标志位
     155            0 :     ackNotifyMsg_.addr = reinterpret_cast<void *>(static_cast<uintptr_t>(notifyVa));  // 本端notify地址交换给对端
     156            0 :     ackNotifyMsg_.len = notifySize_;
     157            0 :     ackNotifyMsg_.offset = offset;
     158              : 
     159            0 :     return HCCL_SUCCESS;
     160              : }
     161              : 
     162            0 : HcclResult TransportRemoteAccess::GetRemoteNotifyInfo()
     163              : {
     164            0 :     NotifyMsg mrMsg;
     165            0 :     s32 sRet = memset_s(&mrMsg, sizeof(NotifyMsg), 0, sizeof(NotifyMsg));
     166            0 :     CHK_PRT_RET(sRet != EOK, HCCL_ERROR("[Get][NotifyInfo]errNo[0x%016llx]get remote addr, memory set 0 failed. "\
     167              :         "params: destMaxSize[%zu], count[%zu]", HCCL_ERROR_CODE(HCCL_E_MEMORY), \
     168              :         sizeof(NotifyMsg), sizeof(NotifyMsg)), HCCL_E_MEMORY);
     169              : 
     170            0 :     CHK_RET(hrtRaSocketBlockRecv(RemoteAccessPara_.socketFdhandle, &mrMsg, sizeof(NotifyMsg)));
     171            0 :     sRet = memcpy_s(&remoteNotifyDataMsg_, sizeof(NotifyMsg), &mrMsg, sizeof(NotifyMsg));
     172            0 :     CHK_PRT_RET(sRet != EOK, HCCL_ERROR(
     173              :         "[Get][NotifyInfo]errNo[0x%016llx] In TransportRemoteAccess get remote addr, memcpy failed. "\
     174              :         "errorno[%d], params:destMaxSize[%zu],count[%zu]", HCCL_ERROR_CODE(HCCL_E_MEMORY),
     175              :         sRet, sizeof(NotifyMsg), sizeof(NotifyMsg)), HCCL_E_MEMORY);
     176            0 :     HCCL_INFO("recv success:len=%llu", mrMsg.len);
     177              : 
     178            0 :     return HCCL_SUCCESS;
     179              : }
     180              : 
     181            0 : HcclResult TransportRemoteAccess::CreateNotifyValueBuffer()
     182              : {
     183            0 :     std::unique_lock<std::mutex> lock(notifyValueMutex_[deviceLogicId_]);
     184            0 :     if (notifyValueMem_[deviceLogicId_].ptr() == nullptr) {
     185            0 :         u64 notifyVaule = 1; // notify值写1表示record
     186            0 :         CHK_RET(DeviceMem::alloc(notifyValueMem_[deviceLogicId_], notifyValueSize_));
     187            0 :         HCCL_DEBUG("create notify value size[%u]", notifySize_);
     188              : 
     189            0 :         CHK_RET(hrtMemSyncCopy(notifyValueMem_[deviceLogicId_].ptr(), notifyValueMem_[deviceLogicId_].size(),
     190              :             &notifyVaule, notifySize_, HcclRtMemcpyKind::HCCL_RT_MEMCPY_KIND_HOST_TO_DEVICE));
     191              :     }
     192            0 :     lock.unlock();
     193            0 :     struct MrInfoT mrInfo = {nullptr};
     194            0 :     mrInfo.addr = notifyValueMem_[deviceLogicId_].ptr();
     195            0 :     mrInfo.size = notifySize_;
     196            0 :     mrInfo.access = access_;
     197            0 :     CHK_RET(HrtRaMrReg(handle_, &mrInfo));
     198              :     // 将notify buffer地址保存
     199            0 :     localRegMem_.push_back(notifyValueMem_[deviceLogicId_].ptr());
     200            0 :     NotifyMsg msg = {};
     201            0 :     msg.mrRegFlag = REG_VALID;
     202            0 :     msg.addr = notifyValueMem_[deviceLogicId_].ptr();
     203            0 :     msg.len = notifySize_;
     204              : 
     205              :     /* 发送mem消息给对端 */
     206            0 :     HcclResult ret = hrtRaSocketBlockSend(RemoteAccessPara_.socketFdhandle, &msg, sizeof(NotifyMsg));
     207            0 :     if (ret != HCCL_SUCCESS) {  // 发送成功字节数与发送字节数不等,发送失败
     208            0 :         HCCL_ERROR("[Create][NotifyValueBuffer]send=%zu", sizeof(NotifyMsg));
     209            0 :         return HCCL_E_INTERNAL;
     210              :     }
     211              : 
     212            0 :     return HCCL_SUCCESS;
     213            0 : }
     214            0 : HcclResult TransportRemoteAccess::RemoteRead(const std::vector<HcomRemoteAccessAddrInfo>& addrInfos, Stream &stream)
     215              : {
     216            0 :     CHK_SMART_PTR_NULL(stream);
     217            0 :     HCCL_INFO("TransportRemoteAccess RemoteRead begin");
     218            0 :     CHK_RET(RdmaDataTransport(addrInfos, RDMA_OP_READ));
     219              : 
     220              :     // 读取远端notify buffer,用于notify同步
     221            0 :     CHK_RET(ReadRemoteNotifyBuffer());
     222              : 
     223              :     // 等待TS把任务处理完成
     224            0 :     CHK_RET(LocalIpcNotify::Wait(stream, const_cast<HcclDispatcher>(dispatcher_), ackNotify_, INVALID_VALUE_STAGE,
     225              :         NOTIFY_INVALID_WAIT_TIME, RemoteAccessPara_.localRank, RemoteAccessPara_.remoteRank));
     226              : 
     227            0 :     HCCL_INFO("TransportRemoteAccess RemoteRead end");
     228            0 :     return HCCL_SUCCESS;
     229              : }
     230              : 
     231            0 : HcclResult TransportRemoteAccess::RemoteWrite(const std::vector<HcomRemoteAccessAddrInfo>& addrInfos, Stream &stream)
     232              : {
     233            0 :     CHK_SMART_PTR_NULL(stream);
     234            0 :     HCCL_RUN_INFO("TransportRemoteAccess RemoteWrite begin, addressNum[%u]", addrInfos.size());
     235            0 :     CHK_RET(RdmaDataTransport(addrInfos, RDMA_OP_WRITE));
     236              :     // 读取远端notify buffer,用于notify同步
     237            0 :     CHK_RET(ReadRemoteNotifyBuffer());
     238              :     // 等待TS把任务处理完成
     239            0 :     CHK_RET(LocalIpcNotify::Wait(stream, const_cast<HcclDispatcher>(dispatcher_), ackNotify_, INVALID_VALUE_STAGE,
     240              :         NOTIFY_INVALID_WAIT_TIME, RemoteAccessPara_.localRank, RemoteAccessPara_.remoteRank));
     241              : 
     242            0 :     return HCCL_SUCCESS;
     243              : }
     244              : 
     245            0 : HcclResult TransportRemoteAccess::RdmaDataTransport(const std::vector<HcomRemoteAccessAddrInfo>& addrInfos, s32 rdmaOp)
     246              : {
     247            0 :     if ((rdmaOp != RDMA_OP_WRITE) && (rdmaOp != RDMA_OP_READ)) {
     248            0 :         HCCL_ERROR("[Transport][RdmaData]invalid rdma op type, op:[%d]", rdmaOp);
     249            0 :         return HCCL_E_PARA;
     250              :     }
     251            0 :     CHK_PRT_RET(addrInfos.empty(), HCCL_ERROR("[Transport][RdmaData]addrInfos is empty!"), HCCL_E_PARA);
     252            0 :     u32 addressNum = addrInfos.size();
     253              :     // 构造wr信息
     254            0 :     std::vector<struct SendWrlistDataExt> wrVec(addressNum);
     255            0 :     std::vector<struct SendWrRsp> opRspVec(addressNum);
     256            0 :     struct SendWrlistDataExt *wr = wrVec.data();
     257            0 :     struct SendWrRsp *opRsp = opRspVec.data();
     258            0 :     struct SgList list = {0};
     259            0 :     u64 length = addrInfos[0].length;
     260              : 
     261            0 :     HCCL_RUN_INFO("RdmaDataTransport begin, addressNum[%u], length[%u]", addressNum, length);
     262            0 :     for (size_t idx = 0; idx < addrInfos.size(); idx++) {
     263            0 :         list.addr = static_cast<u64>(static_cast<uintptr_t>(addrInfos[idx].localAddr));
     264            0 :         list.len = addrInfos[idx].length;
     265              : 
     266            0 :         wr[idx].memList = list;
     267            0 :         wr[idx].dstAddr = static_cast<u64>(static_cast<uintptr_t>(addrInfos[idx].remoteAddr));
     268            0 :         wr[idx].op = rdmaOp; /* RDMA_WRITE: 0  RDMA_READ: 4 */
     269            0 :         wr[idx].sendFlags = RA_SEND_SIGNALED;
     270              :     }
     271            0 :     u32 nowIdex = 0;
     272            0 :     u32 singleCompleteNum = 0;
     273            0 :     u32 sendNum = 0;
     274              :     HcclResult ret;
     275            0 :     u32 tryCount = 0;
     276            0 :     while (nowIdex < addressNum) {
     277            0 :         sendNum = addressNum - nowIdex;
     278            0 :         ret = HrtRaSendWrlistExt(handle_, wr, opRsp, sendNum, &singleCompleteNum);
     279            0 :         if (ret == HCCL_SUCCESS) {
     280            0 :             HCCL_INFO("dlRaSendWrlist success singleCompleteNum[%u], addressNum[%u]", singleCompleteNum, addressNum);
     281            0 :             return HCCL_SUCCESS;
     282            0 :         } else if (ret == ENOENT) { // 未完成发送,需重试
     283            0 :             nowIdex += singleCompleteNum;
     284            0 :             wr += singleCompleteNum;
     285            0 :             opRsp += singleCompleteNum;
     286            0 :             tryCount++;
     287            0 :             CHK_PRT_RET(tryCount > SEND_WRLIST_MAX_COUNT,
     288              :                 HCCL_ERROR("[Transport][RdmaData]dlRaSendWrlist count beyond maxnum[%u], completenum[%u]",
     289              :                     SEND_WRLIST_MAX_COUNT, nowIdex), HCCL_E_NETWORK);
     290            0 :             continue;
     291              :         } else {
     292            0 :             HCCL_ERROR("[Transport][RdmaData]In RdmaDataTransport, hrtRaSendWrlist failed. op[%d], ret[%d]",
     293              :                 rdmaOp, ret);
     294            0 :             return HCCL_E_NETWORK;
     295              :         }
     296              :     }
     297              : 
     298            0 :     return HCCL_SUCCESS;
     299            0 : }
     300              : 
     301            0 : HcclResult TransportRemoteAccess::ReadRemoteNotifyBuffer()
     302              : {
     303            0 :     HCCL_INFO("In TransportRemoteAccess ReadRemoteNotifyBuffer begin");
     304            0 :     struct SgList list = {0};
     305            0 :     struct SendWr wr = {nullptr};
     306              : 
     307              :     // 构造wr信息
     308            0 :     list.addr = static_cast<u64>(reinterpret_cast<uintptr_t>(ackNotifyMsg_.addr));
     309            0 :     list.len = remoteNotifyDataMsg_.len;
     310              : 
     311            0 :     wr.bufList = &list;
     312            0 :     wr.bufNum = 1; /* 此处list只有一个,设置为1 */
     313            0 :     wr.dstAddr = static_cast<u64>(reinterpret_cast<uintptr_t>(remoteNotifyDataMsg_.addr));
     314            0 :     wr.op = RDMA_OP_READ; /* RDMA_WRITE: 0 */
     315            0 :     wr.sendFlag = RA_SEND_SIGNALED;
     316              : 
     317            0 :     struct SendWrRsp opRsp = {0};
     318            0 :     CHK_RET(HrtRaSendWr(handle_, &wr, &opRsp));
     319            0 :     HCCL_INFO("In TransportRemoteAccess ReadRemoteNotifyBuffer end");
     320            0 :     return HCCL_SUCCESS;
     321              : }
     322              : 
     323            0 : HcclResult TransportRemoteAccess::ConnectQp()
     324              : {
     325              :     // QP建链
     326            0 :     CHK_RET(HrtRaQpConnectAsync(handle_, RemoteAccessPara_.socketFdhandle));
     327              : 
     328            0 :     HCCL_INFO("TransportRemoteAccess ConnectQp LocalRank[%u] "\
     329              :         "RemoteRank[%u] LocalIp[%s]", RemoteAccessPara_.localRank,
     330              :         RemoteAccessPara_.remoteRank, RemoteAccessPara_.localIp.GetReadableAddress());
     331              : 
     332              :     // 查询QP建链是否成功
     333            0 :     s32 qpStatus = 0;
     334            0 :     auto startTime = std::chrono::steady_clock::now();
     335            0 :     HCCL_INFO("In link ibv, waiting for qp status ready...");
     336              :     while (true) {
     337            0 :         if ((std::chrono::steady_clock::now() - startTime) >= timeout_) {
     338            0 :             HCCL_ERROR("[Connect][Qp]get qp status timeout_=%lld s, qp_status=%d", timeout_, qpStatus);
     339            0 :             return HCCL_E_TIMEOUT;
     340              :         }
     341              : 
     342            0 :         s32 raRet = hrtGetRaQpStatus(handle_, &qpStatus);
     343            0 :         if ((!raRet) && (qpStatus == 1)) { // 为1时,qp 建链成功
     344            0 :             HCCL_INFO("GetRaQpStatus Success!");
     345            0 :             break;
     346              :         } else {
     347              :             // qp建链需要时间,获取qp状态直至超时
     348            0 :             SaluSleep(WAIT_US_COUNT);
     349              :         }
     350            0 :     }
     351            0 :     return HCCL_SUCCESS;
     352              : }
     353              : }
        

Generated by: LCOV version 2.0-1