LCOV - code coverage report
Current view: top level - coll_communicator_mgr/rank_graph/rank_graph_builder - detour_service.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 26.8 % 205 55
Test Date: 2026-08-25 19:18:03 Functions: 50.0 % 14 7

            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 "detour_service.h"
      12              : #include "env_config/env_config_v2.h"
      13              : #include "detour_rules.h"
      14              : #include "not_support_exception.h"
      15              : 
      16              : namespace Hccl {
      17              : 
      18              : using namespace std;
      19              : 
      20              : constexpr u32 DETOUR_NODE_NUM = 8;
      21              : constexpr u32 DETOUR_NODE_NUM_2P = 2;
      22              : constexpr u32 DETOUR_NODE_NUM_4P = 4;
      23              : 
      24           26 : DetourService& DetourService::GetInstance()
      25              : {
      26           26 :     static DetourService detourService(PhyTopo::GetInstance().get());
      27           26 :     return detourService;
      28              : }
      29              : 
      30            2 : DetourService::DetourService(const PhyTopo* phyTopo) { this->phyTopo = phyTopo; }
      31              : 
      32              : struct DetourData {
      33              :     NodeId detourPhyPeerId{0};
      34              :     NodeId srcPhyPeerId{0};
      35              :     NodeId dstPhyPeerId{0};
      36              :     shared_ptr<NetInstance::Peer> srcNetInstPeer{nullptr};
      37              :     shared_ptr<NetInstance::Peer> dstNetInstPeer{nullptr};
      38              : };
      39              : 
      40              : vector<shared_ptr<PhyTopo::Link>>
      41            0 : GetLinks(NodeId srcId, NodeId dstId, const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>& phyTopoGraph)
      42              : {
      43            0 :     vector<shared_ptr<PhyTopo::Link>> links;
      44            0 :     if (phyTopoGraph == nullptr) {
      45            0 :         THROW<NullPtrException>(StringFormat("[GetLinks] phyTopoGraphis nullptr"));
      46              :     }
      47              :     // 统一物理图中仅 P2P 边可作为绕路候选。
      48            0 :     phyTopoGraph->TraverseEdge(srcId, dstId, [&](shared_ptr<PhyTopo::Link> link) {
      49            0 :         if (link != nullptr && link->GetType() == LinkType::PEER2PEER) {
      50            0 :             links.emplace_back(link);
      51            0 :             return;
      52              :         }
      53              :     });
      54              : 
      55            0 :     return links;
      56            0 : }
      57              : 
      58            0 : void AddDetourLink(
      59              :     NetInstance* innerNetInst, const DetourData& data,
      60              :     const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>& phyTopoGraph,
      61              :     [[maybe_unused]] const RankTableInfo* rankTable)
      62              : {
      63            0 :     vector<shared_ptr<PhyTopo::Link>> src2detVec = GetLinks(data.srcPhyPeerId, data.detourPhyPeerId, phyTopoGraph);
      64            0 :     vector<shared_ptr<PhyTopo::Link>> det2dstVec = GetLinks(data.detourPhyPeerId, data.dstPhyPeerId, phyTopoGraph);
      65            0 :     if (src2detVec.size() == 0 || det2dstVec.size() == 0) {
      66            0 :         return;
      67              :     }
      68            0 :     if (innerNetInst == nullptr) {
      69            0 :         THROW<NullPtrException>(StringFormat("[AddDetourLink] innerGroup is nullptr"));
      70              :     }
      71            0 :     if (data.srcNetInstPeer == nullptr || data.dstNetInstPeer == nullptr) {
      72            0 :         THROW<NullPtrException>(
      73            0 :             StringFormat("[DetourService][InsertDetourLinks][AddDetourLink] virtual peer is nullptr"));
      74              :     }
      75            0 :     u32 hop = 2; // 目前绕路hop一定是2
      76            0 :     for (const auto& src2detLink : src2detVec) {
      77            0 :         for (const auto& det2dstLink : det2dstVec) {
      78            0 :             LinkType linkType = src2detLink->GetType();
      79            0 :             std::set<LinkProtocol> linkProtocols = src2detLink->GetLinkProtocols();
      80            0 :             if (linkType != det2dstLink->GetType()) {
      81            0 :                 HCCL_WARNING(
      82              :                     "[DetourService][InsertDetourLinks][AddDetourLink] src2det[%s] det2dst[%s] linkType no match",
      83              :                     linkType.Describe().c_str(), det2dstLink->GetType().Describe().c_str());
      84            0 :                 continue;
      85            0 :             };
      86              :             // todo 是不是应该改为判断两个set是否有交集,取绕路的协议集合? 修改了一下,llt再check一下
      87            0 :             std::set<LinkProtocol> newLinkProtocols;
      88            0 :             std::set_intersection(
      89            0 :                 linkProtocols.begin(), linkProtocols.end(), det2dstLink->GetLinkProtocols().begin(),
      90            0 :                 det2dstLink->GetLinkProtocols().end(), std::inserter(newLinkProtocols, newLinkProtocols.begin()));
      91              : 
      92            0 :             if (newLinkProtocols.empty()) {
      93              :                 // todo 先改编译,后面再实现日志打印
      94            0 :                 continue;
      95              :             };
      96              : 
      97              :             // 从Link中获取端口集合
      98            0 :             if (src2detLink->GetSourceIFace() == nullptr || det2dstLink->GetTargetIFace() == nullptr) {
      99            0 :                 THROW<InvalidParamsException>(
     100              :                     "[DetourService][InsertDetourLinks][AddDetourLink] source ConnInterface is nullptr");
     101              :             }
     102            0 :             std::set<string> src2detPorts = src2detLink->GetSourceIFace()->GetPorts();
     103            0 :             std::set<string> det2dstPorts = det2dstLink->GetTargetIFace()->GetPorts();
     104            0 :             if (src2detPorts.size() != 1 || det2dstPorts.size() != 1) {
     105            0 :                 HCCL_WARNING(
     106              :                     "[DetourService][InsertDetourLinks][AddDetourLink] Ignore unmatched P2P candidate, "
     107              :                     "srcPortNum[%zu] dstPortNum[%zu]",
     108              :                     src2detPorts.size(), det2dstPorts.size());
     109            0 :                 continue;
     110            0 :             }
     111              : 
     112              :             // 绕路两端口均须属于 RankTable layer 0。
     113            0 :             IpAddress src2detAddr;
     114            0 :             IpAddress det2dstAddr;
     115            0 :             if (!data.srcNetInstPeer->TryGetLayer0Address(*src2detPorts.begin(), src2detAddr)
     116            0 :                 || !data.dstNetInstPeer->TryGetLayer0Address(*det2dstPorts.begin(), det2dstAddr)) {
     117            0 :                 HCCL_WARNING("[DetourService][InsertDetourLinks][AddDetourLink] Ignore P2P candidate not in layer0");
     118            0 :                 continue;
     119            0 :             }
     120              : 
     121              :             // 构造InterFace对象用于后续生成Link
     122              :             shared_ptr<NetInstance::ConnInterface> sourceIface = make_shared<NetInstance::ConnInterface>(
     123            0 :                 src2detAddr, src2detPorts, src2detLink->GetSourceIFace()->GetPos(), LinkType::PEER2PEER,
     124            0 :                 src2detLink->GetLinkProtocols(), src2detLink->GetTopoType(), src2detLink->GetTopoInstId());
     125              :             shared_ptr<NetInstance::ConnInterface> targetIface = make_shared<NetInstance::ConnInterface>(
     126            0 :                 det2dstAddr, det2dstPorts, det2dstLink->GetSourceIFace()->GetPos(), LinkType::PEER2PEER,
     127            0 :                 det2dstLink->GetLinkProtocols(), det2dstLink->GetTopoType(), det2dstLink->GetTopoInstId());
     128              : 
     129              :             // 构造Link加入NetInstance中
     130              :             shared_ptr<NetInstance::Link> sendEdge = make_shared<NetInstance::Link>(
     131            0 :                 data.srcNetInstPeer, data.dstNetInstPeer, sourceIface, targetIface, linkType, newLinkProtocols,
     132            0 :                 LinkDirection::SEND_ONLY, hop);
     133              :             shared_ptr<NetInstance::Link> recvEdge = make_shared<NetInstance::Link>(
     134            0 :                 data.dstNetInstPeer, data.srcNetInstPeer, targetIface, sourceIface, linkType, newLinkProtocols,
     135            0 :                 LinkDirection::RECV_ONLY, hop);
     136            0 :             innerNetInst->AddLink(sendEdge);
     137            0 :             innerNetInst->AddLink(recvEdge);
     138              : 
     139            0 :             data.srcNetInstPeer->AddConnInterface(0, sourceIface);
     140            0 :             data.dstNetInstPeer->AddConnInterface(0, targetIface);
     141              : 
     142            0 :             HCCL_DEBUG(
     143              :                 "[DetourService][AddDetourLink] add SEND_ONLY and RECV_ONLY two links: linkType[%s]"
     144              :                 " sourceIfaceAddress[%s] targetIfaceAddress[%s]",
     145              :                 linkType.Describe().c_str(), sourceIface->GetAddr().Describe().c_str(),
     146              :                 targetIface->GetAddr().Describe().c_str());
     147            0 :         }
     148              :     }
     149              : 
     150            0 :     HCCL_DEBUG(
     151              :         "[DetourService][AddDetourLink] srcRankId[%llu] dstRankId[%llu] srcLocalId[%llu] detourLocalId[%llu] "
     152              :         "dstLocalId[%llu] src2detVec.size[%u] det2dstVec.size[%u]",
     153              :         data.srcNetInstPeer->GetNodeId(), data.dstNetInstPeer->GetNodeId(), data.srcPhyPeerId, data.detourPhyPeerId,
     154              :         data.dstPhyPeerId, src2detVec.size(), det2dstVec.size());
     155            0 : }
     156              : 
     157           24 : std::vector<LocalId> GetInnerLocalIds(const RankGraph* rankGraph)
     158              : {
     159           24 :     if (rankGraph == nullptr) {
     160            0 :         THROW<NullPtrException>(StringFormat("[GetInnerLocalIds] rankGraph is nullptr"));
     161              :     }
     162           24 :     const NetInstance* innerNetInst = rankGraph->GetNetInstanceByRankId(0, rankGraph->GetMyRank());
     163           24 :     if (innerNetInst == nullptr) {
     164            0 :         THROW<NullPtrException>(StringFormat("[GetInnerLocalIds] innerNetInst is nullptr"));
     165              :     }
     166           24 :     set<RankId> innerRanks = innerNetInst->GetRankIds();
     167           24 :     std::vector<LocalId> localIds;
     168           85 :     for (auto& rankId : innerRanks) {
     169           61 :         localIds.emplace_back(rankGraph->GetLocalId(rankId));
     170              :     }
     171           24 :     return localIds;
     172           24 : }
     173              : 
     174            0 : bool IsInSameRow(const std::vector<LocalId>& localIds)
     175              : {
     176            0 :     int preRowId = -1;
     177            0 :     for (auto& localId : localIds) {
     178            0 :         int curRowId = localId / DETOUR_NODE_NUM;
     179            0 :         if (preRowId == -1) {
     180            0 :             preRowId = curRowId;
     181              :         } else {
     182            0 :             if (curRowId != preRowId) {
     183            0 :                 return false;
     184              :             }
     185              :         }
     186              :     }
     187            0 :     return true;
     188              : }
     189              : 
     190            0 : bool IsInSameCol(const std::vector<LocalId>& localIds)
     191              : {
     192            0 :     int preColId = -1;
     193            0 :     for (auto& localId : localIds) {
     194            0 :         int curColId = localId % DETOUR_NODE_NUM;
     195            0 :         if (preColId == -1) {
     196            0 :             preColId = curColId;
     197              :         } else {
     198            0 :             if (curColId != preColId) {
     199            0 :                 return false;
     200              :             }
     201              :         }
     202              :     }
     203            0 :     return true;
     204              : }
     205              : 
     206            0 : bool GetTableIds(
     207              :     const std::vector<LocalId>& localIds, std::unordered_map<LocalId, u32>& tableIds, std::set<u32>& tableIdSet)
     208              : {
     209            0 :     if (IsInSameRow(localIds)) {
     210            0 :         for (auto& localId : localIds) {
     211            0 :             u32 tableId = localId % DETOUR_NODE_NUM;
     212            0 :             tableIds[localId] = tableId;
     213            0 :             tableIdSet.emplace(tableId);
     214              :         }
     215            0 :     } else if (IsInSameCol(localIds)) {
     216            0 :         for (auto& localId : localIds) {
     217            0 :             u32 tableId = localId / DETOUR_NODE_NUM;
     218            0 :             tableIds[localId] = tableId;
     219            0 :             tableIdSet.emplace(tableId);
     220              :         }
     221              :     } else {
     222            0 :         HCCL_WARNING("[DetourService][GetTableIds] The ranks localIds are not in the same row or column.");
     223            0 :         return false;
     224              :     }
     225            0 :     return true;
     226              : }
     227              : 
     228            4 : void SetDetourTable4P(
     229              :     const std::set<u32>& tableIdSet, unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable)
     230              : {
     231           12 :     if (tableIdSet == std::set<u32>{0, 1, 2, 3}) { // tableId必须为 0 1 2 3,才能使用DETOUR4PTABLE_0123绕路
     232            1 :         detourTable = GetDetour4PTable0123();
     233            1 :         HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_0123");
     234            9 :     } else if (tableIdSet == std::set<u32>{4, 5, 6, 7}) { // tableId必须为 4 5 6 7,才能使用DETOUR4PTABLE_4567绕路
     235            1 :         detourTable = GetDetour4PTable4567();
     236            1 :         HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_4567");
     237            6 :     } else if (tableIdSet == std::set<u32>{0, 2, 4, 6}) { // tableId必须为 0 2 4 6,才能使用DETOUR4PTABLE_0246绕路
     238            1 :         detourTable = GetDetour4PTable0246();
     239            1 :         HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_0246");
     240            3 :     } else if (tableIdSet == std::set<u32>{1, 3, 5, 7}) { // tableId必须为 1 3 5 7,才能使用DETOUR4PTABLE_1357绕路
     241            1 :         detourTable = GetDetour4PTable1357();
     242            1 :         HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_1357");
     243              :     } else {
     244            0 :         HCCL_WARNING("no matched detourTable found");
     245              :     }
     246            4 : }
     247              : 
     248            2 : void SetDetourTable2P(
     249              :     const std::set<u32>& tableIdSet, unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable)
     250              : {
     251           11 :     if (tableIdSet == std::set<u32>{0, 1} || tableIdSet == std::set<u32>{2, 3} || tableIdSet == std::set<u32>{4, 5}
     252            7 :         || tableIdSet == std::set<u32>{6, 7}) {
     253            1 :         detourTable = GetDetour2PTable01();
     254            1 :     } else if (
     255            3 :         tableIdSet == std::set<u32>{0, 4} || tableIdSet == std::set<u32>{1, 5} || tableIdSet == std::set<u32>{2, 6}
     256            2 :         || tableIdSet == std::set<u32>{3, 7}) {
     257            1 :         detourTable = GetDetour2PTable04();
     258              :     } else {
     259            0 :         HCCL_WARNING("[DetourService][%s]no matched detourTable found", __func__);
     260              :     }
     261            2 : }
     262              : 
     263           24 : void GetDetourTableAndTableIds(
     264              :     const std::vector<LocalId>& localIds,
     265              :     std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable,
     266              :     std::unordered_map<LocalId, u32>& tableIds, const RankTableInfo* rankTable)
     267              : {
     268           24 :     std::set<u32> tableIdSet;
     269           24 :     HcclDetourType detourType = EnvConfig::GetInstance().GetDetourConfig().GetDetourType();
     270           24 :     if (rankTable->detour == false) {
     271            9 :         detourType = HcclDetourType::HCCL_DETOUR_DISABLE;
     272              :     }
     273           24 :     switch (detourType) {
     274            0 :         case HcclDetourType::HCCL_DETOUR_ENABLE_2P: {
     275            0 :             if (localIds.size() != DETOUR_NODE_NUM_2P) {
     276            0 :                 return;
     277              :             }
     278            0 :             bool res = GetTableIds(localIds, tableIds, tableIdSet);
     279            0 :             if (res) {
     280            0 :                 SetDetourTable2P(tableIdSet, detourTable);
     281            0 :                 HCCL_DEBUG("[DetourService] selected detour type is DETOUR2PTABLE");
     282              :             } else {
     283            0 :                 HCCL_WARNING("[DetourService] detourtype [%s] does not support.", detourType.Describe().c_str());
     284              :             }
     285            0 :             break;
     286              :         }
     287            0 :         case HcclDetourType::HCCL_DETOUR_ENABLE_4P: {
     288            0 :             if (localIds.size() != DETOUR_NODE_NUM_4P) {
     289            0 :                 return;
     290              :             }
     291            0 :             bool res = GetTableIds(localIds, tableIds, tableIdSet);
     292            0 :             if (res) {
     293            0 :                 SetDetourTable4P(tableIdSet, detourTable);
     294              :             } else {
     295            0 :                 HCCL_WARNING("[DetourService] detourtype [%s] does not support.", detourType.Describe().c_str());
     296              :             }
     297            0 :             break;
     298              :         }
     299           24 :         case HcclDetourType::HCCL_DETOUR_DISABLE: {
     300           54 :             HCCL_DEBUG("[DetourService] detour is disable");
     301           24 :             break;
     302              :         }
     303            0 :         default: {
     304            0 :             THROW<NotSupportException>(
     305            0 :                 StringFormat("[DetourService] detourtype [%s] does not support.", detourType.Describe().c_str()));
     306              :         }
     307              :     }
     308           24 : }
     309              : 
     310            0 : void AddDetourLinks(
     311              :     const PhyTopo* phyTopo, RankGraph* rankGraph,
     312              :     std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable,
     313              :     std::unordered_map<LocalId, u32>& tableIds, const RankTableInfo* rankTable)
     314              : {
     315            0 :     auto phyTopoGraph = phyTopo->GetTopoGraph();
     316            0 :     NetInstance* innerNetInst = rankGraph->GetNetInstanceByRankId(0, rankGraph->GetMyRank());
     317            0 :     if (innerNetInst == nullptr) {
     318            0 :         THROW<NullPtrException>(StringFormat("[DetourService] innerNetInst is nullptr"));
     319              :     }
     320            0 :     set<RankId> innerRanks = innerNetInst->GetRankIds();
     321            0 :     for (const auto& srcRankId : innerRanks) {
     322            0 :         LocalId srcLocalId = rankGraph->GetLocalId(srcRankId);
     323            0 :         u32 srcTableId = tableIds[srcLocalId];
     324            0 :         for (const auto& dstRankId : innerRanks) {
     325            0 :             LocalId dstLocalId = rankGraph->GetLocalId(dstRankId);
     326            0 :             u32 dstTableId = tableIds[dstLocalId];
     327              : 
     328            0 :             if (detourTable.count(srcTableId) == 0 || detourTable[srcTableId].count(dstTableId) == 0) {
     329            0 :                 continue;
     330              :             }
     331              : 
     332            0 :             auto detourTableIds = detourTable[srcTableId][dstTableId];
     333            0 :             for (auto& detourTableId : detourTableIds) {
     334            0 :                 LocalId detourLocalId = detourTableId + srcLocalId - srcTableId;
     335              : 
     336              :                 // 插入detourlink
     337            0 :                 DetourData detourData;
     338            0 :                 detourData.detourPhyPeerId = PhyTopo::Peer::GetId(detourLocalId); // 绕路可能没有绕路节点的rankid
     339            0 :                 detourData.srcPhyPeerId = PhyTopo::Peer::GetId(srcLocalId);
     340            0 :                 detourData.dstPhyPeerId = PhyTopo::Peer::GetId(dstLocalId);
     341            0 :                 detourData.srcNetInstPeer = rankGraph->GetPeer(srcRankId);
     342            0 :                 detourData.dstNetInstPeer = rankGraph->GetPeer(dstRankId);
     343              : 
     344            0 :                 AddDetourLink(innerNetInst, detourData, phyTopoGraph, rankTable);
     345            0 :             }
     346            0 :         }
     347              :     }
     348            0 : }
     349              : 
     350           24 : void DetourService::InsertDetourLinks(RankGraph* rankGraph, const RankTableInfo* rankTable)
     351              : {
     352           24 :     std::unordered_map<LocalId, u32> tableIds;
     353           24 :     std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>> detourTable;
     354              : 
     355              :     // 获取innerGroup的localIds
     356           24 :     std::vector<LocalId> localIds = GetInnerLocalIds(rankGraph);
     357              :     // 获取当前localIds的tableId和detourTable
     358           24 :     GetDetourTableAndTableIds(localIds, detourTable, tableIds, rankTable);
     359              : 
     360           24 :     if (!detourTable.empty()) {
     361              :         // 添加绕路links
     362            0 :         AddDetourLinks(phyTopo, rankGraph, detourTable, tableIds, rankTable);
     363              :     } else {
     364           54 :         HCCL_WARNING("no detour links found");
     365              :     }
     366           24 : }
     367              : 
     368              : } // namespace Hccl
        

Generated by: LCOV version 2.0-1