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.7 % 1036 784
Test Date: 2026-07-28 12:11:00 Functions: 87.3 % 63 55

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

Generated by: LCOV version 2.0-1