LCOV - code coverage report
Current view: top level - base_comm/resources/endpoint_pairs/channels/host - host_cpu_roce_channel.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 75.4 % 1057 797
Test Date: 2026-08-25 19:18:03 Functions: 87.5 % 64 56

            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 "host_cpu_roce_channel.h"
      12              : #include "endpoint.h"
      13              : #include "dpu_notify/dpu_notify_manager.h"
      14              : #include "hcomm_res.h"
      15              : #include "hcomm_c_adpt.h"
      16              : #include "exception_handler.h"
      17              : #include "cpu_roce_endpoint.h"
      18              : #include "adapter_error_manager_pub.h"
      19              : 
      20              : // Orion
      21              : #include "orion_adapter_hccp.h"
      22              : #include "orion_adpt_utils.h"
      23              : #include "exchange_rdma_buffer_dto.h"
      24              : #include "rdma_handle_manager.h"
      25              : #include "exchange_rdma_conn_dto.h"
      26              : #include "sal.h"
      27              : #include "adapter_hccp.h"
      28              : #include "binary_stream.h"
      29              : #include "../../../../../legacy/ascend910/platform/resource/notify/notify_pool_impl.h"
      30              : #include "../../../../../base_comm/resources/hccp/inc/network/hccp_common.h"
      31              : #include "dlprof_function.h"
      32              : #include "user_remote_mem_getter.h"
      33              : #include "env_config/env_config_v2.h"
      34              : 
      35              : namespace hcomm {
      36              : constexpr u32 MEM_BLOCK_SIZE = 128;
      37              : constexpr uint16_t DEFAULT_LISTENING_PORT = 60001;
      38              : constexpr u32 SEND_RQE_COUNT = 16;
      39              : constexpr u32 DEFAULT_NOTIFY_WAIT_TIMEOUT_S = 30; // NotifyWait超时默认值(单位:秒)
      40              : 
      41          122 : HostCpuRoceChannel::HostCpuRoceChannel(EndpointHandle endpointHandle, HcommChannelDesc channelDesc)
      42          122 :     : endpointHandle_(endpointHandle),
      43          122 :       channelDesc_(channelDesc)
      44              : {
      45          122 :     if (channelDesc_.roceAttr.srcPortList != nullptr && channelDesc_.roceAttr.queueNum > 0) {
      46            0 :         srcPortBuf_.assign(
      47            0 :             channelDesc_.roceAttr.srcPortList, channelDesc_.roceAttr.srcPortList + channelDesc_.roceAttr.queueNum);
      48            0 :         channelDesc_.roceAttr.srcPortList = srcPortBuf_.data();
      49              :     }
      50          122 : }
      51              : 
      52          193 : HostCpuRoceChannel::~HostCpuRoceChannel()
      53              : {
      54              :     HcclResult ret;
      55              : 
      56          122 :     if (isHybridMode_ && connections_.size() != 0) {
      57            1 :         auto qpInfo = connections_[0]->GetQpInfo();
      58            1 :         struct MrInfoT mrInfo = {};
      59              : 
      60           17 :         for (uint32_t i = 0; i < hccl::MEM_TYPE_RESERVED; i++) {
      61           16 :             if (localMemMsg_[i].addr == nullptr) {
      62           16 :                 continue;
      63              :             }
      64              : 
      65            0 :             mrInfo.addr = localMemMsg_[i].addr;
      66            0 :             ret = HrtRaMrDereg(qpInfo.qpHandle, &mrInfo);
      67            0 :             if (ret != HCCL_SUCCESS) {
      68            0 :                 HCCL_INFO(
      69              :                     "[~HostCpuRoceChannel] Dereg mem, ret=%d, type=%d, addr:%p, lkey:%d, size:%llu, access:%d", ret, i,
      70              :                     mrInfo.addr, mrInfo.lkey, mrInfo.size, mrInfo.access);
      71              :             }
      72              : 
      73            0 :             if (localMemMsg_[i].notifyId != INVALID_DPU_NOTIFY_ID) {
      74            0 :                 delete[] (int8_t*)localMemMsg_[i].addr;
      75              :             }
      76            0 :             localMemMsg_[i].addr = nullptr;
      77              : 
      78            0 :             HCCL_INFO(
      79              :                 "[~HostCpuRoceChannel] Dereg mem, type=%d, addr:%p, lkey:%d, size:%llu, access:%d", i, mrInfo.addr,
      80              :                 mrInfo.lkey, mrInfo.size, mrInfo.access);
      81              :         }
      82              :     }
      83              : 
      84          122 :     ret = DpuNotifyManager::GetInstance().FreeNotifyIds(notifyNum_, localDpuNotifyIds_);
      85          122 :     if (ret != HCCL_SUCCESS) {
      86            5 :         HCCL_ERROR("[HostCpuRoceChannel::~HostCpuRoceChannel] exception occurred, HcclResult=[%d]", ret);
      87              :     }
      88              : 
      89          122 :     if (channelDesc_.socket == nullptr && socket_ != nullptr) {
      90            1 :         SocketMgr::GetInstance(devicePhyId_).PutSocket(socketConfig_, socket_);
      91            1 :         socket_ = nullptr;
      92              :     }
      93          193 : }
      94              : 
      95           64 : HcclResult HostCpuRoceChannel::ParseInputParam()
      96              : {
      97              :     // 1. 从 endpointHandle_,获得 localEp_ 和 rdmaHandle_
      98           64 :     CHK_PTR_NULL(endpointHandle_);
      99           64 :     HCCL_INFO(
     100              :         "[HostCpuRoceChannel][%s] Start. endpointHandle[0x%llx]", __func__,
     101              :         reinterpret_cast<uint64_t>(endpointHandle_));
     102           64 :     Endpoint* localEpPtr = reinterpret_cast<Endpoint*>(endpointHandle_);
     103           64 :     localEp_ = localEpPtr->GetEndpointDesc();
     104           64 :     rdmaHandle_ = localEpPtr->GetRdmaHandle();
     105           64 :     CHK_PTR_NULL(rdmaHandle_);
     106              : 
     107              :     // 2. 从 channelDesc_,获得 remoteEp_, socket_ 和 notifyNum
     108           64 :     remoteEp_ = channelDesc_.remoteEndpoint;
     109           64 :     socket_ = reinterpret_cast<Hccl::Socket*>(channelDesc_.socket);
     110              :     // If HIXL, socket is nullptr for now, will be built later.
     111           64 :     notifyNum_ = channelDesc_.notifyNum;
     112              : 
     113           64 :     if (channelDesc_.exchangeAllMems) { // true for HIXL, false for HCCL
     114              :         // 3. Get memHandles from endpoint
     115            1 :         HCCL_INFO("[HostCpuRoceChannel][%s] exchangeAllMems == True. Get memHandles from endpoint.", __func__);
     116            1 :         std::shared_ptr<Hccl::LocalRdmaRmaBuffer>* memHandles = nullptr;
     117            1 :         uint32_t memHandleNum = 0;
     118            1 :         CHK_RET(static_cast<HcclResult>(
     119              :             HcommMemGetAllMemHandles(endpointHandle_, reinterpret_cast<void**>(&memHandles), &memHandleNum)));
     120            1 :         HCCL_INFO("[HostCpuRoceChannel][%s] Got memHandleNum[%u].", __func__, memHandleNum);
     121            1 :         for (uint32_t i = 0; i < memHandleNum; ++i) {
     122            0 :             std::shared_ptr<Hccl::LocalRdmaRmaBuffer>& localRdmaBuffer = memHandles[i];
     123            0 :             CHK_SMART_PTR_NULL(localRdmaBuffer);
     124            0 :             Hccl::Buffer* buf = localRdmaBuffer->GetBuf();
     125            0 :             CHK_PTR_NULL(buf);
     126            0 :             HCCL_INFO(
     127              :                 "[HostCpuRoceChannel][%s] Got memHandle No.%u: addr[0x%llx], size[0x%llx], memType[%d], memInfo[%s].",
     128              :                 __func__, i, static_cast<unsigned long long>(localRdmaBuffer->GetAddr()),
     129              :                 static_cast<unsigned long long>(localRdmaBuffer->GetSize()), static_cast<int>(buf->GetMemType()),
     130              :                 buf->GetMemInfo().c_str());
     131            0 :             localRmaBuffers_.emplace_back(localRdmaBuffer.get());
     132              :         }
     133              :     } else {
     134              :         // 3. 从 channelDesc 的 memHandle,获得 bufs_
     135           63 :         HCCL_INFO("[HostCpuRoceChannel][%s] exchangeAllMems == false. Get memHandles from channelDesc.", __func__);
     136           63 :         CHK_PTR_NULL(channelDesc_.memHandles);
     137          124 :         for (uint32_t i = 0; i < channelDesc_.memHandleNum; ++i) {
     138           62 :             CHK_PTR_NULL(channelDesc_.memHandles[i]);
     139           62 :             auto* localRdmaBuffer = static_cast<Hccl::LocalRdmaRmaBuffer*>(channelDesc_.memHandles[i]);
     140           62 :             localRmaBuffers_.emplace_back(localRdmaBuffer);
     141              :         }
     142              :     }
     143              : 
     144           63 :     auto* localCpuRoceEpPtr = dynamic_cast<CpuRoceEndpoint*>(localEpPtr);
     145           63 :     if (localCpuRoceEpPtr == nullptr) {
     146            1 :         HCCL_ERROR("[HostCpuRoceChannel][%s] endpointHandle_ is not CpuRoceEndpoint.", __func__);
     147            1 :         return HCCL_E_INTERNAL;
     148              :     }
     149           62 :     CpuRoceEndpoint::Capabilities caps{};
     150           62 :     CHK_RET(localCpuRoceEpPtr->GetCapabilities(caps));
     151           62 :     maxMsgSize_ = caps.maxMsgSize;
     152           62 :     lbMax_ = caps.lbMax;
     153           62 :     constexpr uint64_t TWO_GB = 0x80000000ULL; // 2GB
     154           62 :     if (maxMsgSize_ > TWO_GB) {
     155            0 :         HCCL_RUN_WARNING(
     156              :             "[HostCpuRoceChannel][%s] maxMsgSize_[0x%llx] exceeds 2GB, value may be incorrect.", __func__, maxMsgSize_);
     157              :     }
     158           62 :     HCCL_INFO("[HostCpuRoceChannel][%s] maxMsgSize_[0x%llx].", __func__, maxMsgSize_);
     159              : 
     160           62 :     return HCCL_SUCCESS;
     161              : }
     162              : 
     163            0 : HcclResult HostCpuRoceChannel::StartListen()
     164              : {
     165            0 :     uint16_t port = channelDesc_.port;
     166            0 :     HCCL_INFO(
     167              :         "[HostCpuRoceChannel::%s] Start. EndpointHandle[0x%llx], port[%u]", __func__,
     168              :         reinterpret_cast<uint64_t>(endpointHandle_), port);
     169            0 :     if (port == 0) {
     170            0 :         port = DEFAULT_LISTENING_PORT;
     171            0 :         HCCL_INFO("[HostCpuRoceChannel::%s] channelDesc port is 0, use default port [%u]", __func__, port);
     172              :     }
     173            0 :     CHK_RET(static_cast<HcclResult>(HcommEndpointStartListen(endpointHandle_, port, nullptr)));
     174            0 :     HCCL_INFO("[HostCpuRoceChannel::%s] SUCCESS. port[%u].", __func__, port);
     175            0 :     return HCCL_SUCCESS;
     176              : }
     177              : 
     178           62 : HcclResult HostCpuRoceChannel::BuildSocket()
     179              : {
     180           62 :     if (socket_ != nullptr) {
     181           61 :         return HCCL_SUCCESS;
     182              :     }
     183            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] socket ptr is NULL, rebuild Socket", __func__);
     184              : 
     185            1 :     Hccl::LinkData linkData = BuildDefaultLinkData();
     186            1 :     CHK_RET(EndpointDescPairToLinkData(localEp_, remoteEp_, linkData));
     187            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] built linkData: %s", __func__, linkData.Describe().c_str());
     188            1 :     uint16_t port = channelDesc_.port;
     189            1 :     if (port == 0) {
     190            1 :         port = DEFAULT_LISTENING_PORT;
     191            1 :         HCCL_INFO("[HostCpuRoceChannel::%s] channelDesc port is 0, use default port [%u]", __func__, port);
     192              :     }
     193              :     std::string socketTag
     194            3 :         = (channelDesc_.channelName != nullptr) ? std::string(channelDesc_.channelName) : "AUTOMATIC_SOCKET_TAG";
     195              :     Hccl::SocketConfig socketConfig
     196            1 :         = (channelDesc_.role != HCOMM_SOCKET_ROLE_RESERVED) ?
     197            1 :               Hccl::SocketConfig(linkData, port, socketTag, channelDesc_.role == HCOMM_SOCKET_ROLE_SERVER) :
     198            1 :               Hccl::SocketConfig(linkData, port, socketTag);
     199            1 :     CHK_RET(SocketMgr::GetInstance(devicePhyId_).GetSocket(socketConfig, socket_));
     200            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] SUCCESS. port[%u].", __func__, port);
     201            1 :     return HCCL_SUCCESS;
     202            1 : }
     203              : 
     204           66 : HcclResult HostCpuRoceChannel::BuildConnection()
     205              : {
     206           66 :     u32 loopTimes = 0;
     207           66 :     if (lbMax_ > 0 && channelDesc_.roceAttr.queueNum == 1) { // 1825场景且默认qp数量
     208            0 :         loopTimes = lbMax_;
     209              :     } else {
     210           66 :         loopTimes = channelDesc_.roceAttr.queueNum;
     211              :     }
     212           81 :     for (u32 i = 0; i < loopTimes; i++) {
     213           15 :         std::unique_ptr<HostRdmaConnection> conn;
     214           15 :         EXCEPTION_CATCH(conn = std::make_unique<HostRdmaConnection>(socket_, rdmaHandle_), return HCCL_E_INTERNAL);
     215           15 :         CHK_PTR_NULL(conn);
     216           15 :         CHK_RET(conn->Init());
     217           15 :         Hccl::QpInfo& qpInfo = conn->GetQpInfo();
     218           15 :         if (lbMax_ > 0) {
     219            0 :             qpInfo.lbValue = i % lbMax_;
     220              :         }
     221           15 :         qpInfo.serviceLevel = channelDesc_.roceAttr.sl;
     222           15 :         qpInfo.trafficClass = channelDesc_.roceAttr.tc;
     223           15 :         qpInfo.retryCnt = channelDesc_.roceAttr.retryCnt;
     224           15 :         qpInfo.retryInterval = channelDesc_.roceAttr.retryInterval;
     225           15 :         qpInfo.udpSport = (!channelDesc_.exchangeAllMems && channelDesc_.roceAttr.srcPortList != nullptr) ?
     226            4 :                               static_cast<u32>(channelDesc_.roceAttr.srcPortList[i % channelDesc_.roceAttr.queueNum]) :
     227              :                               0;
     228           15 :         HCCL_INFO(
     229              :             "[HostCpuRoceChannel::BuildConnection] QpInfo[%u]: lbValue[%u], serviceLevel[%u], trafficClass[%u], "
     230              :             "retryCnt[%u], retryInterval[%u], udpSport[%u].",
     231              :             i, qpInfo.lbValue, qpInfo.serviceLevel, qpInfo.trafficClass, qpInfo.retryCnt, qpInfo.retryInterval,
     232              :             qpInfo.udpSport);
     233           15 :         connections_.emplace_back(std::move(conn));
     234           15 :     }
     235           66 :     connNum_ = connections_.size();
     236           66 :     wqeNums_.resize(connNum_, 0);
     237           66 :     HCCL_INFO("[HostCpuRoceChannel::BuildConnection] Success, Qp count = %u", connNum_);
     238           66 :     return HCCL_SUCCESS;
     239              : }
     240              : 
     241           62 : HcclResult HostCpuRoceChannel::BuildNotify()
     242              : {
     243           62 :     CHK_RET(DpuNotifyManager::GetInstance().AllocNotifyIds(notifyNum_, localDpuNotifyIds_));
     244           61 :     return HCCL_SUCCESS;
     245              : }
     246              : 
     247           61 : HcclResult HostCpuRoceChannel::BuildBuffer()
     248              : {
     249           61 :     bufferNum_ = localRmaBuffers_.size();
     250           61 :     return HCCL_SUCCESS;
     251              : }
     252              : 
     253           64 : HcclResult HostCpuRoceChannel::Init()
     254              : {
     255              :     s32 devLogicId;
     256           64 :     CHK_RET(hrtGetDevice(&devLogicId));
     257           64 :     CHK_RET(hrtGetDevicePhyIdByIndex(static_cast<u32>(devLogicId), devicePhyId_));
     258              : 
     259           64 :     CHK_RET(ParseInputParam());
     260              :     // true for HIXL, false for HCCL
     261           62 :     if (channelDesc_.exchangeAllMems && channelDesc_.role != HCOMM_SOCKET_ROLE_CLIENT) {
     262            0 :         CHK_RET(StartListen());
     263              :     }
     264           62 :     CHK_RET(BuildSocket());
     265           62 :     CHK_RET(BuildConnection());
     266           62 :     CHK_RET(BuildNotify());
     267           61 :     CHK_RET(BuildBuffer());
     268              : 
     269           61 :     return HCCL_SUCCESS;
     270              : }
     271              : 
     272              : // 当前AICPU和框架没有改为返回错误码形式,所有暂时使用该方法转换
     273          268 : ChannelStatus HostCpuRoceChannel::GetStatus()
     274              : {
     275          268 :     ChannelStatus status;
     276          268 :     HcclResult ret = GetStatus(status);
     277          268 :     if (ret != HCCL_SUCCESS && ret != HCCL_E_AGAIN) {
     278            8 :         HCCL_ERROR("[HostCpuRoceChannel::GetStatus] get status exception occurred, HcclResult=[%d]", ret);
     279            8 :         return ChannelStatus::FAILED;
     280              :     }
     281          260 :     return status;
     282              : }
     283              : 
     284          262 : HcclResult HostCpuRoceChannel::ProcessStatus()
     285              : {
     286          262 :     switch (channelStatus_) {
     287           48 :         case ChannelStatus::READY:
     288           48 :             return HCCL_SUCCESS;
     289            2 :         case ChannelStatus::SOCKET_TIMEOUT:
     290            2 :             HCCL_ERROR("[HostCpuRoceChannel::ProcessStatus] get socket timeout");
     291            2 :             return HCCL_E_ROCE_CONNECT;
     292          212 :         default:
     293          212 :             return HCCL_E_AGAIN;
     294              :     }
     295              : }
     296              : 
     297           48 : HcclResult HostCpuRoceChannel::SyncAfterModifyQp()
     298              : {
     299              :     EXCEPTION_HANDLE_BEGIN
     300              :     // 告知对端ModifyQp完成
     301           48 :     uint8_t sendFlag = 1;
     302           48 :     CHK_PRT_RET(
     303              :         !socket_->Send(reinterpret_cast<void*>(&sendFlag), sizeof(sendFlag)),
     304              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Send sendFlag failed", __func__), HCCL_E_NETWORK);
     305           48 :     HCCL_INFO(
     306              :         "[HostCpuRoceChannel::%s] Send sendFlag[%u] of data success. [%llu] bytes sent.", __func__, sendFlag,
     307              :         sizeof(sendFlag));
     308              : 
     309              :     // 等待对端ModifyQp完成
     310           48 :     uint8_t recvFlag = 0;
     311           48 :     CHK_PRT_RET(
     312              :         !socket_->Recv(reinterpret_cast<void*>(&recvFlag), sizeof(recvFlag)),
     313              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Recv recvFlag failed", __func__), HCCL_E_NETWORK);
     314           48 :     HCCL_INFO(
     315              :         "[HostCpuRoceChannel::%s] Receive recvFlag[%u] of data success. [%llu] bytes received.", __func__, recvFlag,
     316              :         sizeof(recvFlag));
     317            0 :     EXCEPTION_HANDLE_END
     318           48 :     return HCCL_SUCCESS;
     319              : }
     320              : 
     321          268 : HcclResult HostCpuRoceChannel::GetStatus(ChannelStatus& status)
     322              : {
     323          268 :     switch (rdmaStatus_) {
     324           56 :         case RdmaStatus::INIT:
     325              :             // 检查socket状态
     326           56 :             CHK_RET(CheckSocketStatus());
     327           56 :             break;
     328           55 :         case RdmaStatus::SOCKET_OK:
     329           55 :             CHK_RET(ExchangeCapability());
     330           54 :             rdmaStatus_ = RdmaStatus::CAP_EXCHANGED;
     331           54 :             break;
     332           55 :         case RdmaStatus::CAP_EXCHANGED:
     333              :             // 准备资源
     334           55 :             CHK_RET(CreateQp());
     335           53 :             rdmaStatus_ = RdmaStatus::QP_CREATED;
     336           53 :             break;
     337           52 :         case RdmaStatus::QP_CREATED:
     338              :             // 发送交换数据
     339           52 :             if (isHybridMode_) {
     340            1 :                 CHK_RET(ExchangeDataHybird());
     341              :             } else {
     342           51 :                 CHK_RET(ExchangeData());
     343              :             }
     344           51 :             rdmaStatus_ = RdmaStatus::DATA_EXCHANGE;
     345           51 :             break;
     346           50 :         case RdmaStatus::DATA_EXCHANGE:
     347           50 :             if (isHybridMode_) {
     348            1 :                 CHK_RET(ConnectSingleQpHybrid([]() -> bool {
     349              :                     return 0;
     350              :                 }));
     351              :             } else {
     352           49 :                 CHK_RET(ModifyQp());
     353              :             }
     354           48 :             rdmaStatus_ = RdmaStatus::QP_MODIFIED;
     355              :             // modify完就不需要再轮询状态了,直接向下走准备Rqe的流程。
     356              :             [[fallthrough]];
     357           48 :         case RdmaStatus::QP_MODIFIED:
     358           48 :             CHK_RET(SyncAfterModifyQp());
     359              :             // Prepare Rqes
     360           48 :             if (!isHybridMode_) {
     361          816 :                 for (uint32_t i = 0; i < SEND_RQE_COUNT; ++i) {
     362          768 :                     CHK_RET(IbvPostRecv());
     363              :                 }
     364              :             }
     365              :             [[fallthrough]];
     366              :         default:
     367           48 :             rdmaStatus_ = RdmaStatus::CONN_OK;
     368           48 :             channelStatus_ = ChannelStatus::READY;
     369              :     }
     370              : 
     371          262 :     status = channelStatus_;
     372          262 :     return ProcessStatus();
     373              : }
     374              : 
     375           56 : HcclResult HostCpuRoceChannel::CheckSocketStatus()
     376              : {
     377           56 :     CHK_PTR_NULL(socket_);
     378           56 :     HCCL_DEBUG("[HostCpuRoceChannel::CheckSocketStatus] socket GetStatus start");
     379           56 :     Hccl::SocketStatus socketStatus = socket_->GetStatus(); // socket状态机
     380           56 :     HCCL_DEBUG("[HostCpuRoceChannel::CheckSocketStatus] socket status = %s", socketStatus.Describe().c_str());
     381           56 :     if (socketStatus == Hccl::SocketStatus::OK) {
     382           54 :         rdmaStatus_ = RdmaStatus::SOCKET_OK;
     383           54 :         channelStatus_ = ChannelStatus::SOCKET_OK;
     384            2 :     } else if (socketStatus == Hccl::SocketStatus::TIMEOUT) {
     385            2 :         channelStatus_ = ChannelStatus::SOCKET_TIMEOUT;
     386              :     }
     387           56 :     return HCCL_SUCCESS;
     388              : }
     389              : 
     390              : // 准备资源(创建QP)
     391           55 : HcclResult HostCpuRoceChannel::CreateQp()
     392              : {
     393           59 :     for (auto& conn : connections_) {
     394            6 :         Hccl::CHECK_NULLPTR(
     395           12 :             conn, Hccl::StringFormat("[HostCpuRoceChannel::%s] failed, connection pointer is nullptr", __func__));
     396            6 :         HcclResult ret = conn->CreateQp();
     397            6 :         if (ret == HCCL_E_AGAIN) {
     398            2 :             return HCCL_SUCCESS;
     399              :         }
     400            6 :         if (ret != HCCL_SUCCESS) {
     401            2 :             return ret;
     402              :         }
     403              :     }
     404           53 :     HCCL_INFO("[HostCpuRoceChannel::IsResReady] all connections resources connected.");
     405           53 :     return HCCL_SUCCESS;
     406              : }
     407              : 
     408              : // 交换数据
     409            2 : HcclResult HostCpuRoceChannel::ExchangeData()
     410              : {
     411            2 :     HCCL_INFO(
     412              :         "[HostCpuRoceChannel::%s] Start to SendExchangeData, notifyNum=%u, bufferNum=%u, connNum=%u", __func__,
     413              :         notifyNum_, bufferNum_, connNum_);
     414              : 
     415              :     // 同步数据打包
     416            2 :     Hccl::BinaryStream binaryStream;
     417            2 :     NotifyVecPack(binaryStream);
     418            2 :     CHK_RET(BufferVecPack(binaryStream));
     419            2 :     CHK_RET(ConnVecPack(binaryStream));
     420              : 
     421            2 :     std::vector<char> sendData{};
     422            2 :     binaryStream.Dump(sendData);
     423            2 :     uint64_t sendSize = sendData.size();
     424            2 :     std::vector<char> recvData{};
     425            2 :     uint64_t recvSize = 0;
     426              : 
     427              :     EXCEPTION_HANDLE_BEGIN
     428              :     // 同步发送数据包尺寸
     429            2 :     CHK_PRT_RET(
     430              :         !socket_->Send(reinterpret_cast<void*>(&sendSize), sizeof(sendSize)),
     431              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Send sendSize failed", __func__), HCCL_E_NETWORK);
     432            2 :     HCCL_INFO(
     433              :         "[HostCpuRoceChannel::%s] Send size[%llu] of data success. [%llu] bytes sent.", __func__, sendSize,
     434              :         sizeof(sendSize));
     435              : 
     436              :     // 同步接收数据包尺寸
     437            2 :     CHK_PRT_RET(
     438              :         !socket_->Recv(reinterpret_cast<void*>(&recvSize), sizeof(recvSize)),
     439              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Recv recvSize failed", __func__), HCCL_E_NETWORK);
     440            2 :     HCCL_INFO(
     441              :         "[HostCpuRoceChannel::%s] Receive size[%llu] of data success. [%llu] bytes received.", __func__, recvSize,
     442              :         sizeof(recvSize));
     443              : 
     444              :     // 同步发送数据
     445            2 :     CHK_PRT_RET(
     446              :         !socket_->Send(reinterpret_cast<void*>(sendData.data()), sendSize),
     447              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Send exchange data failed", __func__), HCCL_E_NETWORK);
     448            2 :     HCCL_INFO("[HostCpuRoceChannel::%s] Send Exchange Data success. [%llu] bytes sent.", __func__, sendSize);
     449              : 
     450              :     // 同步接收数据
     451            2 :     HCCL_INFO("[HostCpuRoceChannel::%s] Start to Receive Exchange Data", __func__);
     452            2 :     recvData.resize(recvSize);
     453            2 :     CHK_PRT_RET(
     454              :         !socket_->Recv(reinterpret_cast<void*>(recvData.data()), recvSize),
     455              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Recv exchange data failed", __func__), HCCL_E_NETWORK);
     456            2 :     HCCL_INFO("[HostCpuRoceChannel::%s] Receive Exchange Data success. [%llu] bytes received.", __func__, recvSize);
     457            0 :     EXCEPTION_HANDLE_END
     458              : 
     459              :     // 同步数据解包
     460            2 :     Hccl::BinaryStream recvBinStream(recvData);
     461              :     // CHK_RET(HandshakeMsgUnpack(recvBinStream));
     462            2 :     CHK_RET(NotifyVecUnpack(recvBinStream));
     463            2 :     CHK_RET(RmtBufferVecUnpackProc(recvBinStream));
     464            2 :     CHK_RET(ConnVecUnpackProc(recvBinStream));
     465              : 
     466            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] Unpack exchange Data success.", __func__);
     467            1 :     return HCCL_SUCCESS;
     468            2 : }
     469              : 
     470            1 : void HostCpuRoceChannel::NotifyVecPack(Hccl::BinaryStream& binaryStream)
     471              : {
     472            1 :     binaryStream << notifyNum_;
     473            1 :     HCCL_INFO("start pack DpuRoceChannel notifyVec");
     474            1 :     u32 pos = 0;
     475            5 :     for (auto& it : localDpuNotifyIds_) {
     476            4 :         binaryStream << it;
     477            4 :         HCCL_INFO("pack notify pos=%u, notifyId=%u", pos, it);
     478            4 :         pos++;
     479              :     }
     480            1 : }
     481              : 
     482            1 : HcclResult HostCpuRoceChannel::BufferVecPack(Hccl::BinaryStream& binaryStream)
     483              : {
     484            1 :     binaryStream << bufferNum_;
     485            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] start to pack RmaBuffers", __func__);
     486            1 :     u32 pos = 0;
     487            1 :     for (auto& it : localRmaBuffers_) {
     488            1 :         binaryStream << pos;
     489            1 :         if (it != nullptr) { // 非空的buffer,从buffer中获取 dto
     490            1 :             std::unique_ptr<Hccl::Serializable> dto = it->GetExchangeDto();
     491            1 :             if (dto == nullptr) {
     492            1 :                 return HCCL_E_INTERNAL;
     493              :             }
     494            0 :             dto->Serialize(binaryStream);
     495            0 :             HCCL_INFO("pack buffer pos=%u dto %s", pos, dto->Describe().c_str());
     496            1 :         } else { // 空的buffer,dto所有字段为0(size=0)
     497            0 :             Hccl::ExchangeRdmaBufferDto exchangeDto;
     498            0 :             exchangeDto.Serialize(binaryStream);
     499            0 :             HCCL_INFO("pack buffer pos=%u, dto is null %s", pos, exchangeDto.Describe().c_str());
     500            0 :         }
     501            0 :         pos++;
     502              :     }
     503            0 :     HCCL_INFO("[HostCpuRoceChannel::%s] pack RmaBuffers finish", __func__);
     504            0 :     return HCCL_SUCCESS;
     505              : }
     506              : 
     507            1 : HcclResult HostCpuRoceChannel::ConnVecPack(Hccl::BinaryStream& binaryStream)
     508              : {
     509            1 :     binaryStream << connNum_;
     510            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] start to pack connections", __func__);
     511            1 :     u32 pos = 0;
     512            1 :     binaryStream << channelDesc_.roceAttr.queueNum;
     513            2 :     for (auto& it : connections_) {
     514            1 :         binaryStream << pos;
     515              : 
     516            1 :         binaryStream << channelDesc_.roceAttr.retryCnt;
     517            1 :         binaryStream << channelDesc_.roceAttr.retryInterval;
     518            1 :         binaryStream << channelDesc_.roceAttr.sl;
     519            1 :         binaryStream << channelDesc_.roceAttr.tc;
     520              : 
     521            1 :         std::unique_ptr<Hccl::Serializable> dto = nullptr;
     522            1 :         CHK_RET(it->GetExchangeDto(dto));
     523            1 :         dto->Serialize(binaryStream);
     524            1 :         HCCL_INFO("pack connection pos=%u, dto %s", pos, dto->Describe().c_str());
     525            1 :         pos++;
     526            1 :     }
     527            1 :     HCCL_INFO("[HostCpuRoceChannel::%s] pack connections finish", __func__);
     528            1 :     return HCCL_SUCCESS;
     529              : }
     530              : 
     531            0 : HcclResult HostCpuRoceChannel::RmtBufferVecUnpackProc(Hccl::BinaryStream& binaryStream)
     532              : {
     533              :     u32 rmtNum;
     534            0 :     binaryStream >> rmtNum;
     535              : 
     536            0 :     HCCL_INFO("[HostCpuRoceChannel::%s] bufferNum_=%u, rmtNum=%u", __func__, bufferNum_, rmtNum);
     537              : 
     538            0 :     rmtRmaBuffers_.resize(rmtNum);
     539            0 :     for (u32 i = 0; i < rmtNum; i++) {
     540              :         u32 pos;
     541            0 :         binaryStream >> pos;
     542            0 :         if (pos >= rmtNum) {
     543            0 :             HCCL_ERROR("[HostCpuRoceChannel::%s] pos=%u out of range (rmtNum=%u)", __func__, pos, rmtNum);
     544            0 :             return HCCL_E_INTERNAL;
     545              :         }
     546            0 :         Hccl::ExchangeRdmaBufferDto dto;
     547            0 :         dto.Deserialize(binaryStream);
     548              : 
     549            0 :         HCCL_INFO("[HostCpuRoceChannel::%s] pos=%u, dto %s", __func__, pos, dto.Describe().c_str());
     550            0 :         EXCEPTION_CATCH(
     551              :             rmtRmaBuffers_[pos] = std::make_unique<Hccl::RemoteRdmaRmaBuffer>(rdmaHandle_, dto),
     552              :             HCCL_ERROR(
     553              :                 "[HostCpuRoceChannel::%s] make_unique<Hccl::RemoteRdmaRmaBuffer> throws an exception!", __func__);
     554              :             return HCCL_E_INTERNAL);
     555            0 :         HCCL_INFO(
     556              :             "[HostCpuRoceChannel::%s] pos=%u, rmtRmaBuffer=%s", __func__, pos, rmtRmaBuffers_[pos]->Describe().c_str());
     557            0 :     }
     558              : 
     559            0 :     return HCCL_SUCCESS;
     560              : }
     561              : 
     562            1 : HcclResult HostCpuRoceChannel::NotifyVecUnpack(Hccl::BinaryStream& binaryStream)
     563              : {
     564            1 :     uint32_t notifySize = 0;
     565            1 :     binaryStream >> notifySize;
     566            1 :     if (notifySize != notifyNum_) {
     567            0 :         HCCL_ERROR(
     568              :             "[HostCpuRoceChannel::NotifyVecUnpack] rmtNum=%u is not equal to localNum=%u", notifySize, notifyNum_);
     569            0 :         return HCCL_E_ROCE_CONNECT;
     570              :     }
     571            1 :     remoteDpuNotifyIds_.clear();
     572            1 :     u32 pos = 0;
     573            5 :     for (pos = 0; pos < notifySize; pos++) {
     574              :         uint32_t notifyId;
     575            4 :         binaryStream >> notifyId;
     576            4 :         remoteDpuNotifyIds_.push_back(notifyId);
     577              :     }
     578            1 :     HCCL_INFO("[HostCpuRoceChannel::NotifyVecUnpack] unpack dpuNotify");
     579            1 :     return HCCL_SUCCESS;
     580              : }
     581              : 
     582            1 : HcclResult HostCpuRoceChannel::ConnVecUnpackProc(Hccl::BinaryStream& binaryStream)
     583              : {
     584              :     u32 rmtConnNum;
     585            1 :     binaryStream >> rmtConnNum;
     586            1 :     HCCL_INFO("start unpack conn, connNum=%u, rmtConnNum=%u", connNum_, rmtConnNum);
     587            1 :     if (connNum_ != rmtConnNum) {
     588            0 :         HCCL_ERROR("connNum=%u is not equal to rmtConnNum=%u", connNum_, rmtConnNum);
     589            0 :         return HCCL_E_ROCE_CONNECT;
     590              :     }
     591              : 
     592            1 :     uint32_t localQpNum = channelDesc_.roceAttr.queueNum;
     593            1 :     binaryStream >> channelDesc_.roceAttr.queueNum;
     594            1 :     if (localQpNum != channelDesc_.roceAttr.queueNum) {
     595            0 :         HCCL_ERROR("localQpNum[%u] is not equal to remoteQpNum[%u]", localQpNum, channelDesc_.roceAttr.queueNum);
     596            0 :         return HCCL_E_ROCE_CONNECT;
     597              :     }
     598              : 
     599            1 :     rmtConnDtos_.resize(rmtConnNum);
     600            2 :     for (u32 i = 0; i < rmtConnNum; i++) {
     601              :         u32 pos;
     602            1 :         binaryStream >> pos;
     603            1 :         binaryStream >> channelDesc_.roceAttr.retryCnt;
     604            1 :         binaryStream >> channelDesc_.roceAttr.retryInterval;
     605            1 :         binaryStream >> channelDesc_.roceAttr.sl;
     606            1 :         binaryStream >> channelDesc_.roceAttr.tc;
     607            1 :         rmtConnDtos_[i].Deserialize(binaryStream);
     608              :     }
     609              : 
     610            1 :     return HCCL_SUCCESS;
     611              : }
     612              : 
     613           49 : HcclResult HostCpuRoceChannel::ModifyQp()
     614              : {
     615           51 :     for (uint32_t i = 0; i < connections_.size(); i++) {
     616            3 :         auto& conn = connections_[i];
     617            3 :         Hccl::CHECK_NULLPTR(
     618            6 :             conn, Hccl::StringFormat("[HostCpuRoceChannel::%s] failed, connection pointer is nullptr", __func__));
     619            3 :         CHK_RET(conn->ParseRmtExchangeDto(rmtConnDtos_[i]));
     620            3 :         Hccl::QpInfo& qpInfo = conn->GetQpInfo();
     621            3 :         qpInfo.serviceLevel = channelDesc_.roceAttr.sl;
     622            3 :         qpInfo.trafficClass = channelDesc_.roceAttr.tc;
     623            3 :         qpInfo.retryCnt = channelDesc_.roceAttr.retryCnt;
     624            3 :         qpInfo.retryInterval = channelDesc_.roceAttr.retryInterval;
     625            3 :         HCCL_INFO(
     626              :             "[HostCpuRoceChannel::ModifyQp] QpInfo: serviceLevel[%u], trafficClass[%u], retryCnt[%u], "
     627              :             "retryInterval[%u].",
     628              :             qpInfo.serviceLevel, qpInfo.trafficClass, qpInfo.retryCnt, qpInfo.retryInterval);
     629            3 :         HcclResult ret = conn->ModifyQp();
     630            3 :         if (ret == HCCL_E_AGAIN) {
     631            0 :             return HCCL_SUCCESS;
     632              :         }
     633            3 :         if (ret != HCCL_SUCCESS) {
     634            1 :             return ret;
     635              :         }
     636              :     }
     637           48 :     HCCL_INFO("[HostCpuRoceChannel::IsResReady] all connections resources connected.");
     638           48 :     return HCCL_SUCCESS;
     639              : }
     640              : 
     641            5 : HcclResult HostCpuRoceChannel::GetRemoteMems(uint32_t* memNum, CommMem** remoteMem, char*** memInfos)
     642              : {
     643            5 :     std::lock_guard<std::mutex> lock(remoteMemsMutex_);
     644              :     Hccl::RemoteMemCtx<std::unique_ptr<Hccl::RemoteRdmaRmaBuffer>> remoteMemCtx{
     645            5 :         cacheValid_, rmtRmaBuffers_, userRemoteMems_, memInfoCopies_, memInfoPointers_, remoteMem, memInfos, memNum};
     646            5 :     CHK_RET(GetRemoteUserMems(remoteMemCtx));
     647            4 :     return HCCL_SUCCESS;
     648            5 : }
     649              : 
     650            0 : std::vector<Hccl::QpInfo> HostCpuRoceChannel::GetQpInfos() const
     651              : {
     652            0 :     std::vector<Hccl::QpInfo> qpInfos;
     653            0 :     for (auto& rdmaConn : connections_) {
     654            0 :         qpInfos.emplace_back(rdmaConn->GetQpInfo());
     655              :     }
     656            0 :     return qpInfos;
     657            0 : }
     658              : 
     659            1 : std::string HostCpuRoceChannel::Describe() const
     660              : {
     661            1 :     std::string msg = "HostCpuRoceChannel{";
     662            1 :     msg += Hccl::StringFormat("notifyNum:%u, dpuNotifyList:[-]", notifyNum_);
     663            1 :     msg += Hccl::StringFormat(", bufferNum:%u, localRmaBuffers: [", bufferNum_);
     664            3 :     for (auto& buf : localRmaBuffers_) {
     665            2 :         msg += buf->Describe();
     666            2 :         msg += ", ";
     667              :     }
     668            1 :     msg += Hccl::StringFormat("], connNum:%u, connections:[", connNum_);
     669            1 :     for (auto& conn : connections_) {
     670            0 :         msg += conn->Describe();
     671            0 :         msg += ", ";
     672              :     }
     673            1 :     msg += Hccl::StringFormat("], rdmaHandle: %p, %s, ", rdmaHandle_, channelStatus_.Describe().c_str());
     674              : 
     675            1 :     if (socket_ != nullptr) {
     676            1 :         msg += socket_->Describe();
     677              :     }
     678              : 
     679            1 :     msg += ", ";
     680              :     // msg += attr_.Describe();
     681            1 :     return msg;
     682            0 : }
     683              : 
     684            1 : HcclResult HostCpuRoceChannel::SetDfxCallback(std::function<HcclResult(const Hccl::TaskParam&, u64)> callback)
     685              : {
     686            1 :     dfxCallback_ = callback;
     687            1 :     return HCCL_SUCCESS;
     688              : }
     689              : 
     690            0 : HcclResult HostCpuRoceChannel::IbvPostRecv() const
     691              : {
     692            0 :     std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
     693            0 :     CHK_PRT_RET(qpInfo.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] qpInfos is Empty", __func__), HCCL_E_ROCE_CONNECT);
     694            0 :     CHK_PRT_RET(
     695              :         localRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] localRmaBuffer is Empty", __func__),
     696              :         HCCL_E_ROCE_CONNECT);
     697            0 :     CHK_PRT_RET(
     698              :         rmtRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] rmtRmaBuffers is Empty", __func__),
     699              :         HCCL_E_ROCE_CONNECT);
     700              : 
     701              :     // 准备wr
     702            0 :     HCCL_INFO("[HostCpuRoceChannel::%s] call ibv_post_recv", __func__);
     703            0 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
     704            0 :         ibv_recv_wr recvWr{};
     705            0 :         ibv_recv_wr* recvbadWr = nullptr;
     706            0 :         ibv_sge recvsgList{};
     707            0 :         recvsgList.addr = localRmaBuffers_[0]->GetBufferInfo().first
     708            0 :                           + MEM_BLOCK_SIZE * i; // 本端起始地址,cclbuffer最小为1MB,足够使用
     709            0 :         recvsgList.length = MEM_BLOCK_SIZE;
     710            0 :         recvsgList.lkey = localRmaBuffers_[0]->GetLkey(); // 本端的访问秘钥
     711            0 :         recvWr.wr_id = i;
     712            0 :         recvWr.sg_list = &recvsgList;
     713            0 :         recvWr.next = nullptr;
     714            0 :         recvWr.num_sge = 1;
     715              : 
     716            0 :         HCCL_INFO("qp_state[%u] = [%u]", i, qpInfo[i].qp->state);
     717            0 :         int32_t ret = ibv_post_recv(qpInfo[i].qp, &recvWr, &recvbadWr);
     718            0 :         CHK_PRT_RET(
     719              :             ret == ENOMEM,
     720              :             HCCL_WARNING(
     721              :                 "[HostCpuRoceChannel][%s] post recv wqe overflow. ret:%d, "
     722              :                 "badWr->wr_id[%llu], badWr->sg_list->addr[%llu]",
     723              :                 __func__, ret, recvbadWr->wr_id, recvbadWr->sg_list->addr),
     724              :             HCCL_E_AGAIN);
     725              : 
     726            0 :         CHK_PRT_RET(
     727              :             ret != 0,
     728              :             HCCL_ERROR(
     729              :                 "[HostCpuRoceChannel][%s] ibv_post_recv failed. ret:%d, "
     730              :                 "badWr->wr_id[%llu], badWr->sg_list->addr[%llu]",
     731              :                 __func__, ret, recvbadWr->wr_id, recvbadWr->sg_list->addr),
     732              :             HCCL_E_NETWORK);
     733              :     }
     734              : 
     735            0 :     return HCCL_SUCCESS;
     736            0 : }
     737              : 
     738            3 : HcclResult HostCpuRoceChannel::PrepareNotifyWrResource(
     739              :     uint32_t qpIdx, const uint64_t len, const uint32_t remoteNotifyIdx, struct ibv_send_wr& notifyRecordWr,
     740              :     Hccl::TaskParam& taskParam) const
     741              : {
     742            3 :     taskParam.beginTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
     743            3 :     if (remoteNotifyIdx >= remoteDpuNotifyIds_.size()) {
     744            2 :         HCCL_ERROR(
     745              :             "[HostCpuRoceChannel::%s] remoteNotifyIdx[%u] out of the range of remoteDpuNotifyIds_[%zu].", __func__,
     746              :             remoteNotifyIdx, remoteDpuNotifyIds_.size());
     747            2 :         return HCCL_E_PARA;
     748              :     }
     749            1 :     uint32_t dpuNotifyId = remoteDpuNotifyIds_[remoteNotifyIdx];
     750              : 
     751            1 :     CHK_PRT_RET(
     752              :         localRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] localRmaBuffer is Empty", __func__),
     753              :         HCCL_E_ROCE_CONNECT);
     754            1 :     CHK_PRT_RET(
     755              :         rmtRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] rmtRmaBuffers is Empty", __func__),
     756              :         HCCL_E_ROCE_CONNECT);
     757              : 
     758              :     // 构造send_WR
     759            1 :     notifyRecordWr.sg_list->addr = localRmaBuffers_[0]->GetBufferInfo().first; // 本端起始地址
     760            1 :     notifyRecordWr.sg_list->length = 0;                                        // 取的本端长度
     761            1 :     notifyRecordWr.sg_list->lkey = localRmaBuffers_[0]->GetLkey();             // 本端的访问秘钥
     762            1 :     notifyRecordWr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM;
     763            1 :     notifyRecordWr.send_flags = IBV_SEND_SIGNALED;
     764            1 :     notifyRecordWr.imm_data = dpuNotifyId;
     765            1 :     notifyRecordWr.next = nullptr;
     766            1 :     notifyRecordWr.num_sge = 1;
     767            1 :     notifyRecordWr.wr_id = qpIdx; // 用户定义工作请求id,建议:设为有意义的值
     768            1 :     notifyRecordWr.wr.rdma.rkey = rmtRmaBuffers_[0]->GetRkey();                               // 远端秘钥
     769            1 :     notifyRecordWr.wr.rdma.remote_addr = static_cast<uint64_t>(rmtRmaBuffers_[0]->GetAddr()); // 远端地址
     770              : 
     771            1 :     taskParam.taskType = Hccl::TaskParamType::TASK_DPU_INLINE_WRITE;
     772            1 :     taskParam.taskPara.DMA.dst = reinterpret_cast<void*>(static_cast<uint64_t>(rmtRmaBuffers_[0]->GetAddr()));
     773            1 :     taskParam.taskPara.DMA.size = len;
     774            1 :     taskParam.taskPara.DMA.notifyID = dpuNotifyId;
     775            1 :     taskParam.taskPara.DMA.notifyValue = 1;
     776            1 :     taskParam.taskPara.DMA.linkType = Hccl::DfxLinkType::ROCE;
     777            1 :     taskParam.taskPara.DMA.dmaOp = Hccl::DmaOp::HCCL_DMA_WRITE;
     778            1 :     return HCCL_SUCCESS;
     779              : }
     780              : 
     781            9 : hccl::MemType HostCpuRoceChannel::NotifyIdToMemtypeHybird(uint32_t remoteNotifyIdx)
     782              : {
     783            9 :     if (remoteNotifyIdx == 0) {
     784            5 :         return hccl::MemType::ACK_NOTIFY_MEM;
     785              :     } else {
     786            4 :         return hccl::MemType::DATA_NOTIFY_MEM;
     787              :     }
     788              : 
     789              :     return hccl::MemType::DATA_NOTIFY_MEM;
     790              : }
     791              : 
     792            1 : HcclResult HostCpuRoceChannel::BuildNotifyWrHybird(const uint32_t remoteNotifyIdx, struct ibv_send_wr& notifRecordWr)
     793              : {
     794            1 :     hccl::MemType type = NotifyIdToMemtypeHybird(remoteNotifyIdx);
     795              : 
     796            1 :     notifRecordWr.sg_list->addr = reinterpret_cast<uint64_t>(localMemMsg_[hccl::NOTIFY_SRC_MEM].addr);
     797            1 :     notifRecordWr.sg_list->length = localMemMsg_[hccl::NOTIFY_SRC_MEM].len;
     798            1 :     notifRecordWr.sg_list->lkey = localMemMsg_[hccl::NOTIFY_SRC_MEM].lkey;
     799            1 :     notifRecordWr.opcode = IBV_WR_RDMA_WRITE;
     800            1 :     notifRecordWr.send_flags = IBV_SEND_SIGNALED;
     801            1 :     notifRecordWr.next = nullptr;
     802            1 :     notifRecordWr.num_sge = 1;
     803            1 :     notifRecordWr.wr_id = 0;
     804            1 :     notifRecordWr.wr.rdma.rkey = remoteMemMsg_[type].lkey;
     805            1 :     notifRecordWr.wr.rdma.remote_addr = reinterpret_cast<uint64_t>(remoteMemMsg_[type].addr);
     806              : 
     807            1 :     return HCCL_SUCCESS;
     808              : }
     809              : 
     810            2 : HcclResult HostCpuRoceChannel::NotifyRecord(const uint32_t remoteNotifyIdx)
     811              : {
     812              :     // 1.构造send_WR
     813            2 :     struct ibv_send_wr notifyRecordWr {};
     814            2 :     struct ibv_send_wr* sendbadWr = nullptr;
     815            2 :     struct ibv_sge sgList {};
     816            2 :     notifyRecordWr.sg_list = &sgList;
     817            2 :     Hccl::TaskParam taskParam{};
     818              : 
     819            2 :     std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
     820            2 :     CHK_PRT_RET(qpInfo.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] qpInfos is Empty", __func__), HCCL_E_ROCE_CONNECT);
     821              : 
     822              :     // 3.调用ibv_post_send
     823            2 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
     824            2 :         HCCL_INFO("[HostCpuRoceChannel::%s] call ibv_post_send, qp_state[%u] = [%u]", __func__, i, qpInfo[i].qp->state);
     825            2 :         if (isHybridMode_) {
     826            0 :             BuildNotifyWrHybird(remoteNotifyIdx, notifyRecordWr);
     827              :         } else {
     828            2 :             CHK_RET(PrepareNotifyWrResource(i, MEM_BLOCK_SIZE, remoteNotifyIdx, notifyRecordWr, taskParam));
     829              :         }
     830            0 :         int32_t ret = ibv_post_send(qpInfo[i].qp, &notifyRecordWr, &sendbadWr);
     831            0 :         if (ret != 0 && sendbadWr == nullptr) {
     832            0 :             HCCL_ERROR("[HostCpuRoceChannel::%s] ibv_post_send failed while badWr is nullptr", __func__);
     833            0 :             return HCCL_E_INTERNAL;
     834              :         }
     835            0 :         CHK_PRT_RET(
     836              :             ret == ENOMEM,
     837              :             HCCL_WARNING(
     838              :                 "[HostCpuRoceChannel][%s] post send wqe overflow. ret:%d, badWr->wr_id[%llu], "
     839              :                 "badWr->sg_list->addr[%llu], badWr->wr.rdma.remote_addr[%llu], badWr->wr.ud.remote_qpn[%u]",
     840              :                 __func__, ret, sendbadWr->wr_id, sendbadWr->sg_list->addr, sendbadWr->wr.rdma.remote_addr,
     841              :                 sendbadWr->wr.ud.remote_qpn),
     842              :             HCCL_E_AGAIN);
     843              : 
     844            0 :         CHK_PRT_RET(
     845              :             ret != 0,
     846              :             HCCL_ERROR(
     847              :                 "[HostCpuRoceChannel][%s] ibv_post_send failed. ret:%d, badWr->wr_id[%llu], "
     848              :                 "badWr->sg_list->addr[%llu], badWr->wr.rdma.remote_addr[%llu], badWr->wr.ud.remote_qpn[%u]",
     849              :                 __func__, ret, sendbadWr->wr_id, sendbadWr->sg_list->addr, sendbadWr->wr.rdma.remote_addr,
     850              :                 sendbadWr->wr.ud.remote_qpn),
     851              :             HCCL_E_NETWORK);
     852            0 :         if (wqeNums_[i] == INT32_MAX) {
     853            0 :             HCCL_ERROR("[HostCpuRoceChannel::%s] wqeNums_[%u] has reached the maximum value of uint32_t.", __func__, i);
     854            0 :             return HCCL_E_INTERNAL;
     855              :         }
     856            0 :         wqeNums_[i]++;
     857            0 :         HCCL_INFO("[HostCpuRoceChannel::NotifyRecord] NotifyRecord end, wqeNums_[%u]=%d", i, wqeNums_[i]);
     858              :     }
     859              : 
     860            0 :     taskParam.endTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
     861            0 :     if (dfxCallback_ != nullptr) {
     862            0 :         return dfxCallback_(taskParam, reinterpret_cast<u64>(this));
     863              :     }
     864            0 :     return HCCL_SUCCESS;
     865            2 : }
     866              : 
     867            3 : HcclResult HostCpuRoceChannel::NotifyWait(const uint32_t localNotifyIdx, const uint32_t timeout)
     868              : {
     869            3 :     Hccl::TaskParam taskParam{};
     870            3 :     taskParam.beginTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
     871              : 
     872            3 :     if (isHybridMode_) {
     873            0 :         return NotifyWaitHybrid(localNotifyIdx, timeout);
     874              :     }
     875              : 
     876            3 :     CHK_PRT_RET(
     877              :         localNotifyIdx >= localDpuNotifyIds_.size(),
     878              :         HCCL_ERROR(
     879              :             "[HostCpuRoceChannel::%s] localNotifyIdx[%u] out of the range of localDpuNotifyIds_[%zu].", __func__,
     880              :             localNotifyIdx, localDpuNotifyIds_.size()),
     881              :         HCCL_E_PARA);
     882              : 
     883            3 :     uint32_t dpuNotifyId = localDpuNotifyIds_[localNotifyIdx];
     884              : 
     885              :     // 1. 准备WR
     886            3 :     struct ibv_wc wc {};
     887            3 :     std::lock_guard<std::mutex> lock(cq_mutex);
     888            3 :     std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
     889            3 :     CHK_PRT_RET(qpInfo.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] qpInfos is Empty", __func__), HCCL_E_ROCE_CONNECT);
     890            3 :     HCCL_INFO(
     891              :         "[HostCpuRoceChannel::NotifyWait] poll recvCq = %p, localNotifyIdx = %u, notifyId = %u.", qpInfo[0].recvCq,
     892              :         localNotifyIdx, dpuNotifyId);
     893              : 
     894              :     // 2.轮询rq_cq
     895            3 :     auto startTime = std::chrono::steady_clock::now();
     896            3 :     auto waitTime = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::seconds(timeout));
     897            3 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
     898            3 :         CHK_PRT_RET(
     899              :             qpInfo[i].recvCq == nullptr, HCCL_ERROR("[HostCpuRoceChannel::%s] recvCq[%u] is null", __func__, i),
     900              :             HCCL_E_INTERNAL);
     901            3 :         CHK_PRT_RET(
     902              :             qpInfo[i].qp == nullptr, HCCL_ERROR("[HostCpuRoceChannel::%s] qp[%u] is null", __func__, i),
     903              :             HCCL_E_INTERNAL);
     904            3 :         CHK_PRT_RET(
     905              :             qpInfo[i].recvCq->context == nullptr,
     906              :             HCCL_ERROR("[HostCpuRoceChannel::%s] recvCq[%u]->context is null", __func__, i), HCCL_E_INTERNAL);
     907              : 
     908              :         while (true) {
     909            0 :             auto actualNum = ibv_poll_cq(qpInfo[i].recvCq, 1, &wc);
     910            0 :             CHK_PRT_RET(
     911              :                 actualNum < 0,
     912              :                 HCCL_ERROR("[HostCpuRoceChannel::%s] ibv_poll_cq err. actualNum=%d", __func__, actualNum),
     913              :                 HCCL_E_NETWORK);
     914              : 
     915            0 :             if (actualNum > 0 && wc.imm_data == dpuNotifyId) {
     916            0 :                 if (wc.status != IBV_WC_SUCCESS) {
     917            0 :                     HCCL_ERROR(
     918              :                         "[HostCpuRoceChannel][%s] ibv_poll_cq return wc.status[%d], wc.opcode[%d], wc.vendorErr[%u], "
     919              :                         "wc.byteLen[%u], wc.wcFlags[%u], wc.sl[%u], qpInfo[%u].qp->qp_num[%u]",
     920              :                         __func__, wc.status, wc.opcode, wc.vendor_err, wc.byte_len, wc.wc_flags, wc.sl, i,
     921              :                         qpInfo[i].qp->qp_num);
     922            0 :                     return ReportWcStatusError(wc.status);
     923              :                 }
     924            0 :                 HCCL_INFO("[HostCpuRoceChannel::NotifyWait] poll cq success");
     925            0 :                 break;
     926            0 :             } else if (actualNum > 0) {
     927            0 :                 CHK_PRT_RET(
     928              :                     true,
     929              :                     HCCL_ERROR(
     930              :                         "[HostCpuRoceChannel::%s] polled cq unexpected. imm_data[%u] != dpuNotifyId[%u]", __func__,
     931              :                         wc.imm_data, dpuNotifyId),
     932              :                     HCCL_E_NETWORK);
     933              :             }
     934              : 
     935            0 :             if ((std::chrono::steady_clock::now() - startTime) >= waitTime) {
     936            0 :                 CHK_PRT_RET(
     937              :                     true,
     938              :                     HCCL_ERROR("[HostCpuRoceChannel][%s] call ibv_poll_cq timeout. actualNum=%d", __func__, actualNum),
     939              :                     HCCL_E_TIMEOUT);
     940              :             }
     941            0 :         }
     942              :     }
     943              : 
     944            0 :     CHK_RET(IbvPostRecv());
     945            0 :     taskParam.taskType = Hccl::TaskParamType::TASK_DPU_NOTIFY_WAIT;
     946            0 :     taskParam.taskPara.Notify.notifyID = dpuNotifyId;
     947            0 :     taskParam.taskPara.Notify.value = 1;
     948            0 :     taskParam.endTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
     949            0 :     if (dfxCallback_ != nullptr) {
     950            0 :         return dfxCallback_(taskParam, reinterpret_cast<u64>(this));
     951              :     }
     952            0 :     return HCCL_SUCCESS;
     953            3 : }
     954              : 
     955            6 : HcclResult HostCpuRoceChannel::ReportWcStatusError([[maybe_unused]] enum ibv_wc_status status)
     956              : {
     957            6 :     Hccl::IpAddress localIp, remoteIp;
     958            6 :     (void)CommAddrToIpAddress(localEp_.commAddr, localIp);
     959            6 :     (void)CommAddrToIpAddress(remoteEp_.commAddr, remoteIp);
     960          132 :     RPT_INPUT_ERR(
     961              :         true, "EI0013",
     962              :         std::vector<std::string>(
     963              :             {"localServerId", "localDeviceId", "localDeviceIp", "remoteServerId", "remoteDeviceId", "remoteDeviceIp"}),
     964              :         std::vector<std::string>(
     965              :             {std::to_string(localEp_.loc.device.serverIdx), std::to_string(localEp_.loc.device.devPhyId),
     966              :              localIp.GetIpStr(), std::to_string(remoteEp_.loc.device.serverIdx),
     967              :              std::to_string(remoteEp_.loc.device.devPhyId), remoteIp.GetIpStr()}));
     968            6 :     return HCCL_E_NETWORK;
     969            6 : }
     970              : 
     971            2 : HcclResult HostCpuRoceChannel::PrepareWriteWrResource(
     972              :     const void* dst, const void* src, const uint64_t len, const uint32_t remoteNotifyIdx,
     973              :     struct ibv_send_wr& writeWithNotifyWr, Hccl::TaskParam& taskParam) const
     974              : {
     975            2 :     taskParam.beginTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
     976            2 :     if (remoteNotifyIdx >= remoteDpuNotifyIds_.size()) {
     977            1 :         HCCL_ERROR(
     978              :             "[HostCpuRoceChannel::%s] remoteNotifyIdx[%u] out of the range of remoteDpuNotifyIds_[%zu].", __func__,
     979              :             remoteNotifyIdx, remoteDpuNotifyIds_.size());
     980            1 :         return HCCL_E_PARA;
     981              :     }
     982            1 :     uint32_t dpuNotifyId = remoteDpuNotifyIds_[remoteNotifyIdx];
     983              : 
     984            1 :     CHK_PRT_RET(
     985              :         localRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] localRmaBuffer is Empty", __func__),
     986              :         HCCL_E_ROCE_CONNECT);
     987            1 :     CHK_PRT_RET(
     988              :         rmtRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] rmtRmaBuffers is Empty", __func__),
     989              :         HCCL_E_ROCE_CONNECT);
     990              : 
     991              :     // 1. 构造WR
     992            1 :     CHK_PRT_RET(
     993              :         len > UINT32_MAX, HCCL_ERROR("[HostCpuRoceChannel][%s] the len[%llu] exceeds the size of u32.", __func__, len),
     994              :         HCCL_E_PARA);
     995              : 
     996            1 :     size_t localIdx = 0;
     997            1 :     CHK_RET(FindLocalBuffer(reinterpret_cast<uint64_t>(src), len, localIdx));
     998            1 :     size_t rmtIdx = 0;
     999            1 :     CHK_RET(FindRemoteBuffer(reinterpret_cast<uint64_t>(dst), len, rmtIdx));
    1000              : 
    1001            1 :     writeWithNotifyWr.sg_list->addr = reinterpret_cast<uint64_t>(src); // 本端起始地址
    1002            1 :     writeWithNotifyWr.sg_list->length = static_cast<uint32_t>(len);
    1003            1 :     writeWithNotifyWr.sg_list->lkey = localRmaBuffers_[localIdx]->GetLkey(); // 本端的访问秘钥
    1004              : 
    1005            1 :     writeWithNotifyWr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM;
    1006            1 :     writeWithNotifyWr.send_flags = IBV_SEND_SIGNALED;
    1007            1 :     writeWithNotifyWr.next = nullptr;
    1008            1 :     writeWithNotifyWr.num_sge = 1;
    1009            1 :     writeWithNotifyWr.wr_id = 0;
    1010            1 :     writeWithNotifyWr.imm_data = dpuNotifyId;
    1011            1 :     writeWithNotifyWr.wr.rdma.rkey = rmtRmaBuffers_[rmtIdx]->GetRkey();
    1012            1 :     writeWithNotifyWr.wr.rdma.remote_addr = reinterpret_cast<uint64_t>(dst);
    1013              : 
    1014            1 :     taskParam.taskType = Hccl::TaskParamType::TASK_DPU_WRITE_WITH_NOTIFY;
    1015            1 :     taskParam.taskPara.DMA.src = src;
    1016            1 :     taskParam.taskPara.DMA.dst = dst;
    1017            1 :     taskParam.taskPara.DMA.size = len;
    1018            1 :     taskParam.taskPara.DMA.notifyID = dpuNotifyId;
    1019            1 :     taskParam.taskPara.DMA.notifyValue = 1;
    1020            1 :     taskParam.taskPara.DMA.linkType = Hccl::DfxLinkType::ROCE;
    1021            1 :     taskParam.taskPara.DMA.dmaOp = Hccl::DmaOp::HCCL_DMA_WRITE;
    1022            1 :     return HCCL_SUCCESS;
    1023              : }
    1024              : 
    1025              : HcclResult
    1026            3 : HostCpuRoceChannel::WriteWithNotify(void* dst, const void* src, const uint64_t len, const uint32_t remoteNotifyIdx)
    1027              : {
    1028            3 :     CHK_PTR_NULL(src);
    1029            3 :     CHK_PTR_NULL(dst);
    1030            3 :     CHK_PRT_RET(
    1031              :         maxMsgSize_ == 0, HCCL_ERROR("[HostCpuRoceChannel::%s] maxMsgSize_ is 0, channel not initialized", __func__),
    1032              :         HCCL_E_INTERNAL);
    1033            2 :     CHK_PRT_RET(
    1034              :         GetQpInfos().empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] qpInfos is Empty", __func__), HCCL_E_ROCE_CONNECT);
    1035            2 :     HCCL_INFO(
    1036              :         "[HostCpuRoceChannel::%s] START. dst[%p], src[%p], len[0x%llx], remoteNotifyIdx[%u].", __func__, dst, src, len,
    1037              :         remoteNotifyIdx);
    1038            2 :     std::vector<int> wqeNumBefore = wqeNums_;
    1039              : 
    1040            2 :     if (isHybridMode_) {
    1041            0 :         return WriteWithNotifyHybrid(dst, src, len, remoteNotifyIdx);
    1042              :     }
    1043              : 
    1044              :     // 前 N-1 块: 普通 RDMA_WRITE
    1045            2 :     uint64_t offset = 0;
    1046            4 :     while (len - offset > maxMsgSize_) {
    1047            2 :         CHK_RET(PostRdmaOp(
    1048              :             __func__, IBV_WR_RDMA_WRITE, static_cast<char*>(const_cast<void*>(src)) + offset,
    1049              :             static_cast<const char*>(dst) + offset, maxMsgSize_));
    1050            2 :         offset += maxMsgSize_;
    1051              :     }
    1052              : 
    1053              :     // 尾块: RDMA_WRITE_WITH_IMM,携带 notify
    1054            2 :     void* tailDst = static_cast<char*>(dst) + offset;
    1055            2 :     const void* tailSrc = static_cast<const char*>(src) + offset;
    1056            2 :     uint64_t tailLen = len - offset;
    1057              : 
    1058              :     // 计算每个qp需要发送的数据量
    1059            2 :     std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
    1060            2 :     uint32_t useQpNum = qpInfo.size();
    1061            2 :     uint64_t tileLen = tailLen / useQpNum;
    1062            2 :     uint64_t tileLenTail = tailLen - (useQpNum - 1) * tileLen;
    1063            2 :     if ((qpInfo.size() != 1) && (tileLen != 0) && (tileLen < channelDesc_.roceAttr.qpThreshold)) {
    1064            0 :         useQpNum = (tailLen - 1) / channelDesc_.roceAttr.qpThreshold
    1065            0 :                    + 1; // 自适应选择QP数发送数据,保证每个qp分担的数据量满足最小阈值
    1066            0 :         if (useQpNum > qpInfo.size()) {
    1067            0 :             useQpNum = qpInfo.size();
    1068              :         }
    1069            0 :         tileLen = tailLen / useQpNum;
    1070            0 :         tileLenTail = tailLen - (useQpNum - 1) * tileLen;
    1071            0 :         HCCL_INFO(
    1072              :             "[HostCpuRoceChannel::%s] The data allocated to each Qp (%u) is below the Qp Threshold (%u). "
    1073              :             "the count of Qp for data sending is adaptively adjusted to %u.",
    1074              :             __func__, tileLen, channelDesc_.roceAttr.qpThreshold, useQpNum);
    1075              :     }
    1076              : 
    1077              :     // 构造 WR
    1078            2 :     Hccl::TaskParam taskParam{};
    1079              :     uint64_t wrLen;
    1080            3 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
    1081            2 :         if (i < useQpNum - 1) {
    1082            0 :             wrLen = tileLen;
    1083            0 :             offset = tileLen * i;
    1084            2 :         } else if (i == useQpNum - 1) {
    1085            2 :             wrLen = tileLenTail;
    1086            2 :             offset = tileLen * i;
    1087              :         } else {
    1088            0 :             wrLen = 0;
    1089            0 :             offset = 0;
    1090              :         }
    1091            2 :         struct ibv_send_wr writeWithNotifyWr {};
    1092            2 :         struct ibv_sge sgList {};
    1093            2 :         writeWithNotifyWr.sg_list = &sgList;
    1094            2 :         CHK_RET(PrepareWriteWrResource(
    1095              :             static_cast<char*>(tailDst) + offset, static_cast<const char*>(tailSrc) + offset, wrLen, remoteNotifyIdx,
    1096              :             writeWithNotifyWr, taskParam));
    1097            1 :         CHK_RET(PostAndCheckSend(qpInfo[i].qp, i, __func__, writeWithNotifyWr));
    1098            1 :         HCCL_INFO(
    1099              :             "[HostCpuRoceChannel::%s] SUCCESS. qp[%u], wrlen[0x%llx], newWqe[%u], wqeNums_[%u].", __func__, i, wrLen,
    1100              :             wqeNums_[i] - wqeNumBefore[i], wqeNums_[i]);
    1101              :     }
    1102            1 :     fenceFlag_ = false;
    1103            1 :     taskParam.endTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
    1104            1 :     if (dfxCallback_ != nullptr) {
    1105            0 :         return dfxCallback_(taskParam, reinterpret_cast<u64>(this));
    1106              :     }
    1107              : 
    1108            1 :     return HCCL_SUCCESS;
    1109            2 : }
    1110              : 
    1111            2 : void HostCpuRoceChannel::BuildRdmaWr(
    1112              :     [[maybe_unused]] const char* caller, ibv_wr_opcode opcode, void* localAddr, const void* remoteAddr, uint64_t len,
    1113              :     size_t localIdx, size_t rmtIdx, struct ibv_send_wr& wr, struct ibv_sge& sg) const
    1114              : {
    1115            2 :     wr.sg_list = &sg;
    1116            2 :     wr.sg_list->addr = reinterpret_cast<uint64_t>(localAddr);
    1117            2 :     wr.sg_list->length = static_cast<uint32_t>(len);
    1118            2 :     wr.sg_list->lkey = localRmaBuffers_[localIdx]->GetLkey();
    1119              : 
    1120            2 :     wr.opcode = opcode;
    1121            2 :     wr.send_flags = (fenceFlag_ == true ? (IBV_SEND_SIGNALED | IBV_SEND_FENCE) : IBV_SEND_SIGNALED);
    1122            2 :     wr.next = nullptr;
    1123            2 :     wr.num_sge = 1;
    1124            2 :     wr.wr_id = 0;
    1125            2 :     wr.wr.rdma.rkey = rmtRmaBuffers_[rmtIdx]->GetRkey();
    1126            2 :     wr.wr.rdma.remote_addr = reinterpret_cast<uint64_t>(remoteAddr);
    1127            2 : }
    1128              : 
    1129              : HcclResult
    1130            0 : HostCpuRoceChannel::PostAndCheckSend(struct ibv_qp* qp, uint32_t qpIdx, const char* caller, struct ibv_send_wr& wr)
    1131              : {
    1132            0 :     struct ibv_send_wr* badWr = nullptr;
    1133            0 :     s32 ret = ibv_post_send(qp, &wr, &badWr);
    1134            0 :     if (ret != 0 && badWr == nullptr) {
    1135            0 :         HCCL_ERROR("[HostCpuRoceChannel::%s] ibv_post_send failed while badWr is nullptr", caller);
    1136            0 :         return HCCL_E_INTERNAL;
    1137              :     }
    1138            0 :     CHK_PRT_RET(
    1139              :         ret == ENOMEM,
    1140              :         HCCL_WARNING(
    1141              :             "[HostCpuRoceChannel::%s] post send wqe overflow. ret:%d, "
    1142              :             "badWr->wr_id[%llu], badWr->sg_list->addr[%llu], badWr->wr.rdma.remote_addr[%llu], "
    1143              :             "badWr->wr.ud.remote_qpn[%u]",
    1144              :             caller, ret, badWr->wr_id, badWr->sg_list->addr, badWr->wr.rdma.remote_addr, badWr->wr.ud.remote_qpn),
    1145              :         HCCL_E_AGAIN);
    1146            0 :     CHK_PRT_RET(
    1147              :         ret != 0,
    1148              :         HCCL_ERROR(
    1149              :             "[HostCpuRoceChannel::%s] ibv_post_send failed. ret:%d, "
    1150              :             "badWr->wr_id[%llu], badWr->sg_list->addr[%llu], badWr->wr.rdma.remote_addr[%llu], "
    1151              :             "badWr->wr.ud.remote_qpn[%u]",
    1152              :             caller, ret, badWr->wr_id, badWr->sg_list->addr, badWr->wr.rdma.remote_addr, badWr->wr.ud.remote_qpn),
    1153              :         HCCL_E_NETWORK);
    1154            0 :     CHK_PRT_RET(
    1155              :         wqeNums_[qpIdx] == INT32_MAX,
    1156              :         HCCL_ERROR("[HostCpuRoceChannel::%s] wqeNums_[%u] has reached the maximum value of uint32_t.", caller, qpIdx),
    1157              :         HCCL_E_INTERNAL);
    1158            0 :     wqeNums_[qpIdx]++;
    1159            0 :     return HCCL_SUCCESS;
    1160              : }
    1161              : 
    1162            2 : HcclResult HostCpuRoceChannel::PostRdmaOp(
    1163              :     const char* caller, ibv_wr_opcode opcode, void* localAddr, const void* remoteAddr, const uint64_t len)
    1164              : {
    1165            2 :     HCCL_INFO(
    1166              :         "[HostCpuRoceChannel::%s] Slice START. localAddr[%p], remoteAddr[%p], len[0x%llx].", caller, localAddr,
    1167              :         remoteAddr, len);
    1168              : 
    1169            2 :     CHK_PRT_RET(
    1170              :         GetQpInfos().empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] qpInfos is Empty", caller), HCCL_E_ROCE_CONNECT);
    1171            2 :     CHK_PRT_RET(
    1172              :         localRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] localRmaBuffer is Empty", caller),
    1173              :         HCCL_E_ROCE_CONNECT);
    1174            2 :     CHK_PRT_RET(
    1175              :         rmtRmaBuffers_.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] rmtRmaBuffers is Empty", caller),
    1176              :         HCCL_E_ROCE_CONNECT);
    1177            2 :     if (len > maxMsgSize_) {
    1178            0 :         HCCL_WARNING(
    1179              :             "[HostCpuRoceChannel::%s] len[0x%llx] exceeds maxMsgSize_[0x%llx], caller should slice before posting.",
    1180              :             caller, len, maxMsgSize_);
    1181              :     }
    1182              : 
    1183              :     // 1. 查找 buffer 索引
    1184            2 :     auto startTime = std::chrono::steady_clock::now();
    1185            2 :     size_t localIdx = 0;
    1186            2 :     CHK_RET(FindLocalBuffer(reinterpret_cast<uint64_t>(localAddr), len, localIdx));
    1187            2 :     size_t rmtIdx = 0;
    1188            2 :     CHK_RET(FindRemoteBuffer(reinterpret_cast<uint64_t>(remoteAddr), len, rmtIdx));
    1189            2 :     auto endTime = std::chrono::steady_clock::now();
    1190            2 :     auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime).count();
    1191            2 :     HCCL_INFO("[HostCpuRoceChannel::%s] check buffer takes time [%lld]us", caller, elapsed);
    1192              : 
    1193              :     // 2. 构造 WR 并发送
    1194            2 :     std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
    1195            2 :     uint32_t useQpNum = qpInfo.size();
    1196            2 :     uint64_t tileLen = len / useQpNum;
    1197            2 :     uint64_t tileLenTail = len - (useQpNum - 1) * tileLen;
    1198            2 :     if ((tileLen != 0) && (tileLen < channelDesc_.roceAttr.qpThreshold)) {
    1199            0 :         useQpNum = (len - 1) / channelDesc_.roceAttr.qpThreshold
    1200            0 :                    + 1; // 自适应选择QP数发送数据,保证每个qp分担的数据量满足最小阈值
    1201            0 :         if (useQpNum > qpInfo.size()) {
    1202            0 :             useQpNum = qpInfo.size();
    1203              :         }
    1204            0 :         tileLen = len / useQpNum;
    1205            0 :         tileLenTail = len - (useQpNum - 1) * tileLen;
    1206            0 :         HCCL_INFO(
    1207              :             "[HostCpuRoceChannel::%s] The data allocated to each Qp (%u) is below the Qp Threshold (%u). "
    1208              :             "the count of Qp for data sending is adaptively adjusted to %u.",
    1209              :             __func__, tileLen, channelDesc_.roceAttr.qpThreshold, useQpNum);
    1210              :     }
    1211              : 
    1212              :     uint64_t wrLen, offset;
    1213            4 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
    1214            2 :         if (i < useQpNum - 1) {
    1215            0 :             wrLen = tileLen;
    1216            0 :             offset = tileLen * i;
    1217            2 :         } else if (i == useQpNum - 1) {
    1218            2 :             wrLen = tileLenTail;
    1219            2 :             offset = tileLen * i;
    1220              :         } else {
    1221            0 :             wrLen = 0;
    1222            0 :             offset = 0;
    1223              :         }
    1224              : 
    1225            2 :         struct ibv_send_wr wr {};
    1226              :         struct ibv_sge sg;
    1227            2 :         BuildRdmaWr(
    1228              :             caller, opcode, static_cast<char*>(localAddr) + offset, static_cast<const char*>(remoteAddr) + offset,
    1229              :             wrLen, localIdx, rmtIdx, wr, sg);
    1230            2 :         CHK_RET(PostAndCheckSend(qpInfo[i].qp, i, caller, wr));
    1231            2 :         HCCL_INFO(
    1232              :             "[HostCpuRoceChannel::%s] Slice SUCCESS. qp[%u] wrLen[0x%llx], wqeNums_[%u]=%d", caller, i, wrLen, i,
    1233              :             wqeNums_[i]);
    1234              :     }
    1235            2 :     fenceFlag_ = false;
    1236            2 :     return HCCL_SUCCESS;
    1237            2 : }
    1238              : 
    1239            5 : HcclResult HostCpuRoceChannel::Write(void* dst, const void* src, const uint64_t len)
    1240              : {
    1241            5 :     CHK_PRT_RET(
    1242              :         maxMsgSize_ == 0, HCCL_ERROR("[HostCpuRoceChannel::%s] maxMsgSize_ is 0, channel not initialized", __func__),
    1243              :         HCCL_E_INTERNAL);
    1244            4 :     HCCL_INFO("[HostCpuRoceChannel::%s] START. dst[%p], src[%p], len[0x%llx].", __func__, dst, src, len);
    1245            4 :     std::vector<int> wqeNumBefore = wqeNums_;
    1246            4 :     uint64_t offset = 0;
    1247            9 :     while (offset < len) {
    1248            6 :         uint64_t chunkLen = std::min(len - offset, maxMsgSize_);
    1249            6 :         CHK_RET(PostRdmaOp(
    1250              :             __func__, IBV_WR_RDMA_WRITE, static_cast<char*>(const_cast<void*>(src)) + offset,
    1251              :             static_cast<const char*>(dst) + offset, chunkLen));
    1252            5 :         offset += chunkLen;
    1253              :     }
    1254            3 :     HCCL_INFO(
    1255              :         "[HostCpuRoceChannel::%s] SUCCESS. len[0x%llx], newWqe[%d], wqeNums_[%d].", __func__, len,
    1256              :         wqeNums_[0] - wqeNumBefore[0], wqeNums_[0]);
    1257            3 :     return HCCL_SUCCESS;
    1258            4 : }
    1259              : 
    1260            3 : HcclResult HostCpuRoceChannel::Read(void* dst, const void* src, const uint64_t len)
    1261              : {
    1262            3 :     CHK_PRT_RET(
    1263              :         maxMsgSize_ == 0, HCCL_ERROR("[HostCpuRoceChannel::%s] maxMsgSize_ is 0, channel not initialized", __func__),
    1264              :         HCCL_E_INTERNAL);
    1265            2 :     HCCL_INFO("[HostCpuRoceChannel::%s] START. dst[%p], src[%p], len[0x%llx].", __func__, dst, src, len);
    1266            2 :     std::vector<int> wqeNumBefore = wqeNums_;
    1267            2 :     uint64_t offset = 0;
    1268            6 :     while (offset < len) {
    1269            4 :         uint64_t chunkLen = std::min(len - offset, maxMsgSize_);
    1270            4 :         CHK_RET(PostRdmaOp(
    1271              :             __func__, IBV_WR_RDMA_READ, static_cast<char*>(dst) + offset, static_cast<const char*>(src) + offset,
    1272              :             chunkLen));
    1273            4 :         offset += chunkLen;
    1274              :     }
    1275            2 :     HCCL_INFO(
    1276              :         "[HostCpuRoceChannel::%s] SUCCESS. len[0x%llx], newWqe[%d], wqeNums_[%d].", __func__, len,
    1277              :         wqeNums_[0] - wqeNumBefore[0], wqeNums_[0]);
    1278            2 :     return HCCL_SUCCESS;
    1279            2 : }
    1280              : 
    1281            2 : HcclResult HostCpuRoceChannel::FindLocalBuffer(const uint64_t addr, const uint64_t len, size_t& targetIdx) const
    1282              : {
    1283            2 :     uint64_t endAddr = addr + len;
    1284            2 :     HCCL_INFO(
    1285              :         "[HostCpuRoceChannel::%s] START. Finding buffer addr[0x%llx], len[0x%llx], addr+len[0x%llx].", __func__, addr,
    1286              :         len, endAddr);
    1287            2 :     for (size_t i = 0; i < localRmaBuffers_.size(); ++i) {
    1288            2 :         CHK_PTR_NULL(localRmaBuffers_[i]);
    1289            2 :         uint64_t bufAddr = localRmaBuffers_[i]->GetBufferInfo().first;
    1290            2 :         uint64_t bufSize = localRmaBuffers_[i]->GetBufferInfo().second;
    1291            2 :         uint64_t bufEndAddr = bufAddr + bufSize;
    1292            2 :         HCCL_INFO(
    1293              :             "[HostCpuRoceChannel::%s] Comparing with saved localRmaBuffer[%zu]: addr[0x%llx], len[0x%llx], "
    1294              :             "addr+len[0x%llx].",
    1295              :             __func__, i, bufAddr, bufSize, bufEndAddr);
    1296            2 :         if (addr >= bufAddr && endAddr <= bufEndAddr) {
    1297            2 :             targetIdx = i;
    1298            2 :             HCCL_INFO("[HostCpuRoceChannel::%s] SUCCESS. targetIdx[%zu]", __func__, targetIdx);
    1299            2 :             return HCCL_SUCCESS;
    1300              :         }
    1301              :     }
    1302            0 :     HCCL_ERROR(
    1303              :         "[HostCpuRoceChannel::%s] FAIL. Can not Found Target Buffer addr[0x%llx], len[0x%llx], addr+len[0x%llx].",
    1304              :         __func__, addr, len, endAddr);
    1305            0 :     return HCCL_E_NOT_FOUND;
    1306              : }
    1307              : 
    1308            2 : HcclResult HostCpuRoceChannel::FindRemoteBuffer(const uint64_t addr, const uint64_t len, size_t& targetIdx) const
    1309              : {
    1310            2 :     uint64_t endAddr = addr + len;
    1311            2 :     HCCL_INFO(
    1312              :         "[HostCpuRoceChannel::%s] START. Finding buffer addr[0x%llx], len[0x%llx], addr+len[0x%llx].", __func__, addr,
    1313              :         len, endAddr);
    1314            2 :     for (size_t i = 0; i < rmtRmaBuffers_.size(); ++i) {
    1315            2 :         CHK_PTR_NULL(rmtRmaBuffers_[i]);
    1316            2 :         uint64_t bufAddr = static_cast<uint64_t>(rmtRmaBuffers_[i]->GetAddr());
    1317            2 :         uint64_t bufSize = rmtRmaBuffers_[i]->GetSize();
    1318            2 :         uint64_t bufEndAddr = bufAddr + bufSize;
    1319            2 :         HCCL_INFO(
    1320              :             "[HostCpuRoceChannel::%s] Comparing with saved rmtRmaBuffers[%zu]: addr[0x%llx], len[0x%llx], "
    1321              :             "addr+len[0x%llx].",
    1322              :             __func__, i, bufAddr, bufSize, bufEndAddr);
    1323            2 :         if (addr >= bufAddr && endAddr <= bufEndAddr) {
    1324            2 :             targetIdx = i;
    1325            2 :             HCCL_INFO("[HostCpuRoceChannel::%s] SUCCESS. targetIdx[%zu]", __func__, targetIdx);
    1326            2 :             return HCCL_SUCCESS;
    1327              :         }
    1328              :     }
    1329            0 :     HCCL_ERROR(
    1330              :         "[HostCpuRoceChannel::%s] FAIL. Can not Found Target Buffer addr[0x%llx], len[0x%llx], addr+len[0x%llx].",
    1331              :         __func__, addr, len, endAddr);
    1332            0 :     return HCCL_E_NOT_FOUND;
    1333              : }
    1334              : 
    1335            3 : HcclResult HostCpuRoceChannel::WaitForFenceCompletion()
    1336              : {
    1337            3 :     const std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
    1338            3 :     CHK_PRT_RET(qpInfo.empty(), HCCL_ERROR("[HostCpuRoceChannel::%s] qpInfos is Empty", __func__), HCCL_E_ROCE_CONNECT);
    1339            3 :     uint32_t fenceCount = 0;
    1340            6 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
    1341            3 :         if (wqeNums_[i] == 0) {
    1342            1 :             fenceCount += 1;
    1343              :         }
    1344              :     }
    1345            3 :     if (fenceCount == qpInfo.size()) {
    1346            1 :         fenceFlag_ = true;
    1347            1 :         HCCL_INFO("[HostCpuRoceChannel::%s] SUCCESS. elements in wqeNums_ are 0.", __func__);
    1348            1 :         return HCCL_SUCCESS;
    1349              :     }
    1350              : 
    1351              :     auto timeout = std::chrono::milliseconds(
    1352            2 :         static_cast<uint64_t>(Hccl::EnvConfig::GetInstance().GetRtsConfig().GetExecTimeOut())
    1353            2 :         * 1000ULL); // 乘1000转为毫秒
    1354            2 :     for (uint32_t i = 0; i < qpInfo.size(); i++) {
    1355            2 :         std::vector<struct ibv_wc> wc(wqeNums_[i]);
    1356            2 :         CHK_PRT_RET(
    1357              :             qpInfo[i].sendCq == nullptr, HCCL_ERROR("[HostCpuRoceChannel::%s] qp[%u] sendCq is null", __func__, i),
    1358              :             HCCL_E_INTERNAL);
    1359            2 :         CHK_PRT_RET(
    1360              :             qpInfo[i].qp == nullptr, HCCL_ERROR("[HostCpuRoceChannel::%s] qp[%u] is null", __func__, i),
    1361              :             HCCL_E_INTERNAL);
    1362            2 :         CHK_PRT_RET(
    1363              :             qpInfo[i].sendCq->context == nullptr,
    1364              :             HCCL_ERROR("[HostCpuRoceChannel::%s] qp[%u] sendCq->context is null", __func__, i), HCCL_E_INTERNAL);
    1365              : 
    1366            2 :         auto startTime = std::chrono::steady_clock::now();
    1367              :         while (true) {
    1368            2 :             int actualNum = IbvPollCq(qpInfo[i].sendCq, wqeNums_[i], wc.data());
    1369            2 :             if (actualNum < 0) {
    1370            1 :                 HCCL_ERROR(
    1371              :                     "[HostCpuRoceChannel::%s] qp[%u] ibv_poll_cq failed. actualNum: %d.", __func__, i, actualNum);
    1372            1 :                 return HCCL_E_NETWORK;
    1373              :             }
    1374              : 
    1375            1 :             if (actualNum > wqeNums_[i]) {
    1376            1 :                 HCCL_ERROR(
    1377              :                     "[HostCpuRoceChannel::%s] qp[%u] ibv_poll_cq polled more completions (%d) than expected (%d).",
    1378              :                     __func__, i, actualNum, wqeNums_[i]);
    1379            1 :                 return HCCL_E_INTERNAL;
    1380            0 :             } else if (actualNum > 0) {
    1381            0 :                 for (int j = 0; j < actualNum; j++) {
    1382            0 :                     if (wc[j].status != IBV_WC_SUCCESS) {
    1383            0 :                         HCCL_ERROR(
    1384              :                             "[HostCpuRoceChannel::%s] ibv_poll_cq error. wc[%d] status[%d], opcode[%d], vendorErr[%u], "
    1385              :                             "byteLen[%u], wcFlags[%u], sl[%u]. qpInfo[%d].qp->qp_num[%u]",
    1386              :                             __func__, j, wc[j].status, wc[j].opcode, wc[j].vendor_err, wc[j].byte_len, wc[j].wc_flags,
    1387              :                             wc[j].sl, i, qpInfo[i].qp->qp_num);
    1388            0 :                         return HCCL_E_NETWORK;
    1389              :                     }
    1390              :                 }
    1391            0 :                 wqeNums_[i] -= actualNum; // 减去已经完成的数量,继续等待剩余的完成
    1392            0 :                 if (wqeNums_[i] == 0) {
    1393            0 :                     break; // 所有的wqe都已经完成,退出循环
    1394              :                 }
    1395            0 :                 startTime = std::chrono::steady_clock::now(); // 有进展,重置超时计时
    1396              :             }
    1397              : 
    1398            0 :             if ((std::chrono::steady_clock::now() - startTime) >= timeout) {
    1399            0 :                 HCCL_ERROR(
    1400              :                     "[HostCpuRoceChannel][%s] qp[%u] call ibv_poll_cq timeout, remaining wqeNum[%u].", __func__, i,
    1401              :                     wqeNums_[i]);
    1402            0 :                 return HCCL_E_TIMEOUT;
    1403              :             }
    1404            0 :         }
    1405            0 :         wqeNums_[i] = 0; // 所有的wqe都已经完成,重置计数器
    1406            0 :         HCCL_INFO("[HostCpuRoceChannel::%s] SUCCESS. wqeNums_[%u]=%d.", __func__, i, wqeNums_[i]);
    1407            2 :     }
    1408            0 :     fenceFlag_ = true;
    1409            0 :     return HCCL_SUCCESS;
    1410            3 : }
    1411              : 
    1412            3 : HcclResult HostCpuRoceChannel::ChannelFence()
    1413              : {
    1414            3 :     std::lock_guard<std::mutex> lock(sendCq_mutex);
    1415            3 :     Hccl::TaskParam taskParam{};
    1416            3 :     taskParam.beginTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
    1417            3 :     HCCL_INFO("[HostCpuRoceChannel::%s] ChannelFence start, wqeNums_[0]=%d", __func__, wqeNums_[0]);
    1418            3 :     HcclResult ret = WaitForFenceCompletion();
    1419            3 :     if (ret != HCCL_SUCCESS) {
    1420            2 :         return ret;
    1421              :     }
    1422              : 
    1423            1 :     taskParam.taskType = Hccl::TaskParamType::TASK_DPU_CHANNEL_FENCE;
    1424            1 :     taskParam.taskPara.Notify.notifyID = INVALID_U64;
    1425            1 :     taskParam.taskPara.Notify.value = 1;
    1426            1 :     taskParam.endTime = hccl::DlProfFunction::GetInstance().dlMsprofSysCycleTime();
    1427            1 :     if (dfxCallback_ != nullptr) {
    1428            0 :         return dfxCallback_(taskParam, reinterpret_cast<u64>(this));
    1429              :     }
    1430            1 :     return HCCL_SUCCESS;
    1431            3 : }
    1432              : 
    1433            1 : HcclResult HostCpuRoceChannel::GetNotifyNum(uint32_t* notifyNum) const
    1434              : {
    1435            1 :     CHK_PTR_NULL(notifyNum);
    1436            1 :     *notifyNum = notifyNum_;
    1437            1 :     return HCCL_SUCCESS;
    1438              : }
    1439              : 
    1440            1 : HcclResult HostCpuRoceChannel::GetHcclBuffer(void*& addr, uint64_t& size)
    1441              : {
    1442            1 :     if (rmtRmaBuffers_.empty()) {
    1443            0 :         HCCL_ERROR(
    1444              :             "[HostCpuRoceChannel::%s] remote buffer is empty, please check if channel complete exchange data",
    1445              :             __func__);
    1446            0 :         return HCCL_E_INTERNAL;
    1447              :     }
    1448            1 :     addr = reinterpret_cast<void*>(rmtRmaBuffers_[0]->GetAddr());
    1449            1 :     size = static_cast<uint64_t>(rmtRmaBuffers_[0]->GetSize());
    1450            1 :     return HCCL_SUCCESS;
    1451              : }
    1452              : 
    1453            0 : HcclResult HostCpuRoceChannel::Clean() { return HCCL_SUCCESS; }
    1454              : 
    1455            0 : HcclResult HostCpuRoceChannel::Resume() { return HCCL_SUCCESS; }
    1456              : 
    1457              : constexpr u32 DEFAULT_LOCAL_NOTIFY_ACCESS = 7;
    1458              : constexpr u32 DEFAULT_LOCAL_NOTIFY_SIZE = 4;
    1459            9 : HcclResult HostCpuRoceChannel::CreateNotifyHybird(hccl::MemType notifyType, uint32_t notifyId)
    1460              : {
    1461            9 :     localNotifyAccess_ = DEFAULT_LOCAL_NOTIFY_ACCESS;
    1462            9 :     localNotifySize_ = DEFAULT_LOCAL_NOTIFY_SIZE;
    1463              : 
    1464            9 :     int8_t* ptr = new (std::nothrow) int8_t[localNotifySize_];
    1465            9 :     CHK_PTR_NULL(ptr);
    1466              : 
    1467            9 :     if (memset_s(ptr, localNotifySize_, 0, localNotifySize_) < 0) {
    1468            0 :         HCCL_ERROR("[HostCpuRoceChannel::CreateNotifyHybird] memset_s failed");
    1469            0 :         delete[] ptr;
    1470            0 :         return HCCL_E_MEMORY;
    1471              :     }
    1472              : 
    1473            9 :     struct MrInfoT mrInfo = {};
    1474            9 :     mrInfo.addr = ptr;
    1475            9 :     mrInfo.size = localNotifySize_;
    1476            9 :     mrInfo.access = localNotifyAccess_;
    1477            9 :     auto qpInfo = connections_[0]->GetQpInfo();
    1478            9 :     if (HrtRaMrReg(qpInfo.qpHandle, &mrInfo) != HCCL_SUCCESS) {
    1479            1 :         HCCL_ERROR("[HostCpuRoceChannel::CreateNotifyHybird] MrReg failed");
    1480            1 :         delete[] ptr;
    1481            1 :         return HCCL_E_MEMORY;
    1482              :     }
    1483              : 
    1484            8 :     localMemMsg_[notifyType].addr = ptr;
    1485            8 :     localMemMsg_[notifyType].lkey = mrInfo.lkey;
    1486            8 :     localMemMsg_[notifyType].memType = notifyType;
    1487            8 :     localMemMsg_[notifyType].len = localNotifySize_;
    1488            8 :     localMemMsg_[notifyType].notifyId = notifyId;
    1489              : 
    1490            8 :     return HCCL_SUCCESS;
    1491              : }
    1492              : 
    1493            2 : HcclResult HostCpuRoceChannel::CreateNotifyValueBufferHybird()
    1494              : {
    1495            2 :     if (CreateNotifyHybird(hccl::MemType::NOTIFY_SRC_MEM, hccl::MemType::NOTIFY_SRC_MEM) != HCCL_SUCCESS) {
    1496            0 :         HCCL_ERROR(
    1497              :             "[HostCpuRoceChannel::CreateNotifyValueBufferHybird]Create host notify fail, type=%d",
    1498              :             hccl::MemType::NOTIFY_SRC_MEM);
    1499            0 :         return HCCL_E_MEMORY;
    1500              :     }
    1501            2 :     *reinterpret_cast<uint32_t*>(localMemMsg_[hccl::MemType::NOTIFY_SRC_MEM].addr) = 1;
    1502            2 :     return HCCL_SUCCESS;
    1503              : }
    1504              : 
    1505              : HcclResult
    1506            4 : HostCpuRoceChannel::CreateNotifyBufferHybird(hccl::MemType notifyType, uint32_t notifyId, u8*& data, u64& size)
    1507              : {
    1508            4 :     if (CreateNotifyHybird(notifyType, notifyId) != HCCL_SUCCESS) {
    1509            0 :         HCCL_ERROR("[HostCpuRoceChannel::CreateNotifyBufferHybird]Create host notify buffer fail, type=%d", notifyType);
    1510            0 :         return HCCL_E_MEMORY;
    1511              :     }
    1512              : 
    1513            4 :     CHK_SAFETY_FUNC_RET(memcpy_s(data, size, reinterpret_cast<void*>(&localMemMsg_[notifyType]), sizeof(hccl::MemMsg)));
    1514              : 
    1515            4 :     data += sizeof(hccl::MemMsg);
    1516            4 :     size -= sizeof(hccl::MemMsg);
    1517              : 
    1518            4 :     return HCCL_SUCCESS;
    1519              : }
    1520              : 
    1521            2 : HcclResult HostCpuRoceChannel::ExchangeCapability()
    1522              : {
    1523            2 :     HCCL_INFO("[Hybrid][HostCpuRoceChannel] Starting capability exchange");
    1524              : 
    1525              :     // 1. 构造本地能力信息(使用公共头文件中的默认值)
    1526              :     RoCECapability localCap;
    1527            2 :     localCap.InitDefaults();
    1528            2 :     localCap.nicDeploy = NICDeployment::NIC_DEPLOYMENT_HOST;
    1529            2 :     localCap.commStack = CommStackType::COMM_STACK_HOST_CPU_ROCE;
    1530              : 
    1531              :     // 2. 发送本地能力(合并为单次发送:totalLength已包含结构体大小)
    1532            2 :     CHK_PRT_RET(
    1533              :         !socket_->Send(&localCap, sizeof(localCap)),
    1534              :         HCCL_ERROR("[HostCpuRoceChannel::%s] Send exchange localCap failed", __func__), HCCL_E_NETWORK);
    1535            2 :     HCCL_INFO("[Hybrid][HostCpuRoceChannel] Sent capability, version=%u", localCap.version);
    1536              : 
    1537              :     // 3. 接收对端能力(单次接收)
    1538              :     RoCECapability recvCap;
    1539            2 :     CHK_PRT_RET(
    1540              :         !socket_->Recv(&recvCap, sizeof(recvCap)), HCCL_ERROR("[HostCpuRoceChannel::%s] Recv recvCap failed", __func__),
    1541              :         HCCL_E_NETWORK);
    1542            2 :     HCCL_INFO("[Hybrid][HostCpuRoceChannel] recvCap success");
    1543              : 
    1544              :     // 4. 先检查魔数,如果不对可能是旧版本,需要回退
    1545            2 :     if (!RoCECapability::CheckMagic(reinterpret_cast<uint8_t*>(&recvCap), sizeof(recvCap))) {
    1546            1 :         HCCL_WARNING("[Hybrid][HostCpuRoceChannel] Magic mismatch, peer may be old version. "
    1547              :                      "Falling back to native mode.");
    1548              :         // 回退到原生模式
    1549            1 :         isHybridMode_ = false;
    1550              :         // 标记为"跳过混合模式协商",后续流程继续使用原生模式
    1551            1 :         remoteCap_.magic = 0; // 标记为无效
    1552            1 :         return HCCL_SUCCESS;
    1553              :     }
    1554              : 
    1555              :     // 5. 魔数正确,解析对端能力
    1556            1 :     if (!remoteCap_.Deserialize(reinterpret_cast<uint8_t*>(&recvCap), sizeof(recvCap))) {
    1557            0 :         HCCL_ERROR("[Hybrid][HostCpuRoceChannel] Failed to deserialize capability");
    1558            0 :         return HCCL_E_PARA;
    1559              :     }
    1560              : 
    1561              :     // 6. 校验字段有效性
    1562            1 :     if (!remoteCap_.Validate()) {
    1563            0 :         HCCL_ERROR("[Hybrid][HostCpuRoceChannel] Capability validation failed");
    1564            0 :         return HCCL_E_INTERNAL;
    1565              :     }
    1566              : 
    1567              :     // 7. 版本兼容性处理(高版本兼容低版本)
    1568            1 :     if (remoteCap_.version > ROCE_CAPABILITY_VERSION) {
    1569              :         // 对端版本更高,使用本地版本的功能集(最小公分母)
    1570            0 :         HCCL_INFO(
    1571              :             "[Hybrid][HostCpuRoceChannel] Remote version %u > local %u, using local version features",
    1572              :             remoteCap_.version, ROCE_CAPABILITY_VERSION);
    1573            1 :     } else if (remoteCap_.version < ROCE_CAPABILITY_VERSION) {
    1574              :         // 对端版本更低,使用对端版本的功能集(向下兼容)
    1575            0 :         HCCL_INFO(
    1576              :             "[Hybrid][HostCpuRoceChannel] Remote version %u < local %u, using remote version features",
    1577              :             remoteCap_.version, ROCE_CAPABILITY_VERSION);
    1578              :     }
    1579              : 
    1580            1 :     isHybridMode_ = (remoteCap_.commStack == CommStackType::COMM_STACK_TRANSPORT_IBVERBS) ? true : false;
    1581              : 
    1582            1 :     HCCL_INFO(
    1583              :         "[Hybrid][HostCpuRoceChannel] Capability exchange success, "
    1584              :         "remote commStack=%u, version=%u, mode=%s",
    1585              :         static_cast<uint8_t>(remoteCap_.commStack), remoteCap_.version, isHybridMode_ ? "hybrid" : "normal");
    1586            1 :     return HCCL_SUCCESS;
    1587              : }
    1588              : 
    1589              : constexpr u32 DEFAULT_MRINFO_ACCESS = 7;
    1590            1 : HcclResult HostCpuRoceChannel::RegisterUserMemHybird()
    1591              : {
    1592            1 :     struct MrInfoT mrInfo = {};
    1593            1 :     mrInfo.addr = reinterpret_cast<void*>(localRmaBuffers_[0]->GetAddr());
    1594            1 :     mrInfo.size = localRmaBuffers_[0]->GetSize();
    1595            1 :     mrInfo.access = DEFAULT_MRINFO_ACCESS;
    1596            1 :     auto qpInfo = connections_[0]->GetQpInfo();
    1597            1 :     CHK_RET(HrtRaMrReg(qpInfo.qpHandle, &mrInfo));
    1598              : 
    1599            1 :     localMemMsg_[hccl::USER_OUTPUT_MEM].addr = reinterpret_cast<void*>(localRmaBuffers_[0]->GetAddr());
    1600            1 :     localMemMsg_[hccl::USER_OUTPUT_MEM].lkey = mrInfo.lkey;
    1601            1 :     localMemMsg_[hccl::USER_OUTPUT_MEM].memType = hccl::USER_OUTPUT_MEM;
    1602            1 :     localMemMsg_[hccl::USER_OUTPUT_MEM].len = localRmaBuffers_[0]->GetSize();
    1603            1 :     localMemMsg_[hccl::USER_OUTPUT_MEM].notifyId = INVALID_DPU_NOTIFY_ID;
    1604              : 
    1605            1 :     return HCCL_SUCCESS;
    1606              : }
    1607              : 
    1608              : constexpr u32 BUFFER_NUM = 2; // output、input buffer
    1609              : constexpr u32 NOTIFY_NUM = 3; // 3个Notify
    1610            3 : HcclResult HostCpuRoceChannel::BuildExchangeDataLengthHybird()
    1611              : {
    1612            3 :     exchangeDataTotalSize_ = 0;
    1613            3 :     exchangeDataTotalSize_ += sizeof(u32);                       // qp数量
    1614            3 :     exchangeDataTotalSize_ += sizeof(hccl::MemMsg) * BUFFER_NUM; // output、input buffer
    1615            3 :     exchangeDataTotalSize_ += sizeof(hccl::MemMsg) * NOTIFY_NUM; // 3个Notify
    1616            3 :     exchangeDataTotalSize_ += sizeof(u8);                        // atomic value
    1617            3 :     HCCL_INFO("[BuildExchangeDataLengthHybird]ExchangeDataSize:%ld", exchangeDataTotalSize_);
    1618            3 :     return HCCL_SUCCESS;
    1619              : }
    1620              : 
    1621              : constexpr u32 DATA_NOTIFY_ID = 1;     // DATA_NOTIFY_MEM类型使用的notifyId
    1622              : constexpr u32 ACK_NOTIFY_ID = 0;      // ACK_NOTIFY_MEM类型使用的notifyId
    1623              : constexpr u32 DATA_ACK_NOTIFY_ID = 2; // DATA_ACK_NOTIFY_MEM类型使用的notifyId
    1624            1 : HcclResult HostCpuRoceChannel::BuildExchangeDataHybird()
    1625              : {
    1626            1 :     CHK_RET(BuildExchangeDataLengthHybird());
    1627              : 
    1628            1 :     exchangeDataForSend_.resize(exchangeDataTotalSize_);
    1629              : 
    1630            1 :     u8* data = exchangeDataForSend_.data();
    1631            1 :     u64 size = exchangeDataTotalSize_;
    1632              : 
    1633            1 :     u32 qpNum = 1;
    1634            1 :     CHK_SAFETY_FUNC_RET(memcpy_s(data, size, reinterpret_cast<void*>(&qpNum), sizeof(u32)));
    1635            1 :     data += sizeof(u32);
    1636            1 :     size -= sizeof(u32);
    1637              : 
    1638            1 :     CHK_SAFETY_FUNC_RET(
    1639              :         memcpy_s(data, size, reinterpret_cast<void*>(&localMemMsg_[hccl::USER_OUTPUT_MEM]), sizeof(hccl::MemMsg)));
    1640            1 :     data += sizeof(hccl::MemMsg);
    1641            1 :     size -= sizeof(hccl::MemMsg);
    1642            1 :     CHK_SAFETY_FUNC_RET(
    1643              :         memcpy_s(data, size, reinterpret_cast<void*>(&localMemMsg_[hccl::USER_OUTPUT_MEM]), sizeof(hccl::MemMsg)));
    1644            1 :     data += sizeof(hccl::MemMsg);
    1645            1 :     size -= sizeof(hccl::MemMsg);
    1646              : 
    1647            1 :     CHK_RET(CreateNotifyValueBufferHybird());
    1648            1 :     CHK_RET(CreateNotifyBufferHybird(hccl::DATA_NOTIFY_MEM, DATA_NOTIFY_ID, data, size));
    1649            1 :     CHK_RET(CreateNotifyBufferHybird(hccl::ACK_NOTIFY_MEM, ACK_NOTIFY_ID, data, size));
    1650            1 :     CHK_RET(CreateNotifyBufferHybird(hccl::DATA_ACK_NOTIFY_MEM, DATA_ACK_NOTIFY_ID, data, size));
    1651              : 
    1652            1 :     u8 atomicWrite = 1;
    1653            1 :     CHK_SAFETY_FUNC_RET(memcpy_s(data, size, reinterpret_cast<void*>(&atomicWrite), sizeof(u8)));
    1654            1 :     data += sizeof(u8);
    1655            1 :     size -= sizeof(u8);
    1656              : 
    1657            1 :     if (size != 0) {
    1658            0 :         HCCL_ERROR("HostCpuRoceChannel::BuildExchangeDataHybird, failed to construct exchange data, size=%llu", size);
    1659            0 :         return HCCL_E_INTERNAL;
    1660              :     }
    1661              : 
    1662            1 :     return HCCL_SUCCESS;
    1663              : }
    1664              : 
    1665            6 : HcclResult HostCpuRoceChannel::GetRemoteAddrHybird(hccl::MemType memType, u8*& data, u64& size)
    1666              : {
    1667            6 :     CHK_SAFETY_FUNC_RET(
    1668              :         memcpy_s(&remoteMemMsg_[static_cast<u32>(memType)], sizeof(hccl::MemMsg), data, sizeof(hccl::MemMsg)));
    1669            6 :     data += sizeof(hccl::MemMsg);
    1670            6 :     size -= sizeof(hccl::MemMsg);
    1671            6 :     return HCCL_SUCCESS;
    1672              : }
    1673              : 
    1674            1 : HcclResult HostCpuRoceChannel::ParseRecvExchangeDataHybird()
    1675              : {
    1676            1 :     u8* data = exchangeDataForRecv_.data();
    1677            1 :     u64 size = exchangeDataTotalSize_;
    1678              : 
    1679            1 :     u32 remoteQpNum = 0;
    1680            1 :     CHK_SAFETY_FUNC_RET(memcpy_s(reinterpret_cast<void*>(&remoteQpNum), sizeof(u32), data, sizeof(u32)));
    1681            1 :     data += sizeof(u32);
    1682            1 :     size -= sizeof(u32);
    1683              : 
    1684            1 :     CHK_RET(GetRemoteAddrHybird(hccl::USER_OUTPUT_MEM, data, size));
    1685            1 :     CHK_RET(GetRemoteAddrHybird(hccl::USER_INPUT_MEM, data, size));
    1686            1 :     CHK_RET(GetRemoteAddrHybird(hccl::DATA_NOTIFY_MEM, data, size));
    1687            1 :     CHK_RET(GetRemoteAddrHybird(hccl::ACK_NOTIFY_MEM, data, size));
    1688            1 :     CHK_RET(GetRemoteAddrHybird(hccl::DATA_ACK_NOTIFY_MEM, data, size));
    1689              : 
    1690            1 :     data += sizeof(u8);
    1691            1 :     size -= sizeof(u8);
    1692              : 
    1693            1 :     if (size != 0) {
    1694            0 :         HCCL_ERROR("HostCpuRoceChannel::ParseRecvExchangeDataHybird: failed to parse exchange data, size=%lld", size);
    1695            0 :         return HCCL_E_INTERNAL;
    1696              :     }
    1697              : 
    1698              :     Hccl::ExchangeRdmaBufferDto dto(
    1699            2 :         (u64)remoteMemMsg_[static_cast<u32>(hccl::USER_OUTPUT_MEM)].addr,
    1700            1 :         remoteMemMsg_[static_cast<u32>(hccl::USER_OUTPUT_MEM)].len,
    1701            1 :         remoteMemMsg_[static_cast<u32>(hccl::USER_OUTPUT_MEM)].lkey, "HcclBuffer");
    1702            1 :     rmtRmaBuffers_.push_back(std::make_unique<Hccl::RemoteRdmaRmaBuffer>(rdmaHandle_, dto));
    1703              : 
    1704            1 :     return HCCL_SUCCESS;
    1705            1 : }
    1706              : 
    1707              : constexpr u32 GET_QP_SLEEP_TIME = 1000;
    1708            1 : HcclResult HostCpuRoceChannel::ConnectSingleQpHybrid(std::function<bool()> needStop)
    1709              : {
    1710            1 :     auto qpInfo = connections_[0]->GetQpInfo();
    1711            1 :     bool hasSocket = (socket_ != nullptr);
    1712            1 :     if (!hasSocket) {
    1713            0 :         CHK_RET(SocketMgr::GetInstance(devicePhyId_).GetSocket(*socketConfig_, socket_));
    1714              :     }
    1715            1 :     CHK_RET(HrtRaQpConnectAsync(qpInfo.qpHandle, socket_->GetFdHandle(), needStop));
    1716              : 
    1717              :     // 查询QP建链是否成功
    1718            1 :     s32 qpStatus = 0;
    1719            1 :     s32 raRet = 0;
    1720            1 :     constexpr uint32_t timeoutSec = 120;
    1721            1 :     constexpr auto timeout = std::chrono::seconds(timeoutSec);
    1722            1 :     auto startTime = std::chrono::steady_clock::now();
    1723            1 :     HCCL_INFO("HostCpuRoceChannel: waiting for qp status ready...");
    1724              :     while (true) {
    1725            3 :         CHK_PRT_RET(needStop(), HCCL_ERROR("Terminating operation due to external request"), HCCL_E_INTERNAL);
    1726              : 
    1727            2 :         if ((std::chrono::steady_clock::now() - startTime) >= timeout) {
    1728            0 :             HCCL_ERROR("[Connect][Qp]get qp status timeout_=[%lld s], qp_status=[%d]", timeout, qpStatus);
    1729            0 :             if (!hasSocket) {
    1730            0 :                 SocketMgr::GetInstance(devicePhyId_).PutSocket(socketConfig_, socket_);
    1731              :             }
    1732            0 :             return HCCL_E_TIMEOUT;
    1733              :         }
    1734            2 :         raRet = hrtGetRaQpStatus(qpInfo.qpHandle, &qpStatus);
    1735            2 :         if ((!raRet) && (qpStatus == 1)) { // 为1时,qp 建链成功
    1736            0 :             HCCL_INFO("In link ibv, QP get status success.");
    1737            0 :             break;
    1738              :         } else {
    1739            2 :             SaluSleep(GET_QP_SLEEP_TIME);
    1740              :         }
    1741              :     }
    1742            0 :     if (!hasSocket) {
    1743            0 :         SocketMgr::GetInstance(devicePhyId_).PutSocket(socketConfig_, socket_);
    1744              :     }
    1745            0 :     return HCCL_SUCCESS;
    1746              : }
    1747              : 
    1748            5 : HcclResult HostCpuRoceChannel::ExchangeDataHybird()
    1749              : {
    1750            5 :     HCCL_INFO("[Hybrid] Starting hybrid data exchange");
    1751              : 
    1752            5 :     CHK_RET(RegisterUserMemHybird());
    1753              : 
    1754            4 :     CHK_RET(BuildExchangeDataHybird());
    1755              : 
    1756            3 :     CHK_PRT_RET(
    1757              :         !socket_->Send(exchangeDataForSend_.data(), exchangeDataTotalSize_),
    1758              :         HCCL_ERROR("[Hybrid] Send exchange data failed"), HCCL_E_NETWORK);
    1759              : 
    1760            2 :     exchangeDataForRecv_.resize(exchangeDataTotalSize_);
    1761            2 :     CHK_PRT_RET(
    1762              :         !socket_->Recv(exchangeDataForRecv_.data(), exchangeDataTotalSize_),
    1763              :         HCCL_ERROR("[Hybrid] Recv exchange data failed"), HCCL_E_NETWORK);
    1764              : 
    1765            1 :     CHK_RET(ParseRecvExchangeDataHybird());
    1766              : 
    1767            0 :     return HCCL_SUCCESS;
    1768              : }
    1769              : 
    1770              : constexpr u32 WQE_NUM_STEP = 2; // 增加步长
    1771            5 : HcclResult HostCpuRoceChannel::WriteWithNotifyHybrid(void* dst, const void* src, uint64_t len, uint32_t remoteNotifyIdx)
    1772              : {
    1773            5 :     CHK_PTR_NULL(src);
    1774            4 :     CHK_PTR_NULL(dst);
    1775            3 :     HCCL_INFO("[Hybrid] WriteWithNotifyHybrid start, len=%lu", len);
    1776              : 
    1777              :     // 参数校验
    1778            3 :     CHK_PRT_RET(localRmaBuffers_.empty(), HCCL_ERROR("[Hybrid] localRmaBuffer is Empty"), HCCL_E_ROCE_CONNECT);
    1779              : 
    1780            3 :     std::vector<Hccl::QpInfo> qpInfo = GetQpInfos();
    1781            3 :     CHK_PRT_RET(qpInfo.empty(), HCCL_ERROR("[Hybrid] qpInfos is Empty"), HCCL_E_ROCE_CONNECT);
    1782              : 
    1783              :     // 获取本地 buffer 信息
    1784            2 :     hccl::MemType type = NotifyIdToMemtypeHybird(remoteNotifyIdx);
    1785              : 
    1786              :     // 校验数据长度
    1787            2 :     CHK_PRT_RET(
    1788              :         len > localRmaBuffers_[0]->GetSize(),
    1789              :         HCCL_ERROR("[Hybrid] Data length %lu exceeds buffer size %lu", len, localRmaBuffers_[0]->GetSize()),
    1790              :         HCCL_E_PARA);
    1791              : 
    1792              :     // 构造发送 WR 链:数据 WR + Notify WR
    1793            0 :     struct ibv_send_wr dataWr {};
    1794            0 :     struct ibv_send_wr notifyWr {};
    1795            0 :     struct ibv_send_wr* badWr = nullptr;
    1796            0 :     struct ibv_sge dataSge {};
    1797            0 :     struct ibv_sge notifySge {};
    1798              : 
    1799              :     // 1. 数据 WR(RDMA Write)
    1800            0 :     dataSge.addr = reinterpret_cast<uint64_t>(src);
    1801            0 :     dataSge.length = len;
    1802            0 :     dataSge.lkey = localRmaBuffers_[0]->GetLkey();
    1803              : 
    1804            0 :     dataWr.wr_id = 0;
    1805            0 :     dataWr.opcode = IBV_WR_RDMA_WRITE;
    1806            0 :     dataWr.send_flags = IBV_SEND_SIGNALED; // 需要 CQE 确认完成
    1807            0 :     dataWr.sg_list = &dataSge;
    1808            0 :     dataWr.num_sge = 1;
    1809            0 :     dataWr.wr.rdma.remote_addr = reinterpret_cast<uint64_t>(dst);
    1810            0 :     dataWr.wr.rdma.rkey = rmtRmaBuffers_[0]->GetRkey();
    1811              : 
    1812              :     // 2. Notify WR(写入对端 TransportIbverbs 的 Notify 内存)
    1813            0 :     notifySge.addr = reinterpret_cast<uint64_t>(localMemMsg_[hccl::NOTIFY_SRC_MEM].addr);
    1814            0 :     notifySge.length = localMemMsg_[hccl::NOTIFY_SRC_MEM].len;
    1815            0 :     notifySge.lkey = localMemMsg_[hccl::NOTIFY_SRC_MEM].lkey; // 使用本地 buffer 的 lkey
    1816              : 
    1817            0 :     notifyWr.wr_id = 1;
    1818            0 :     notifyWr.opcode = IBV_WR_RDMA_WRITE;
    1819            0 :     notifyWr.send_flags = IBV_SEND_SIGNALED;
    1820            0 :     notifyWr.sg_list = &notifySge;
    1821            0 :     notifyWr.num_sge = 1;
    1822              :     // Notify 写入对端 hostNotifyAddr 的偏移位置
    1823            0 :     notifyWr.wr.rdma.remote_addr = reinterpret_cast<uint64_t>(remoteMemMsg_[type].addr);
    1824            0 :     notifyWr.wr.rdma.rkey = remoteMemMsg_[type].lkey;
    1825              : 
    1826              :     // 链接 WR 链:dataWr -> notifyWr
    1827            0 :     dataWr.next = &notifyWr;
    1828            0 :     notifyWr.next = nullptr;
    1829              : 
    1830              :     // 3. 下发 WR 链
    1831            0 :     int32_t ret = ibv_post_send(qpInfo[0].qp, &dataWr, &badWr);
    1832            0 :     CHK_PRT_RET(ret != 0, HCCL_ERROR("[Hybrid] ibv_post_send failed, ret=%d", ret), HCCL_E_NETWORK);
    1833              : 
    1834            0 :     wqeNums_[0] += WQE_NUM_STEP;
    1835              : 
    1836            0 :     HCCL_INFO("[Hybrid] WriteWithNotifyHybrid success");
    1837            0 :     return HCCL_SUCCESS;
    1838            3 : }
    1839              : 
    1840            2 : HcclResult HostCpuRoceChannel::NotifyWaitHybrid(uint32_t localNotifyIdx, uint32_t timeout)
    1841              : {
    1842            2 :     HCCL_INFO("[Hybrid] NotifyWaitHybrid start, idx=%u", localNotifyIdx);
    1843              : 
    1844            2 :     hccl::MemType type = NotifyIdToMemtypeHybird(localNotifyIdx);
    1845              : 
    1846              :     // 使用配置的超时时间和轮询间隔(timeOut单位为秒,默认30s)
    1847            2 :     uint32_t pollTimeout = (timeout == 0) ? DEFAULT_NOTIFY_WAIT_TIMEOUT_S : timeout;
    1848            2 :     uint32_t pollInterval = 1;
    1849              : 
    1850              :     // 使用原子操作读取 Notify 内存
    1851            2 :     std::atomic<uint32_t>* notifyAddr = reinterpret_cast<std::atomic<uint32_t>*>(localMemMsg_[type].addr);
    1852            2 :     const uint64_t expectedValue = 1;
    1853              : 
    1854            2 :     auto startTime = std::chrono::steady_clock::now();
    1855            2 :     auto waitTime = std::chrono::seconds(pollTimeout);
    1856              : 
    1857              :     while (true) {
    1858              :         // 使用原子操作读取,确保内存可见性
    1859        75564 :         if (notifyAddr->load(std::memory_order_acquire) == expectedValue) {
    1860              :             // 读取成功后清零,为下一次通知做准备
    1861            0 :             notifyAddr->store(0, std::memory_order_release);
    1862            0 :             HCCL_INFO("[Hybrid] NotifyWaitHybrid success");
    1863            0 :             return HCCL_SUCCESS;
    1864              :         }
    1865              : 
    1866              :         // 检查超时
    1867        37782 :         if ((std::chrono::steady_clock::now() - startTime) >= waitTime) {
    1868            2 :             HCCL_ERROR("[Hybrid] NotifyWaitHybrid timeout, notify idx:%d", localNotifyIdx);
    1869            2 :             return HCCL_E_TIMEOUT;
    1870              :         }
    1871              : 
    1872        37780 :         SaluSleep(pollInterval);
    1873              :     }
    1874              : }
    1875              : 
    1876              : } // namespace hcomm
        

Generated by: LCOV version 2.0-1