LCOV - code coverage report
Current view: top level - coll_communicator_mgr/resource_mgr/local/my_rank - exchange_info_mgr.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.8 % 189 164
Test Date: 2026-08-18 17:47:01 Functions: 100.0 % 10 10

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2026 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 "exchange_info_mgr.h"
      12              : #include "env_config/env_config_v2.h"
      13              : #include "rank_consistency_checker_v2.h"
      14              : #include "hcomm_res_defs.h"
      15              : #include "hcomm_channel.h"
      16              : #include "comm_engine_utils.h"
      17              : 
      18              : namespace hccl {
      19          232 : ExchangeInfoMgr::ExchangeInfoMgr() {}
      20              : 
      21          232 : ExchangeInfoMgr::~ExchangeInfoMgr()
      22              : {
      23          232 :     HCCL_INFO("[ExchangeInfoMgr][~ExchangeInfoMgr] CollCommConfigConsistency deinit");
      24          232 : }
      25              : 
      26            2 : HcclResult ExchangeInfoMgr::BatchExchangeAndCheckConsistency(
      27              :     const HcclChannelDesc* channelDescs, const std::vector<HcommChannelDesc>& hcommDescs, uint32_t channelNum,
      28              :     const std::vector<std::pair<u32, u32>>& newChannels, CollCommConfigConsistency& collCommConfigConsistency,
      29              :     CommEngine engine) const
      30              : {
      31            2 :     std::vector<Hccl::Socket*> sockets;
      32            2 :     std::vector<u32> remoteRanks;
      33            2 :     std::vector<HcommSocketRole> roles;
      34              : 
      35            2 :     if (channelNum == 0) {
      36            0 :         HCCL_INFO("[BatchExchangeAndCheckConsistency] channelNum is 0.");
      37            0 :         return HCCL_SUCCESS;
      38              :     }
      39              : 
      40            4 :     for (uint32_t i = 0; i < channelNum; i++) {
      41            2 :         u32 remoteRank = channelDescs[i].remoteRank;
      42            2 :         HcommSocket rawSocket = hcommDescs[i].socket;
      43            2 :         Hccl::Socket* socket = static_cast<Hccl::Socket*>(rawSocket);
      44            2 :         CHK_PRT_RET(
      45              :             socket == nullptr,
      46              :             HCCL_ERROR(
      47              :                 "[BatchExchangeAndCheckConsistency] socket is null for channel[%u] remoteRank[%u].", i, remoteRank),
      48              :             HCCL_E_INTERNAL);
      49            2 :         sockets.push_back(socket);
      50            2 :         remoteRanks.push_back(remoteRank);
      51            2 :         roles.push_back(hcommDescs[i].role);
      52              :     }
      53              : 
      54            2 :     bool isHostLoc = (channelDescs[0].localEndpoint.loc.locType == ENDPOINT_LOC_TYPE_HOST);
      55            2 :     HCCL_INFO(
      56              :         "[BatchExchangeAndCheckConsistency] isHostLoc[%d], engine[%s]", isHostLoc,
      57              :         GetEnumToString(GetCommEngineStatusStrMap(), engine).c_str());
      58              : 
      59              :     // host 网卡使用 Socket 同步收发接口
      60            2 :     if (isHostLoc) {
      61              :         // 校验HComm信息
      62            1 :         CHK_RET(CheckHcommInfo(channelDescs, hcommDescs, sockets, remoteRanks, roles, newChannels, false));
      63              :         // 交换HCCL算子信息
      64            1 :         CHK_RET(ExchangeUserInfo(sockets, remoteRanks, roles, collCommConfigConsistency));
      65              :     } else {
      66              :         // 校验HComm信息
      67            1 :         CHK_RET(CheckHcommInfo(channelDescs, hcommDescs, sockets, remoteRanks, roles, newChannels, true));
      68              :         // 交换HCCL算子信息
      69            1 :         CHK_RET(ExchangeUserInfoAsync(sockets, remoteRanks, roles, collCommConfigConsistency));
      70              :     }
      71            2 :     CHK_RET(collCommConfigConsistency.ResetExchangeInfo());
      72              : 
      73            2 :     return HCCL_SUCCESS;
      74            2 : }
      75              : 
      76            2 : HcclResult ExchangeInfoMgr::CheckHcommInfo(
      77              :     const HcclChannelDesc* channelDescs, const std::vector<HcommChannelDesc>& hcommDescs,
      78              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<u32>& remoteRanks,
      79              :     const std::vector<HcommSocketRole>& roles, const std::vector<std::pair<u32, u32>>& newChannels, bool isAsync) const
      80              : {
      81            2 :     s32 deviceLogicId = 0;
      82            2 :     (void)hrtGetDeviceRefresh(&deviceLogicId);
      83            2 :     auto& checker = RankConsistencyCheckerV2::GetInstance(deviceLogicId);
      84            2 :     u64 frameLenV2 = checker.GetCheckFrameLengthV2();
      85            2 :     std::vector<Hccl::Socket*> newSockets; // 新建链的
      86            2 :     std::vector<u32> newRemoteRanks;
      87            2 :     std::vector<HcommSocketRole> newRoles;
      88              : 
      89            4 :     for (const auto& newCh : newChannels) {
      90            2 :         u32 idx = newCh.first;
      91            2 :         u32 remoteRank = channelDescs[idx].remoteRank;
      92            2 :         HcommSocket rawSocket = hcommDescs[idx].socket;
      93            2 :         Hccl::Socket* socket = static_cast<Hccl::Socket*>(rawSocket);
      94            2 :         CHK_PRT_RET(
      95              :             socket == nullptr,
      96              :             HCCL_ERROR("[CheckHcommInfo] socket is null for channel[%u] remoteRank[%u].", idx, remoteRank),
      97              :             HCCL_E_INTERNAL);
      98            2 :         newSockets.push_back(socket);
      99            2 :         newRemoteRanks.push_back(remoteRank);
     100            2 :         newRoles.push_back(hcommDescs[idx].role);
     101              :     }
     102            2 :     if (newChannels.size() > 0) {
     103            2 :         checker.SetInconsistentCheckFirstDone(false);
     104              :     }
     105              :     // 只有rankConsistentState是first或者on时才进行hcomm信息校验
     106            2 :     int32_t mode = Hccl::EnvConfig::GetInstance().GetLogConfig().GetDfsConfig().rankConsistentState;
     107            2 :     bool isFirst = (mode == 0 && !checker.GetInconsistentCheckFirstDone()); // 0:first 1:on
     108            2 :     if (mode == 1 || isFirst) {
     109              :         // ====== 生成本端CheckFrameV2 ======
     110            2 :         CheckFrameV2 localFrame;
     111            2 :         CHK_RET(checker.GenerateCheckFrameV2(localFrame));
     112              : 
     113              :         // ====== 交换CheckFrameV2(定长,批量并发交换)======
     114            2 :         std::vector<CheckFrameV2> remoteFrames;
     115            2 :         u32 checkSocketSize = newSockets.size();
     116            2 :         if (isFirst) {
     117            2 :             remoteFrames.resize(newSockets.size());
     118            2 :             CHK_RET(BatchExchangeFixedData(
     119              :                 newSockets, newRemoteRanks, newRoles, reinterpret_cast<const u8*>(&localFrame),
     120              :                 static_cast<u32>(frameLenV2), reinterpret_cast<u8*>(remoteFrames.data()), static_cast<u32>(frameLenV2),
     121              :                 isAsync));
     122              :         } else {
     123            0 :             checkSocketSize = sockets.size();
     124            0 :             remoteFrames.resize(sockets.size());
     125            0 :             CHK_RET(BatchExchangeFixedData(
     126              :                 sockets, remoteRanks, roles, reinterpret_cast<const u8*>(&localFrame), static_cast<u32>(frameLenV2),
     127              :                 reinterpret_cast<u8*>(remoteFrames.data()), static_cast<u32>(frameLenV2), isAsync));
     128              :         }
     129              : 
     130              :         // ====== 逐个比对CheckFrameV2(精确报错:环境变量名/子通信域参数名等)======
     131            4 :         for (u32 i = 0; i < checkSocketSize; i++) {
     132            2 :             CHK_RET(checker.CompareCheckFrameV2(localFrame, remoteFrames[i]));
     133              :         }
     134            2 :         HCCL_INFO("[BatchExchangeAndCheckConsistency] hcomm compare check suc.");
     135            2 :         checker.SetInconsistentCheckFirstDone(true);
     136            2 :     }
     137            2 :     return HCCL_SUCCESS;
     138            2 : }
     139              : 
     140            1 : HcclResult ExchangeInfoMgr::ExchangeUserInfo(
     141              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<u32>& remoteRanks,
     142              :     const std::vector<HcommSocketRole>& roles, hccl::CollCommConfigConsistency& collCommConfigConsistency) const
     143              : {
     144              :     (void)roles;
     145              : 
     146            1 :     u32 localExchangeInfoLen = collCommConfigConsistency.GetExchangeInfoLen();
     147            1 :     if (localExchangeInfoLen == 0) {
     148            0 :         HCCL_INFO("[ExchangeUserInfo] localExchangeInfoLen is 0.");
     149            0 :         return HCCL_SUCCESS;
     150              :     }
     151              : 
     152              :     // 交换infoLen
     153            1 :     std::vector<u32> remoteExchangeInfoLens(sockets.size(), 0);
     154            1 :     u8* recvData = reinterpret_cast<u8*>(remoteExchangeInfoLens.data());
     155            1 :     const u8* sendData = reinterpret_cast<const u8*>(&localExchangeInfoLen);
     156            1 :     u32 len = sizeof(u32);
     157            2 :     for (u32 i = 0; i < sockets.size(); i++) {
     158            1 :         sockets[i]->Send(sendData, len);
     159            1 :         sockets[i]->Recv(recvData + i * len, len);
     160              :     }
     161              : 
     162              :     // 交换info数据(长度可能不同,需逐个收发)
     163            1 :     std::vector<std::vector<u8>> remoteUserDatas(sockets.size());
     164            2 :     for (u32 i = 0; i < sockets.size(); i++) {
     165            1 :         std::vector<u8> exchangeBuf;
     166            1 :         collCommConfigConsistency.GetExchangeInfoBuf(exchangeBuf);
     167            1 :         remoteUserDatas[i].resize(remoteExchangeInfoLens[i], 0);
     168            1 :         sockets[i]->Send(exchangeBuf.data(), localExchangeInfoLen);
     169            1 :         sockets[i]->Recv(remoteUserDatas[i].data(), remoteExchangeInfoLens[i]);
     170            1 :     }
     171              : 
     172              :     // 存储对端交换信息
     173            2 :     for (u32 i = 0; i < sockets.size(); i++) {
     174            1 :         if (remoteExchangeInfoLens[i] > 0 && !remoteUserDatas[i].empty()) {
     175            0 :             CHK_RET(collCommConfigConsistency.StoreRemoteExchangeInfo(remoteRanks[i], remoteUserDatas[i]));
     176              :         }
     177              :     }
     178              : 
     179            1 :     HCCL_INFO("[ExchangeUserInfo] suc.");
     180            1 :     return HCCL_SUCCESS;
     181            1 : }
     182              : 
     183            1 : HcclResult ExchangeInfoMgr::ExchangeUserInfoAsync(
     184              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<u32>& remoteRanks,
     185              :     const std::vector<HcommSocketRole>& roles, CollCommConfigConsistency& collCommConfigConsistency) const
     186              : {
     187            1 :     u32 localExchangeInfoLen = collCommConfigConsistency.GetExchangeInfoLen();
     188            1 :     if (localExchangeInfoLen == 0) {
     189            0 :         HCCL_INFO("[ExchangeUserInfoAsync] localExchangeInfoLen is 0.");
     190            0 :         return HCCL_SUCCESS;
     191              :     }
     192              :     // 交换infoLen
     193            1 :     std::vector<u32> remoteExchangeInfoLens(sockets.size(), 0);
     194            1 :     CHK_RET(BatchExchangeFixedData(
     195              :         sockets, remoteRanks, roles, reinterpret_cast<const u8*>(&localExchangeInfoLen), sizeof(u32),
     196              :         reinterpret_cast<u8*>(remoteExchangeInfoLens.data()), sizeof(u32), true));
     197              : 
     198              :     // 交换info数据(两阶段异步收发,防死锁)
     199            1 :     std::vector<std::vector<u8>> remoteUserDatas(sockets.size());
     200              :     // 第一阶段:SERVER先Recv/CLIENT先Send
     201            1 :     CHK_RET(ExchangeAsyncDataPhase(
     202              :         sockets, roles, remoteRanks, remoteUserDatas, remoteExchangeInfoLens, localExchangeInfoLen,
     203              :         collCommConfigConsistency, true));
     204            1 :     CHK_RET(WaitActiveAsyncComplete(sockets, remoteRanks, roles, remoteExchangeInfoLens, localExchangeInfoLen, true));
     205              :     // 第二阶段:SERVER再Send/CLIENT再Recv
     206            1 :     CHK_RET(ExchangeAsyncDataPhase(
     207              :         sockets, roles, remoteRanks, remoteUserDatas, remoteExchangeInfoLens, localExchangeInfoLen,
     208              :         collCommConfigConsistency, false));
     209            1 :     CHK_RET(WaitActiveAsyncComplete(sockets, remoteRanks, roles, remoteExchangeInfoLens, localExchangeInfoLen, false));
     210              : 
     211              :     // 存储对端交换信息
     212            2 :     for (u32 i = 0; i < sockets.size(); i++) {
     213            1 :         if (remoteExchangeInfoLens[i] > 0 && !remoteUserDatas[i].empty()) {
     214            0 :             CHK_RET(collCommConfigConsistency.StoreRemoteExchangeInfo(remoteRanks[i], remoteUserDatas[i]));
     215              :         }
     216              :     }
     217              : 
     218            1 :     HCCL_INFO("[ExchangeUserInfoAsync] suc.");
     219            1 :     return HCCL_SUCCESS;
     220            1 : }
     221              : 
     222              : // 异步交换info数据的一个阶段(isServerRecv=true: SERVER先Recv; false: SERVER先Send)
     223            5 : HcclResult ExchangeInfoMgr::ExchangeAsyncDataPhase(
     224              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<HcommSocketRole>& roles,
     225              :     const std::vector<u32>& remoteRanks, std::vector<std::vector<u8>>& remoteUserDatas,
     226              :     const std::vector<u32>& remoteExchangeInfoLens, u32 localExchangeInfoLen,
     227              :     CollCommConfigConsistency& collCommConfigConsistency, bool isServerRecv) const
     228              : {
     229           11 :     for (u32 i = 0; i < sockets.size(); i++) {
     230            7 :         bool shouldRecv = (roles[i] == HCOMM_SOCKET_ROLE_SERVER) == isServerRecv;
     231            7 :         if (shouldRecv) {
     232            4 :             CHK_PRT_RET(
     233              :                 remoteExchangeInfoLens[i] > HCCL_EXCHANGE_INFO_LEN,
     234              :                 HCCL_ERROR(
     235              :                     "[ExchangeUserInfoAsync] remoteExchangeInfoLen[%u] for remoteRank[%u] "
     236              :                     "exceeds max allowed [%u].",
     237              :                     remoteExchangeInfoLens[i], remoteRanks[i], HCCL_EXCHANGE_INFO_LEN),
     238              :                 HCCL_E_PARA);
     239            3 :             remoteUserDatas[i].resize(remoteExchangeInfoLens[i], 0);
     240            3 :             sockets[i]->RecvAsync(remoteUserDatas[i].data(), remoteExchangeInfoLens[i]);
     241              :         } else {
     242            3 :             std::vector<u8> exchangeBuf;
     243            3 :             collCommConfigConsistency.GetExchangeInfoBuf(exchangeBuf);
     244            3 :             sockets[i]->SendAsync(exchangeBuf.data(), localExchangeInfoLen);
     245            3 :         }
     246              :     }
     247            4 :     return HCCL_SUCCESS;
     248              : }
     249              : 
     250              : // 批量异步交换定长数据(SERVER先Recv再Send,CLIENT先Send再Recv,防死锁)
     251            3 : HcclResult ExchangeInfoMgr::BatchExchangeFixedData(
     252              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<u32>& remoteRanks,
     253              :     const std::vector<HcommSocketRole>& roles, const u8* sendData, u32 sendLen, u8* recvData, u32 recvLen,
     254              :     bool isAsync) const
     255              : {
     256            3 :     if (!isAsync) {
     257              :         // 确保 Socket 连接完成
     258            1 :         CHK_RET(WaitAllAsyncComplete(sockets, remoteRanks));
     259              :         // 使用 Socket 同步收发接口
     260            2 :         for (u32 i = 0; i < sockets.size(); i++) {
     261            1 :             sockets[i]->Send(sendData, sendLen);
     262            1 :             sockets[i]->Recv(recvData + i * recvLen, recvLen);
     263              :         }
     264            1 :         return HCCL_SUCCESS;
     265              :     }
     266              : 
     267            2 :     CHK_RET(WaitAllAsyncComplete(sockets, remoteRanks));
     268              :     // SERVER先Recv/CLIENT先Send
     269            4 :     for (u32 i = 0; i < sockets.size(); i++) {
     270            2 :         if (roles[i] == HCOMM_SOCKET_ROLE_SERVER) {
     271            0 :             sockets[i]->RecvAsync(recvData + i * recvLen, recvLen);
     272              :         } else {
     273            2 :             sockets[i]->SendAsync(sendData, sendLen);
     274              :         }
     275              :     }
     276            2 :     CHK_RET(WaitAllAsyncComplete(sockets, remoteRanks));
     277              : 
     278              :     // SERVER再Send/CLIENT再Recv
     279            4 :     for (u32 i = 0; i < sockets.size(); i++) {
     280            2 :         if (roles[i] == HCOMM_SOCKET_ROLE_SERVER) {
     281            0 :             sockets[i]->SendAsync(sendData, sendLen);
     282              :         } else {
     283            2 :             sockets[i]->RecvAsync(recvData + i * recvLen, recvLen);
     284              :         }
     285              :     }
     286            2 :     CHK_RET(WaitAllAsyncComplete(sockets, remoteRanks));
     287              : 
     288            2 :     return HCCL_SUCCESS;
     289              : }
     290              : 
     291            9 : HcclResult ExchangeInfoMgr::WaitAllAsyncComplete(
     292              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<u32>& remoteRanks) const
     293              : {
     294            9 :     auto timeout = std::chrono::seconds(Hccl::EnvConfig::GetInstance().GetSocketConfig().GetLinkTimeOut());
     295            9 :     auto startTime = std::chrono::steady_clock::now();
     296            9 :     std::vector<bool> done(sockets.size(), false);
     297            9 :     uint32_t doneCount = 0;
     298              : 
     299           18 :     while (doneCount < sockets.size()) {
     300           19 :         for (size_t i = 0; i < sockets.size(); i++) {
     301           10 :             if (done[i]) {
     302           10 :                 continue;
     303              :             }
     304           10 :             Hccl::SocketStatus status = sockets[i]->GetAsyncStatus();
     305           10 :             if (status == Hccl::SocketStatus::OK) {
     306           10 :                 done[i] = true;
     307           10 :                 doneCount++;
     308           10 :                 continue;
     309              :             }
     310            0 :             if (status == Hccl::SocketStatus::TIMEOUT) {
     311            0 :                 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
     312            0 :                                    std::chrono::steady_clock::now() - startTime)
     313            0 :                                    .count();
     314            0 :                 HCCL_ERROR(
     315              :                     "[WaitAllAsyncComplete] socket timeout for remoteRank[%u], elapsed[%lld]ms.", remoteRanks[i],
     316              :                     elapsed);
     317            0 :                 return HCCL_E_TIMEOUT;
     318              :             }
     319              :         }
     320            9 :         if ((std::chrono::steady_clock::now() - startTime) >= timeout) {
     321              :             auto elapsed
     322            0 :                 = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime)
     323            0 :                       .count();
     324            0 :             for (size_t i = 0; i < sockets.size(); i++) {
     325            0 :                 if (!done[i]) {
     326            0 :                     HCCL_ERROR(
     327              :                         "[WaitAllAsyncComplete] wall-clock timeout for remoteRank[%u], elapsed[%lld]ms.",
     328              :                         remoteRanks[i], elapsed);
     329              :                 }
     330              :             }
     331            0 :             return HCCL_E_TIMEOUT;
     332              :         }
     333              :     }
     334              : 
     335              :     auto elapsed
     336            9 :         = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime).count();
     337            9 :     HCCL_INFO("[WaitAllAsyncComplete] all[%zu] sockets completed, elapsed[%lld]ms.", sockets.size(), elapsed);
     338            9 :     return HCCL_SUCCESS;
     339            9 : }
     340              : 
     341              : // 收集并等待有实际异步操作的socket子集
     342            2 : HcclResult ExchangeInfoMgr::WaitActiveAsyncComplete(
     343              :     const std::vector<Hccl::Socket*>& sockets, const std::vector<u32>& remoteRanks,
     344              :     const std::vector<HcommSocketRole>& roles, const std::vector<u32>& remoteExchangeInfoLens, u32 localExchangeInfoLen,
     345              :     bool isFirstPass) const
     346              : {
     347            2 :     std::vector<Hccl::Socket*> activeSockets;
     348            2 :     std::vector<u32> activeRanks;
     349            4 :     for (u32 i = 0; i < sockets.size(); i++) {
     350            4 :         bool isActive = isFirstPass ? (roles[i] == HCOMM_SOCKET_ROLE_SERVER && remoteExchangeInfoLens[i] > 0)
     351            1 :                                           || (roles[i] != HCOMM_SOCKET_ROLE_SERVER && localExchangeInfoLen > 0) :
     352            1 :                                       (roles[i] == HCOMM_SOCKET_ROLE_SERVER && localExchangeInfoLen > 0)
     353            1 :                                           || (roles[i] != HCOMM_SOCKET_ROLE_SERVER && remoteExchangeInfoLens[i] > 0);
     354            2 :         if (isActive) {
     355            1 :             activeSockets.push_back(sockets[i]);
     356            1 :             activeRanks.push_back(remoteRanks[i]);
     357              :         }
     358              :     }
     359            2 :     if (!activeSockets.empty()) {
     360            1 :         CHK_RET(WaitAllAsyncComplete(activeSockets, activeRanks));
     361              :     }
     362            2 :     return HCCL_SUCCESS;
     363            2 : }
     364              : } // namespace hccl
        

Generated by: LCOV version 2.0-1