LCOV - code coverage report
Current view: top level - legacy/ascend910/framework/common/src/topo - topoinfo_exchange_dispatcher.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 45.2 % 230 104
Test Date: 2026-08-18 17:47:01 Functions: 65.0 % 20 13

            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 <algorithm>
      12              : #include <cerrno>
      13              : #include <cmath>
      14              : #include <cstring>
      15              : #include <sys/socket.h>
      16              : #include <sys/epoll.h>
      17              : #include <unistd.h>
      18              : #include <ctime>
      19              : #include "sal_pub.h"
      20              : #include "topoinfo_exchange_dispatcher.h"
      21              : 
      22              : namespace hccl {
      23           16 : TopoInfoExchangeDispather::~TopoInfoExchangeDispather() { CleanResource(); }
      24              : 
      25           13 : HcclResult TopoInfoExchangeDispather::BroadcastRankTable(
      26              :     const std::map<std::string, std::shared_ptr<HcclSocket>> connectSockets, const RankTable_t& clusterInfo,
      27              :     const std::string& failedAgentIdList)
      28              : {
      29           13 :     CHK_RET(PrepareResource(connectSockets, clusterInfo, failedAgentIdList));
      30           13 :     CHK_RET(ProcessSend());
      31           13 :     HCCL_INFO(
      32              :         "cluster topo exchange worker broadcast topoinfo success, rankNum[%d], "
      33              :         "threadNum[%u]",
      34              :         rankNum_, threadNum_);
      35           13 :     return HCCL_SUCCESS;
      36              : }
      37              : 
      38            0 : HcclResult TopoInfoExchangeDispather::BroadcastGroupLeaderInfo(
      39              :     const std::map<std::string, std::shared_ptr<HcclSocket>> connectSockets, const GroupLeader_t& leaderInfo)
      40              : {
      41            0 :     CHK_RET(PrepareLeaderResource(connectSockets, leaderInfo));
      42            0 :     CHK_RET(ProcessSend());
      43            0 :     HCCL_INFO(
      44              :         "cluster topo exchange worker broadcast GroupLeaderInfo success, rankNum[%d], "
      45              :         "threadNum[%u]",
      46              :         rankNum_, threadNum_);
      47            0 :     return HCCL_SUCCESS;
      48              : }
      49              : 
      50           13 : void TopoInfoExchangeDispather::InitWorkerThread()
      51              : {
      52           13 :     threadNum_ = std::max(1, std::min(int(rankNum_ / RANK_CAPACITY_PER_THREAD), int(MAX_THREAD_NUM)));
      53           13 :     HCCL_INFO(
      54              :         "[TopoInfoExchangeDispather][InitWorkerThread]calculate threadNum[%u], rankNum[%d]", threadNum_, rankNum_);
      55           26 :     for (u32 i = 0; i < threadNum_; ++i) {
      56           13 :         auto th = std::thread(&TopoInfoExchangeDispather::RunWorkerThread, this, i);
      57           13 :         workerThreads_.emplace_back(std::move(th));
      58           13 :         HCCL_DEBUG("[TopoInfoExchangeDispather][InitWorkerThread]create thread[%u]", i);
      59           13 :     }
      60           13 : }
      61              : 
      62           13 : void TopoInfoExchangeDispather::WorkerWait(int workId)
      63              : {
      64           13 :     HCCL_DEBUG("[TopoInfoExchangeDispather][WorkerWait]start wait! workId[%d]", workId);
      65           13 :     std::unique_lock<std::mutex> lck(wakeMutex_);
      66           26 :     while (!ready_ && !stop_) {
      67           13 :         wakeManager_.wait(lck);
      68              :     }
      69           13 :     HCCL_DEBUG("[TopoInfoExchangeDispather][WorkerWait]finish wait! workId[%d]", workId);
      70           13 : }
      71              : 
      72           13 : bool TopoInfoExchangeDispather::GetTask(WorkerTask& workTask)
      73              : {
      74           13 :     auto& taskQueue = taskQueue_;
      75           13 :     std::unique_lock<std::mutex> lckForGetTask(taskQueueMutex_);
      76           13 :     if (taskQueue.empty()) {
      77           13 :         ready_ = false;
      78           13 :         return false;
      79              :     }
      80            0 :     workTask = taskQueue.front();
      81            0 :     taskQueue.pop();
      82            0 :     return true;
      83           13 : }
      84              : 
      85           13 : void TopoInfoExchangeDispather::RunWorkerThread(int workId)
      86              : {
      87              :     // 给当前线程添加名字
      88           13 :     SetThreadName("Hccl_RunWorker");
      89              : 
      90           26 :     while (!stop_) {
      91           13 :         WorkerWait(workId);
      92              :         while (true) {
      93           13 :             WorkerTask task;
      94           13 :             if (GetTask(task)) {
      95            0 :                 task();
      96              :             } else {
      97           13 :                 break;
      98              :             }
      99           13 :         }
     100              :     }
     101           13 :     HCCL_DEBUG("[TopoInfoExchangeDispather][RunWorkerThread]finish thread! workId[%d]", workId);
     102           13 : }
     103              : 
     104           13 : HcclResult TopoInfoExchangeDispather::PrepareResource(
     105              :     const std::map<std::string, std::shared_ptr<HcclSocket>> connectSockets, const RankTable_t& clusterInfo,
     106              :     const std::string& failedAgentIdList)
     107              : {
     108           13 :     rankNum_ = connectSockets.size();
     109           13 :     InitWorkerThread();
     110              : 
     111           13 :     HcclResult ret = hrtRaCreateEventHandle(epollFds_);
     112           13 :     if (ret != HCCL_SUCCESS) {
     113            0 :         HCCL_ERROR(
     114              :             "[TopoInfoExchangeDispather][PrepareEpollResource]hrtRaCreateEventHandle create"
     115              :             " epollFds_ failed, ret[%d]",
     116              :             ret);
     117            0 :         return HCCL_E_TCP_TRANSFER;
     118              :     }
     119              : 
     120           13 :     nlohmann::json basicJson;
     121           13 :     CHK_RET(topoInfoExchangeServer_->TopoInfoExchangeBase::Struct2Json(clusterInfo, basicJson));
     122           13 :     basicJson[PROP_STEP] = topoInfoExchangeServer_->TopoInfoExchangeBase::currentStep_;
     123           13 :     if (!failedAgentIdList.empty()) {
     124            0 :         basicJson["fault_info"] = "[" + failedAgentIdList + "]";
     125            0 :         basicJson["fault_type"] = static_cast<int>(TopoDetectResult::TOPO_CONNECT_FAILED);
     126              :     }
     127           13 :     rankTableJson_ = basicJson.dump();
     128              : 
     129           13 :     u32 socketIndex = 0; // socket已经经过rankid(or serverip +deviceid排序)
     130           13 :     for (auto it : connectSockets) {
     131            0 :         FdContext fdcontext;
     132            0 :         fdcontext.socket = it.second;
     133            0 :         if (topoInfoExchangeServer_->TopoInfoExchangeBase::isByMasterInfo_) { // masterInfo场景下无法获取rankid
     134            0 :             fdcontext.txState.identify = socketIndex;
     135              :         }
     136            0 :         fdcontext.txState.bodyLen = rankTableJson_.length();
     137            0 :         fdcontext.txState.data = &rankTableJson_[0];
     138            0 :         fdcontext.txState.rankId = socketIndex;
     139            0 :         socketIndex++;
     140            0 :         HCCL_DEBUG(
     141              :             "[TopoInfoExchangeDispather][PrepareResource]socketIndex:%u, bodyLen:%u, data:%u", socketIndex,
     142              :             fdcontext.txState.bodyLen, fdcontext.txState.data);
     143            0 :         fdHandleToFdContextMap_.emplace(it.second->GetFdHandle(), fdcontext);
     144            0 :     }
     145              : 
     146           13 :     HCCL_DEBUG(
     147              :         "[TopoInfoExchangeDispather][PrepareEpollResource]fdHandleToFdContextMap_ size[%d]",
     148              :         fdHandleToFdContextMap_.size());
     149           13 :     return HCCL_SUCCESS;
     150           13 : }
     151              : 
     152            0 : HcclResult TopoInfoExchangeDispather::PrepareLeaderResource(
     153              :     const std::map<std::string, std::shared_ptr<HcclSocket>> connectSockets, const GroupLeader_t& leaderInfo)
     154              : {
     155            0 :     rankNum_ = connectSockets.size();
     156            0 :     InitWorkerThread();
     157              : 
     158            0 :     HcclResult ret = hrtRaCreateEventHandle(epollFds_);
     159            0 :     if (ret != HCCL_SUCCESS) {
     160            0 :         HCCL_ERROR(
     161              :             "[TopoInfoExchangeDispather][PrepareEpollResource]hrtRaCreateEventHandle create"
     162              :             " epollFds_ failed, ret[%d]",
     163              :             ret);
     164            0 :         return HCCL_E_TCP_TRANSFER;
     165              :     }
     166              : 
     167            0 :     nlohmann::json basicJson;
     168            0 :     CHK_RET(topoInfoExchangeServer_->TopoInfoExchangeBase::GrpLeader2Json(leaderInfo, basicJson));
     169            0 :     basicJson[PROP_STEP] = topoInfoExchangeServer_->TopoInfoExchangeBase::currentStep_;
     170            0 :     rankTableJson_ = basicJson.dump();
     171              : 
     172            0 :     u32 socketIndex = 0; // socket已经经过rankid(or serverip +deviceid排序)
     173            0 :     for (auto it : connectSockets) {
     174            0 :         FdContext fdContext;
     175            0 :         fdContext.socket = it.second;
     176            0 :         if (topoInfoExchangeServer_->TopoInfoExchangeBase::isByMasterInfo_) { // masterInfo场景下无法获取rankid
     177            0 :             fdContext.txState.identify = socketIndex;
     178              :         }
     179            0 :         fdContext.txState.bodyLen = rankTableJson_.length();
     180            0 :         fdContext.txState.data = &rankTableJson_[0];
     181            0 :         fdContext.txState.rankId = socketIndex;
     182            0 :         socketIndex++;
     183            0 :         HCCL_DEBUG(
     184              :             "[TopoInfoExchangeDispather][PrepareLeaderResource]socketIndex:%u, bodyLen:%u, data:%u", socketIndex,
     185              :             fdContext.txState.bodyLen, fdContext.txState.data);
     186            0 :         fdHandleToFdContextMap_.emplace(it.second->GetFdHandle(), fdContext);
     187            0 :     }
     188              : 
     189            0 :     HCCL_DEBUG(
     190              :         "[TopoInfoExchangeDispather][PrepareEpollResource]fdHandleToFdContextMap_ size[%d]",
     191              :         fdHandleToFdContextMap_.size());
     192            0 :     return HCCL_SUCCESS;
     193            0 : }
     194              : 
     195           16 : void TopoInfoExchangeDispather::WakeWoker()
     196              : {
     197           16 :     std::unique_lock<std::mutex> lck(wakeMutex_);
     198           16 :     ready_ = true;
     199           16 :     wakeManager_.notify_all();
     200           16 : }
     201              : 
     202           16 : void TopoInfoExchangeDispather::CleanResource()
     203              : {
     204              :     // 主线程广播结束,结束从线程(不确定是否存在出于wait状态的线程,统一全部唤醒)
     205           16 :     stop_ = true;
     206           16 :     WakeWoker();
     207           16 :     HCCL_INFO("[TopoInfoExchangeDispather][PrepareEpollResource]wake all workers.");
     208           29 :     for (auto& th : workerThreads_) {
     209           13 :         if (th.joinable()) {
     210           13 :             th.join();
     211              :         }
     212              :     }
     213           16 :     fdHandleToFdContextMap_.clear();
     214           16 :     workerThreads_.clear();
     215           16 : }
     216              : 
     217           13 : HcclResult TopoInfoExchangeDispather::CloseEpollFd()
     218              : {
     219           13 :     HcclResult ret = hrtRaDestroyEventHandle(epollFds_);
     220           13 :     if (ret != HCCL_SUCCESS) {
     221            0 :         HCCL_ERROR(
     222              :             "[TopoInfoExchangeDispather][CloseEpollFd]DestroyEventHandle destroy "
     223              :             "epollFds_ failed, ret[%d]",
     224              :             ret);
     225            0 :         return HCCL_E_TCP_TRANSFER;
     226              :     }
     227           13 :     return HCCL_SUCCESS;
     228              : }
     229              : 
     230            0 : HcclResult TopoInfoExchangeDispather::ProcessOneSendEvent([[maybe_unused]] s32 epollFd, FdHandle& fdHandle)
     231              : {
     232            0 :     std::unique_lock<std::mutex> lckForMap(fdHandleMapMutex_);
     233            0 :     if (fdHandleToFdContextMap_.find(fdHandle) == fdHandleToFdContextMap_.end()) {
     234            0 :         HCCL_ERROR("[TopoInfoExchangeDispather][ProcessOneSendEvent]no fdhandle[%p]", fdHandle);
     235            0 :         stop_ = true;
     236            0 :         return HCCL_E_INTERNAL;
     237              :     }
     238            0 :     auto ctx = &(fdHandleToFdContextMap_.at(fdHandle));
     239            0 :     if (ctx->txState.Send(ctx->socket) != 0) {
     240            0 :         HCCL_ERROR(
     241              :             "[TopoInfoExchangeDispather][ProcessOneSendEvent]send data to rank[%u] failed.", ctx->txState.rankId);
     242            0 :         stop_ = true;
     243            0 :         return HCCL_E_INTERNAL;
     244              :     }
     245              : 
     246            0 :     int ctlType = EPOLL_CTL_DEL;
     247            0 :     if (ctx->txState.IsOk()) {
     248            0 :         sendDoneCount_++;
     249              :     } else {
     250            0 :         ctlType = EPOLL_CTL_MOD;
     251              :     }
     252              :     // EPOLLOUT_LET_ONESHOT -> EPOLLOUT | EPOLLET | EPOLLONESHOT, 防止多个线程同时操作同一个fd(fd重复触发)
     253            0 :     HcclResult ret = hrtRaCtlEventHandle(epollFds_, fdHandle, ctlType, HcclEpollEvent::HCCL_EPOLLOUT_LET_ONESHOT);
     254            0 :     if (ret != HCCL_SUCCESS) {
     255            0 :         HCCL_ERROR(
     256              :             "[TopoInfoExchangeDispather][ProcessOneSendEvent]epoll_ctl delete/modify "
     257              :             "failed, ctlType[%d]",
     258              :             ctlType);
     259            0 :         stop_ = true;
     260            0 :         return HCCL_E_INTERNAL;
     261              :     }
     262            0 :     return HCCL_SUCCESS;
     263            0 : }
     264              : 
     265           13 : HcclResult TopoInfoExchangeDispather::SendOnce()
     266              : {
     267              :     HcclResult ret;
     268           13 :     for (auto& it : fdHandleToFdContextMap_) {
     269            0 :         auto fdCtx = &(it.second);
     270            0 :         if (fdCtx->txState.Send(fdCtx->socket) != 0) {
     271            0 :             HCCL_ERROR("[TopoInfoExchangeDispather][SendOnce]Send data to rank[%u] failed.", fdCtx->txState.rankId);
     272            0 :             stop_ = true;
     273            0 :             return HCCL_E_INTERNAL;
     274              :         }
     275              : 
     276              :         // 数据未发送完成,添加epoll事件
     277            0 :         if (!fdCtx->txState.IsOk()) {
     278              :             // EPOLLOUT_LET_ONESHOT -> EPOLLOUT | EPOLLET | EPOLLONESHOT, 防止多个线程同时操作同一个fd(fd重复触发)
     279            0 :             ret = hrtRaCtlEventHandle(epollFds_, it.first, EPOLL_CTL_ADD, HcclEpollEvent::HCCL_EPOLLOUT_LET_ONESHOT);
     280            0 :             if (ret != HCCL_SUCCESS) {
     281            0 :                 HCCL_ERROR("[TopoInfoExchangeDispather][SendOnce]epoll_ctl add fd failed.");
     282            0 :                 stop_ = true;
     283            0 :                 return HCCL_E_INTERNAL;
     284              :             }
     285              :         } else {
     286            0 :             sendDoneCount_++;
     287              :         }
     288              :     }
     289           13 :     return HCCL_SUCCESS;
     290              : }
     291              : 
     292           13 : HcclResult TopoInfoExchangeDispather::ProcessSend()
     293              : {
     294           13 :     HcclResult ret = SendOnce(); // 先尝试发送数据
     295           13 :     CHK_RET(ret);
     296           26 :     HCCL_INFO(
     297              :         "[TopoInfoExchangeDispather][ProcessSend]sendOnce success, start epoll_wait."
     298              :         " sendDoneCount[%d], rankNum[%d].",
     299              :         sendDoneCount_.load(), rankNum_);
     300           13 :     const int sendEvsCount = 20; // epoll_wait 缓冲区大小(单次触发的事件个数)
     301           13 :     std::vector<SocketEventInfo> eventInfos(sendEvsCount);
     302           13 :     bool lastEpollWaitFlag = false; // 最后一轮epoll_wait标识位
     303           13 :     auto startTime = std::chrono::steady_clock::now();
     304           13 :     auto timeout = std::chrono::seconds(GetExternalInputHcclLinkTimeOut());
     305           13 :     while (sendDoneCount_ != rankNum_) {
     306            0 :         if (stop_) {
     307            0 :             return HCCL_E_INTERNAL;
     308              :         }
     309            0 :         if (rankNum_ - sendDoneCount_ < sendEvsCount && !lastEpollWaitFlag) { // 最后一轮epoll_wait
     310            0 :             lastEpollWaitFlag = true;
     311              :         }
     312            0 :         if ((std::chrono::steady_clock::now() - startTime) >= timeout) {
     313            0 :             HCCL_ERROR("[TopoInfoExchangeDispather][ProcessSend]epoll_wait timeout!");
     314            0 :             return HCCL_E_INTERNAL;
     315              :         }
     316            0 :         s32 epollTimeout = lastEpollWaitFlag ? LAST_EPOLL_TIMEOUT_MS : EPOLL_TIMEOUT_MS;
     317            0 :         u32 eventsNum{0};
     318            0 :         ret = hrtRaWaitEventHandle(epollFds_, eventInfos, epollTimeout, sendEvsCount, eventsNum);
     319            0 :         if (eventsNum == 0 && ret == HCCL_SUCCESS && sendDoneCount_ == rankNum_) {
     320              :             // 最后一轮epoll_wait结束, 等待超时,epoll池内无事件
     321            0 :             HCCL_WARNING(
     322              :                 "[TopoInfoExchangeDispather][ProcessSend]hrtRaWaitEventHandle is timeout[%d] ms, "
     323              :                 "eventsNum[%u], ret[%d], sendDoneCount_[%d]",
     324              :                 epollTimeout, eventsNum, ret, sendDoneCount_.load());
     325            0 :             return HCCL_SUCCESS;
     326              :         }
     327            0 :         if (eventsNum <= 0 && ret != HCCL_SUCCESS) {
     328            0 :             HCCL_ERROR(
     329              :                 "[TopoInfoExchangeDispather][ProcessSend]hrtRaWaitEventHandle failed, eventsNum[%u], "
     330              :                 "ret[%d]",
     331              :                 eventsNum, ret);
     332            0 :             return HCCL_E_INTERNAL;
     333              :         }
     334            0 :         for (u32 i = 0; i < eventsNum; ++i) {
     335            0 :             std::unique_lock<std::mutex> lck(taskQueueMutex_);
     336            0 :             taskQueue_.push(
     337            0 :                 std::bind(&TopoInfoExchangeDispather::ProcessOneSendEvent, this, epollFds_, eventInfos[i].fdHandle));
     338            0 :             lck.unlock();
     339            0 :         }
     340              :         // 唤醒处理
     341            0 :         WakeWoker();
     342              :     }
     343           13 :     CHK_RET(CloseEpollFd());
     344           13 :     return HCCL_SUCCESS;
     345           13 : }
     346              : 
     347            0 : HcclResult TopoInfoExchangeDispather::SendState::Send(std::shared_ptr<HcclSocket> socket)
     348              : {
     349            0 :     if (headerSended != headerLen) {
     350            0 :         header = bodyLen;
     351            0 :         CHK_RET(SendHeader(socket));
     352              :     }
     353              : 
     354            0 :     if ((headerSended == headerLen) && (bodyLen != bodySended)) {
     355            0 :         CHK_RET(SendBody(socket));
     356              :     }
     357              : 
     358            0 :     if ((headerSended == headerLen) && (bodyLen == bodySended)
     359            0 :         && (identify != UINT_MAX && identifyLen != identifySended)) {
     360            0 :         CHK_RET(SendIdentify(socket));
     361              :     }
     362              : 
     363            0 :     return HCCL_SUCCESS;
     364              : }
     365              : 
     366            0 : HcclResult TopoInfoExchangeDispather::SendState::SendHeader(std::shared_ptr<HcclSocket> socket)
     367              : {
     368            0 :     return SendHelper(socket, reinterpret_cast<char*>(&header), headerLen, headerSended);
     369              : }
     370              : 
     371            0 : HcclResult TopoInfoExchangeDispather::SendState::SendBody(std::shared_ptr<HcclSocket> socket)
     372              : {
     373            0 :     return SendHelper(socket, reinterpret_cast<char*>(data), bodyLen, bodySended);
     374              : }
     375              : 
     376            0 : HcclResult TopoInfoExchangeDispather::SendState::SendIdentify(std::shared_ptr<HcclSocket> socket)
     377              : {
     378            0 :     return SendHelper(socket, reinterpret_cast<char*>(&identify), identifyLen, identifySended);
     379              : }
     380              : 
     381            3 : HcclResult TopoInfoExchangeDispather::SendState::SendHelper(
     382              :     std::shared_ptr<HcclSocket> socket, char* buf, size_t dataLen, size_t& sendedLen)
     383              : {
     384            3 :     CHK_SMART_PTR_NULL(socket);
     385            3 :     CHK_PTR_NULL(buf);
     386            3 :     u64 needSend = dataLen - sendedLen;
     387            3 :     u64 sentSize = 0;
     388            3 :     HcclResult ret = socket->ISend(buf + sendedLen, needSend, sentSize);
     389            3 :     if (ret == HCCL_E_NETWORK) {
     390            1 :         HCCL_ERROR("[TopoInfoExchangeDispather][SendState][SendHelper]SendHelper fail error[%d].", ret);
     391            1 :         return HCCL_E_TCP_TRANSFER;
     392              :     }
     393            2 :     if (ret != HCCL_SUCCESS && ret != HCCL_E_AGAIN) {
     394            1 :         HCCL_ERROR("[TopoInfoExchangeDispather][SendState][SendHelper]socket send fail error[%d].", ret);
     395            1 :         return HCCL_E_INTERNAL;
     396              :     }
     397            1 :     if (ret == HCCL_SUCCESS) {
     398            1 :         sendedLen += sentSize;
     399              :     }
     400            1 :     return HCCL_SUCCESS;
     401              : }
     402              : 
     403              : } // namespace hccl
        

Generated by: LCOV version 2.0-1