LCOV - code coverage report
Current view: top level - legacy/ascend950/framework/topo/rank_info_detect - rank_info_dispatcher.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.4 % 157 145
Test Date: 2026-08-04 10:52:23 Functions: 100.0 % 17 17

            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 "rank_info_dispatcher.h"
      12              : 
      13              : #include <algorithm>
      14              : #include <cerrno>
      15              : #include <cmath>
      16              : #include <cstring>
      17              : #include <sys/socket.h>
      18              : #include <sys/epoll.h>
      19              : #include <unistd.h>
      20              : #include <ctime>
      21              : #include "sal.h"
      22              : #include "hccp.h"
      23              : #include "env_config.h"
      24              : #include "hccp_common.h"
      25              : #include "network_api_exception.h"
      26              : #include "adapter_error_manager_pub.h"
      27              : 
      28              : namespace Hccl {
      29              : 
      30           20 : RankInfoDispather::~RankInfoDispather()
      31              : {
      32           20 :     DECTOR_TRY_CATCH("RankInfoDispather", CleanResource());
      33           20 :     DECTOR_TRY_CATCH("RankInfoDispather", CloseEpollFd());
      34           20 : }
      35              : 
      36            1 : void RankInfoDispather::BroadcastRankTable(const std::unordered_map<std::string, std::shared_ptr<Socket>> &connectSockets,
      37              :     const RankTableInfo &clusterInfo, const std::string &failedAgentIdList, u32 step)
      38              : {
      39            1 :     PrepareResource(connectSockets, clusterInfo, failedAgentIdList, step);
      40            1 :     ProcessSend();
      41            3 :     HCCL_INFO("[RankInfoDispather::%s] broadcast topoinfo success, rankNum[%u], threadNum[%u]", __func__, rankNum_, threadNum_);
      42            1 : }
      43              : 
      44            1 : void RankInfoDispather::InitWorkerThread()
      45              : {
      46            1 :     threadNum_ = std::max(1, std::min(s32(rankNum_ / RANK_CAPACITY_PER_THREAD), s32(MAX_THREAD_NUM)));
      47            2 :     for (u32 i = 0; i < threadNum_; ++i) {
      48            1 :         auto th = std::thread(&RankInfoDispather::RunWorkerThread, this, i);
      49            1 :         workerThreads_.emplace_back(std::move(th));
      50            1 :     }
      51            3 :     HCCL_INFO("[RankInfoDispather::%s]calculate threadNum[%u], rankNum[%u]", __func__, threadNum_, rankNum_);
      52            1 : }
      53              : 
      54            1 : void RankInfoDispather::WorkerWait(s32 workId)
      55              : {
      56            3 :     HCCL_DEBUG("[RankInfoDispather::%s]start wait! workId[%d]", __func__, workId);
      57            1 :     std::unique_lock<std::mutex> lck(wakeMutex_);
      58            1 :     while (!ready_ && !stop_) {
      59            0 :         wakeManager_.wait(lck);
      60              :     }
      61            3 :     HCCL_DEBUG("[RankInfoDispather::%s]finish wait! workId[%d]", __func__, workId);
      62            1 : }
      63              : 
      64            1 : bool RankInfoDispather::GetTask(WorkerTask &workTask)
      65              : {
      66            1 :     auto &taskQueue = taskQueue_;
      67            1 :     std::unique_lock<std::mutex> lckForGetTask(taskQueueMutex_);
      68            1 :     if (taskQueue.empty()) {
      69            1 :         ready_ = false;
      70            1 :         return false;
      71              :     }
      72            0 :     workTask = taskQueue.front();
      73            0 :     taskQueue.pop();
      74            0 :     return true;
      75            1 : }
      76              : 
      77            1 : void RankInfoDispather::RunWorkerThread(s32 workId)
      78              : {
      79              :     // 给当前线程添加名字
      80            1 :     SetThreadName("Hccl_RunWorker");
      81              : 
      82            1 :     while (!stop_) {
      83            0 :         WorkerWait(workId);
      84              :         while (true) {
      85            0 :             WorkerTask task;
      86            0 :             if (GetTask(task)) {
      87            0 :                 task();
      88              :             } else {
      89            0 :                 break;
      90              :             }
      91            0 :         }
      92              :     }
      93            3 :     HCCL_DEBUG("[RankInfoDispather::%s]finish thread! workId[%d]", __func__, workId);
      94            1 : }
      95              : 
      96            2 : void RankInfoDispather::PrepareResource(const std::unordered_map<std::string, std::shared_ptr<Socket>> connectSockets,
      97              :     const RankTableInfo &clusterInfo, const std::string &failedAgentIdList, u32 step)
      98              : {
      99            2 :     rankNum_ = connectSockets.size();
     100            2 :     InitWorkerThread();
     101              : 
     102            2 :     s32 res = RaCreateEventHandle(&epollFds_);
     103            2 :     CHK_PRT_THROW(res != 0, HCCL_ERROR("[RankInfoDispather::%s] create epoll event failed, res[%d].", __func__, res),
     104              :                   NetworkApiException, "create epoll event error.");
     105            2 :     epollCreate_ = true;
     106              : 
     107            2 :     BinaryStream binaryStream;
     108            2 :     clusterInfo.GetBinStream(true, binaryStream);
     109            2 :     binaryStream << step;
     110            2 :     binaryStream << failedAgentIdList;
     111              :     
     112            2 :     binaryStream.Dump(rankTableMsg_);
     113              : 
     114            3 :     for (auto &it : connectSockets) {
     115            2 :         FdContext fdcontext;
     116            2 :         fdcontext.socket = it.second;
     117            2 :         fdcontext.txState.bodyLen = rankTableMsg_.size();
     118            2 :         fdcontext.txState.data = rankTableMsg_.data();
     119            3 :         CHK_RET_THROW(InvalidParamsException, 
     120              :             StringFormat("[RankInfoDispather::%s] ranid[%s] strToULong fail.", __func__, it.first.c_str()),
     121              :             SalStrToULong(it.first, HCCL_BASE_DECIMAL, fdcontext.txState.rankId));
     122            3 :         HCCL_DEBUG("[RankInfoDispather::%s]rankId:%u, bodyLen:%u", __func__, fdcontext.txState.rankId, fdcontext.txState.bodyLen);
     123            1 :         fdHandleToFdContextMap_.emplace(it.second->GetFdHandle(), fdcontext);
     124            2 :     }
     125              : 
     126            3 :     HCCL_INFO("[RankInfoDispather::%s]fdHandleToFdContextMap_ size[%d]", __func__, fdHandleToFdContextMap_.size());
     127            2 : }
     128              : 
     129       524746 : void RankInfoDispather::WakeWoker()
     130              : {
     131       524746 :     std::unique_lock<std::mutex> lck(wakeMutex_);
     132       524746 :     ready_ = true;
     133       524746 :     wakeManager_.notify_all();
     134       524746 : }
     135              : 
     136           21 : void RankInfoDispather::CleanResource()
     137              : {
     138              :     // 主线程广播结束,结束从线程(不确定是否存在出于wait状态的线程,统一全部唤醒)
     139           21 :     stop_ = true;
     140           21 :     WakeWoker();
     141           63 :     HCCL_INFO("[RankInfoDispather::%s]wake all workers.", __func__);
     142           22 :     for (auto &th : workerThreads_) {
     143            1 :         if (th.joinable()) {
     144            1 :             th.join();
     145              :         }
     146              :     }
     147           21 :     fdHandleToFdContextMap_.clear();
     148           21 :     workerThreads_.clear();
     149           21 : }
     150              : 
     151            4 : void RankInfoDispather::ProcessOneSendEvent(s32 epollFd, FdHandle &fdHanlde)
     152              : {
     153            4 :     std::unique_lock<std::mutex> lckForMap(fdHandleMapMutex_);
     154            7 :     CHK_PRT_RET_NULL(fdHandleToFdContextMap_.find(fdHanlde) == fdHandleToFdContextMap_.end(),
     155              :         stop_ = true;HCCL_ERROR("[RankInfoDispather::%s]no fdhandle[%p]", __func__, fdHanlde));
     156            3 :     auto ctx = &(fdHandleToFdContextMap_.at(fdHanlde));
     157            6 :     CHK_PRT_RET_NULL(!ctx->txState.Send(ctx->socket),
     158              :         stop_ = true;HCCL_ERROR("[RankInfoDispather::%s]send data to rank[%u] failed.", __func__, ctx->txState.rankId));
     159              : 
     160            2 :     s32 ctlType = EPOLL_CTL_DEL;
     161            2 :     if (ctx->txState.IsOk()) {
     162            1 :         sendDoneCount_++;
     163              :     } else {
     164            1 :         ctlType = EPOLL_CTL_MOD;
     165              :     }
     166              :     // EPOLLOUT_LET_ONESHOT -> EPOLLOUT | EPOLLET | EPOLLONESHOT, 防止多个线程同时操作同一个fd(fd重复触发)
     167            2 :     s32 ret = RaCtlEventHandle(epollFds_, fdHanlde, ctlType, RaEpollEvent::RA_EPOLLOUT_LET_ONESHOT);
     168            2 :     CHK_PRT_RET_NULL(ret != 0, stop_ = true;HCCL_ERROR("[RankInfoDispather::%s]epoll_ctl failed, ctlType[%d]", __func__, ctlType));
     169            4 : }
     170              : 
     171            3 : void RankInfoDispather::SendOnce()
     172              : {
     173            5 :     for (auto &it : fdHandleToFdContextMap_) {
     174            3 :         auto fdCtx = &(it.second);
     175            8 :         CHK_PRT_THROW(!fdCtx->txState.Send(fdCtx->socket),
     176              :             HCCL_ERROR("[RankInfoDispather::%s]Send data to rank[%u] failed.", __func__, fdCtx->txState.rankId),
     177              :             InvalidParamsException, "send data error.");
     178              : 
     179              :         // 数据未发送完成,添加epoll事件
     180            2 :         if (!fdCtx->txState.IsOk()) {
     181              :             // EPOLLOUT_LET_ONESHOT -> EPOLLOUT | EPOLLET | EPOLLONESHOT, 防止多个线程同时操作同一个fd(fd重复触发)
     182            1 :             s32 ret = RaCtlEventHandle(epollFds_, it.first, EPOLL_CTL_ADD, RaEpollEvent::RA_EPOLLOUT_LET_ONESHOT);
     183            1 :             CHK_PRT_THROW(ret != 0, HCCL_ERROR("[RankInfoDispather::%s]epoll_ctl add fd failed.", __func__),
     184              :                 InvalidParamsException, "send data error.");
     185              :         } else {
     186            1 :             sendDoneCount_++;
     187              :         }
     188              :     }
     189            2 : }
     190              : 
     191            2 : void RankInfoDispather::ProcessSend()
     192              : {
     193            2 :     SendOnce();  // 先尝试发送数据
     194            8 :     HCCL_INFO("[RankInfoDispather::%s]sendOnce success, start epoll_wait. sendDoneCount[%d], rankNum[%u].",
     195              :                 __func__, sendDoneCount_.load(), rankNum_);
     196            2 :     const s32 sendEvsCount = 20;  // epoll_wait 缓冲区大小(单次触发的事件个数)
     197            2 :     std::vector<SocketEventInfo> eventInfos(sendEvsCount);
     198            2 :     bool lastEpollWaitFlag = false;  // 最后一轮epoll_wait标识位
     199            2 :     auto timeout = std::chrono::seconds(EnvConfig::GetInstance().GetSocketConfig().GetLinkTimeOut());
     200            2 :     auto startTime = std::chrono::steady_clock::now();
     201              :     HcclResult ret;
     202       524729 :     while (sendDoneCount_ != rankNum_) {
     203       524729 :         CHK_PRT_THROW(stop_, HCCL_ERROR("[RankInfoDispather::%s] process stop.", __func__), InvalidParamsException, "process stop.");
     204              :         
     205       524729 :         if (rankNum_ - sendDoneCount_ < sendEvsCount && !lastEpollWaitFlag) {  // 最后一轮epoll_wait
     206            2 :             lastEpollWaitFlag = true;
     207              :         }
     208              : 
     209              :         //循环超时
     210       524729 :         if ((std::chrono::steady_clock::now() - startTime) >= timeout) {
     211            3 :             HCCL_ERROR("[RankInfoDispather::%s] epoll_wait timeout, timeout[%lld s].", __func__,
     212              :                 static_cast<long long>(timeout.count()));
     213            1 :             RPT_INPUT_ERR(true, "EI0015", std::vector<std::string>({"error_reason"}),
     214              :                 std::vector<std::string>({StringFormat("Receiving message from the root node timed out "
     215              :                     "Timeout was set to %lld seconds. Expected to send to %u nodes, completed %u nodes.",
     216              :                     static_cast<long long>(timeout.count()), rankNum_, sendDoneCount_.load())}));
     217            1 :             THROW<TimeoutException>("epoll_wait timeout");
     218              :         }
     219              :         
     220              :         // 等待epoll事件
     221       524728 :         s32 epollTimeout = lastEpollWaitFlag ? LAST_EPOLL_TIMEOUT_MS : EPOLL_TIMEOUT_MS;
     222       524728 :         u32 eventsNum{0};
     223       524728 :         ret = HrtRaWaitEventHandle(epollFds_, eventInfos, epollTimeout, sendEvsCount, eventsNum);
     224              : 
     225              :         // 最后一轮epoll_wait结束, 等待超时,epoll池内无事件
     226       524728 :         CHK_PRT_RET_NULL((eventsNum == 0 && ret == HCCL_SUCCESS && sendDoneCount_ == rankNum_),
     227              :             HCCL_WARNING("[RankInfoDispather::%s]hrtRaWaitEventHandle is timeout[%d] ms, eventsNum[%u], "
     228              :                          "sendDoneCount_[%d]", __func__, epollTimeout, eventsNum, sendDoneCount_.load()));
     229              :         
     230              :         // epoll wait事件失败
     231              :         // 可能出现ret==HCCL_SUCCESS但eventsNum==0的情况,属于正常情况,不报错退出,需要继续循环
     232       524733 :         CHK_PRT_THROW(ret != HCCL_SUCCESS, 
     233              :                       HCCL_ERROR("[RankInfoDispather::%s] HrtRaWaitEventHandle failed ret[%d], eventsNum[%u].", __func__, ret, eventsNum),
     234              :                       InvalidParamsException, "epoll_wait fail");
     235      1049454 :         for (u32 i = 0; i < eventsNum; ++i) {
     236       524727 :             std::unique_lock<std::mutex> lck(taskQueueMutex_);
     237       524727 :             taskQueue_.push(std::bind(&RankInfoDispather::ProcessOneSendEvent, this, epollFds_, static_cast<void*>(eventInfos[i].fdHandle)));
     238       524727 :             lck.unlock();
     239       524727 :         }
     240              :         // 唤醒处理
     241       524727 :         WakeWoker();
     242              :     }
     243              : 
     244            0 :     CloseEpollFd();
     245            0 :     HCCL_INFO("[RankInfoDispather::%s]ProcessSend success, sendDoneCount[%d], rankNum[%d].", __func__, sendDoneCount_.load(), rankNum_);
     246            2 : }
     247              : 
     248           20 : void RankInfoDispather::CloseEpollFd()
     249              : {
     250           20 :     if (epollCreate_) {
     251            2 :         s32 ret = RaDestroyEventHandle(&epollFds_);
     252            2 :         CHK_PRT_THROW(ret != 0, HCCL_ERROR("[RankInfoDispather::%s] destroy epoll event failed, res[%d].", __func__, ret),
     253              :                     NetworkApiException, "destroy epoll event error.");
     254            2 :         epollCreate_ = false;
     255              :     }
     256           20 : }
     257              : 
     258            3 : bool RankInfoDispather::SendState::Send(std::shared_ptr<Socket> socket)
     259              : {
     260            3 :     if (headerSended != headerLen) {
     261            2 :         header = bodyLen;
     262            5 :         CHK_PRT_RET(!SendHeader(socket), HCCL_ERROR("SendHeader error"), false);
     263              :     }
     264              : 
     265            2 :     if ((headerSended == headerLen) && (bodyLen != bodySended)) {
     266            1 :         CHK_PRT_RET(!SendBody(socket), HCCL_ERROR("SendBody error"), false);
     267              :     }
     268              : 
     269            2 :     return true;
     270              : }
     271              : 
     272            2 : bool RankInfoDispather::SendState::SendHeader(std::shared_ptr<Socket> socket)
     273              : {
     274            2 :     return SendHelper(socket, &header, headerLen, headerSended);
     275              : }
     276              : 
     277            1 : bool RankInfoDispather::SendState::SendBody(std::shared_ptr<Socket> socket)
     278              : {
     279            1 :     return SendHelper(socket, data, bodyLen, bodySended);
     280              : }
     281              : 
     282            5 : bool RankInfoDispather::SendState::SendHelper(
     283              :     std::shared_ptr<Socket> socket, void *buf, size_t dataLen, size_t &sendedLen)
     284              : {
     285            5 :     u64 needSend = dataLen - sendedLen;
     286            5 :     u64 sentSize = 0;
     287            5 :     u8 *sendData = static_cast<u8 *>(buf) + sendedLen;
     288           11 :     CHK_PRT_RET(!socket->ISend(sendData, needSend, sentSize), HCCL_ERROR("ISend fail"), false);
     289            3 :     sendedLen += sentSize;
     290            3 :     return true;
     291              : }
     292              : 
     293              : }  // namespace Hccl
        

Generated by: LCOV version 2.0-1