LCOV - code coverage report
Current view: top level - coll_communicator_mgr/rank_graph/phy_topo_builder - phy_topo_builder.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.6 % 149 138
Test Date: 2026-08-25 19:18:03 Functions: 100.0 % 14 14

            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 "phy_topo_builder.h"
      12              : #include "log.h"
      13              : #include "json_parser.h"
      14              : #include "exception_util.h"
      15              : #include "null_ptr_exception.h"
      16              : #include "invalid_params_exception.h"
      17              : #include "adapter_error_manager_pub.h"
      18              : 
      19              : namespace Hccl {
      20              : 
      21           56 : PhyTopoBuilder& PhyTopoBuilder::GetInstance()
      22              : {
      23           56 :     static PhyTopoBuilder phyTopoBuilder;
      24           56 :     return phyTopoBuilder;
      25              : }
      26              : 
      27              : // 根据nodeType和localId创建节点
      28           73 : std::shared_ptr<PhyTopo::Node> CreateNode(const PhyTopo::Node::NodeType nodeType, const LocalId localId)
      29              : {
      30           73 :     if (nodeType == PhyTopo::Node::NodeType::PEER) {
      31           56 :         return std::make_shared<PhyTopo::Peer>(localId);
      32              :     } else {
      33           17 :         return std::make_shared<PhyTopo::Fabric>();
      34              :     }
      35              : }
      36              : 
      37           17 : void PhyTopoBuilder::Build(const std::string& topoPath)
      38              : {
      39           17 :     std::lock_guard<std::mutex> lock(phyTopoMutex);
      40              : 
      41           17 :     if (PhyTopo::GetInstance()->IsInitFinished()) {
      42           33 :         HCCL_INFO("PhyTopo has been initialized and does not need to be rebuilt");
      43           11 :         return;
      44              :     }
      45              : 
      46            6 :     if (topoPath.empty()) {
      47            0 :         RPT_INPUT_ERR(
      48              :             true, "EI0004", std::vector<std::string>({"ranktable_path", "error_reason"}),
      49              :             std::vector<std::string>(
      50              :                 {"Please check the path configuration of the topo json file.",
      51              :                  "The rankTable file path does not exist, the permission is insufficient, or the JSON format is "
      52              :                  "incorrect."}));
      53            0 :         THROW<InvalidParamsException>("[PhyTopoBuilder::%s] Topo path is empty.", __func__);
      54              :     }
      55              : 
      56           18 :     HCCL_DEBUG("[PhyTopoBuilder::%s]Start to build physic topo.", __func__);
      57              : 
      58            6 :     auto topoInfo = LoadTopoInfo(topoPath);
      59            6 :     BuildPhyTopo(*topoInfo);
      60              : 
      61            6 :     PhyTopo::GetInstance()->InitFinish();
      62              : 
      63           18 :     HCCL_DEBUG("[PhyTopoBuilder::%s]build physic topo success.", __func__);
      64            6 :     PhyTopo::GetInstance()->Dump();
      65           17 : }
      66              : 
      67            9 : std::shared_ptr<TopoInfo> PhyTopoBuilder::LoadTopoInfo(const std::string& topoPath)
      68              : {
      69            9 :     std::shared_ptr<TopoInfo> topoInfo = std::make_shared<TopoInfo>();
      70              :     // 检查是否为非法路径以及size的大小。
      71              :     struct stat fileStat;
      72            9 :     if (stat(topoPath.c_str(), &fileStat) != 0) {
      73            2 :         HCCL_ERROR(
      74              :             "[PhyTopoBuilder][LoadTopoInfo] Get file stat failed, file path:%s, errno:%d, error: %s", topoPath.c_str(),
      75              :             errno, strerror(errno));
      76            2 :         THROW<InvalidParamsException>(
      77              :             "[PhyTopoBuilder][LoadTopoInfo]Get file stat failed, file path:%s, errno:%d, error: %s", topoPath.c_str(),
      78            2 :             errno, strerror(errno));
      79              :     }
      80              : 
      81            7 :     u64 topoFileSize = static_cast<u64>(fileStat.st_size);
      82            7 :     if (topoFileSize > SUPPORT_MAX_TOPOFILE_SIZE || topoFileSize <= 0) {
      83            1 :         HCCL_ERROR(
      84              :             "[PhyTopoBuilder][LoadTopoInfo] topoFileSize size: %llu, topoFile must be greater than 0 and less than %u",
      85              :             topoFileSize, SUPPORT_MAX_TOPOFILE_SIZE);
      86            2 :         THROW<InvalidParamsException>(StringFormat(
      87              :             "[PhyTopoBuilder][LoadTopoInfo]file %s size (%llu bytes) exceeds max allowed size (%u bytes)",
      88              :             topoPath.c_str(), topoFileSize, SUPPORT_MAX_TOPOFILE_SIZE));
      89              :     }
      90              : 
      91              :     JsonParser topoParser;
      92            6 :     topoParser.ParseFile(topoPath, *topoInfo);
      93            6 :     topoInfo_ = topoInfo;
      94            6 :     return topoInfo;
      95            3 : }
      96              : 
      97           64 : shared_ptr<PhyTopo::Link> CreatePeer2PeerLink(const LinkParams& params)
      98              : {
      99           64 :     LinkType linkType = LinkType::PEER2PEER;
     100              :     auto srcIface
     101           64 :         = std::make_shared<PhyTopo::ConnInterface>(params.localAPorts, params.position, linkType, params.protocols);
     102              :     auto dstIface
     103           64 :         = std::make_shared<PhyTopo::ConnInterface>(params.localBPorts, params.position, linkType, params.protocols);
     104           64 :     PhyTopo::LinkAttributes linkAttrs;
     105           64 :     linkAttrs.linktype = linkType;
     106           64 :     linkAttrs.protocols = params.protocols;
     107              :     auto link = std::make_shared<PhyTopo::Link>(
     108           64 :         params.srcNode, params.dstNode, linkAttrs, params.topoType, params.topoInstanceId);
     109           64 :     link->SetSourceIface(srcIface);
     110           64 :     params.srcNode->AddConnInterface(srcIface);
     111           64 :     link->SetTargetIface(dstIface);
     112           64 :     params.dstNode->AddConnInterface(dstIface);
     113          128 :     return {link};
     114           64 : }
     115              : 
     116          186 : shared_ptr<PhyTopo::Link> CreatePeer2NetLink(const LinkParams& params)
     117              : {
     118          186 :     LinkType linkType = LinkType::PEER2NET;
     119              :     auto srcIface
     120          186 :         = std::make_shared<PhyTopo::ConnInterface>(params.localAPorts, params.position, linkType, params.protocols);
     121              :     // fabric 没有ports
     122          186 :     std::set<std::string> ports{};
     123          186 :     auto dstIface = std::make_shared<PhyTopo::ConnInterface>(ports, params.position, linkType, params.protocols);
     124          186 :     PhyTopo::LinkAttributes linkAttrs;
     125          186 :     linkAttrs.linktype = linkType;
     126          186 :     linkAttrs.protocols = params.protocols;
     127              :     auto link = std::make_shared<PhyTopo::Link>(
     128          186 :         params.srcNode, params.dstNode, linkAttrs, params.topoType, params.topoInstanceId);
     129          186 :     link->SetSourceIface(srcIface);
     130          186 :     params.srcNode->AddConnInterface(srcIface);
     131          186 :     link->SetTargetIface(dstIface);
     132          186 :     params.dstNode->AddConnInterface(dstIface);
     133          372 :     return {link};
     134          186 : }
     135              : 
     136              : // 根据链路类型建链
     137          250 : shared_ptr<PhyTopo::Link> CreateLink(const LinkType linkType, const LinkParams& params)
     138              : {
     139          250 :     if (linkType == LinkType::PEER2PEER) {
     140           64 :         return CreatePeer2PeerLink(params);
     141              :     } else {
     142          186 :         return CreatePeer2NetLink(params);
     143              :     }
     144              : }
     145              : 
     146          250 : NodeId GetNodeId(const PhyTopo::Node::NodeType nodeType, LocalId localId)
     147              : {
     148          250 :     switch (nodeType) {
     149          157 :         case PhyTopo::Node::NodeType::PEER:
     150          157 :             return PhyTopo::Peer::GetId(localId);
     151           93 :         case PhyTopo::Node::NodeType::FABRIC:
     152           93 :             return PhyTopo::Fabric::GetId();
     153            0 :         default:
     154            0 :             THROW<InvalidParamsException>(StringFormat("[PhyTopoBuilder]Invalid NodeType."));
     155              :             return 0;
     156              :     }
     157              : }
     158              : 
     159              : std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>
     160           25 : PhyTopoBuilder::CreateGraph(const std::vector<EdgeInfo>& edges) const
     161              : {
     162              :     // 所有物理边构建到同一张图,逻辑分层由 RankTable 端口确定。
     163           25 :     auto graph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
     164              : 
     165          150 :     for (const auto& edgeInfo : edges) {
     166          125 :         std::shared_ptr<PhyTopo::Node> nodeA;
     167          125 :         std::shared_ptr<PhyTopo::Node> nodeB;
     168              : 
     169              :         // 生成 nodeAId,localA 始终为 PEER 类型
     170          125 :         NodeId nodeAId = GetNodeId(PhyTopo::Node::NodeType::PEER, edgeInfo.localA);
     171              :         // 获取或创建 nodeA
     172          125 :         if (!graph->HasNode(nodeAId)) {
     173           22 :             nodeA = CreateNode(PhyTopo::Node::NodeType::PEER, edgeInfo.localA);
     174           22 :             graph->AddNode(nodeAId, nodeA);
     175           36 :             HCCL_DEBUG("[PhyTopoBuilder::%s] Add node[%llu] success.", __func__, nodeAId);
     176              :         } else {
     177              :             // 使用 TraverseNode 查找 nodeA
     178          103 :             graph->TraverseNode([&nodeA, nodeAId](NodeId id, const std::shared_ptr<PhyTopo::Node>& n) {
     179          368 :                 if (id == nodeAId) {
     180          103 :                     nodeA = n;
     181              :                 }
     182          368 :             });
     183          103 :             if (nodeA == nullptr) {
     184            0 :                 HCCL_ERROR("[PhyTopoBuilder::CreateGraph] nodeAId [%llu] not found.", nodeAId);
     185            0 :                 THROW<NullPtrException>(
     186            0 :                     StringFormat("[PhyTopoBuilder::CreateGraph] Unable to find node [%llu].", nodeAId));
     187              :             }
     188              :         }
     189              : 
     190              :         // 根据 linkType 生成 nodeBId
     191          125 :         PhyTopo::Node::NodeType nodeBType;
     192          125 :         if (edgeInfo.linkType == LinkType::PEER2PEER) {
     193           32 :             nodeBType = PhyTopo::Node::NodeType::PEER;
     194              :         } else {
     195           93 :             nodeBType = PhyTopo::Node::NodeType::FABRIC;
     196              :         }
     197              : 
     198          125 :         NodeId nodeBId = GetNodeId(nodeBType, edgeInfo.localB);
     199              :         // 获取或创建 nodeB
     200          125 :         if (!graph->HasNode(nodeBId)) {
     201           42 :             nodeB = CreateNode(nodeBType, edgeInfo.localB);
     202           42 :             graph->AddNode(nodeBId, nodeB);
     203           76 :             HCCL_DEBUG("[PhyTopoBuilder::%s] Add node[%llu] success.", __func__, nodeBId);
     204              :         } else {
     205              :             // 使用 TraverseNode 查找 nodeB
     206           83 :             graph->TraverseNode([&nodeB, nodeBId](NodeId id, const std::shared_ptr<PhyTopo::Node>& n) {
     207          321 :                 if (id == nodeBId) {
     208           83 :                     nodeB = n;
     209              :                 }
     210          321 :             });
     211           83 :             if (nodeB == nullptr) {
     212            0 :                 HCCL_ERROR("[PhyTopoBuilder::CreateGraph] nodeBId [%llu] not found.", nodeBId);
     213            0 :                 THROW<NullPtrException>(
     214            0 :                     StringFormat("[PhyTopoBuilder::CreateGraph] Unable to find node [%llu].", nodeBId));
     215              :             }
     216              :         }
     217              : 
     218              :         // 双向分别创建link
     219              :         LinkParams abLinkParams{
     220              :             nodeA,
     221              :             nodeB,
     222          125 :             edgeInfo.localAPorts,
     223          125 :             edgeInfo.localBPorts,
     224              :             edgeInfo.position,
     225              :             edgeInfo.topoType,
     226          125 :             edgeInfo.topoInstId,
     227          125 :             edgeInfo.protocols};
     228          125 :         auto abLinks = CreateLink(edgeInfo.linkType, abLinkParams);
     229          125 :         graph->AddEdge(nodeAId, nodeBId, abLinks);
     230              :         LinkParams baLinkParams{
     231              :             nodeB,
     232              :             nodeA,
     233          125 :             edgeInfo.localBPorts,
     234          125 :             edgeInfo.localAPorts,
     235              :             edgeInfo.position,
     236              :             edgeInfo.topoType,
     237          125 :             edgeInfo.topoInstId,
     238          125 :             edgeInfo.protocols};
     239          125 :         auto baLinks = CreateLink(edgeInfo.linkType, baLinkParams);
     240          125 :         graph->AddEdge(nodeBId, nodeAId, baLinks);
     241          125 :     }
     242              : 
     243           25 :     return graph;
     244            0 : }
     245              : 
     246           22 : void PhyTopoBuilder::BuildPhyTopo(const TopoInfo& topoInfo) const
     247              : {
     248              :     // topo.json 只描述物理连接,不再划分逻辑层。
     249           22 :     auto graph = CreateGraph(topoInfo.edges);
     250              :     // 补齐未出现在 edge_list 中的 Peer 节点。
     251           70 :     for (const auto& peerInfo : topoInfo.peers) {
     252           48 :         NodeId nodeId = PhyTopo::Peer::GetId(peerInfo.localId);
     253           48 :         if (!graph->HasNode(nodeId)) {
     254            9 :             auto node = CreateNode(PhyTopo::Node::NodeType::PEER, peerInfo.localId);
     255            9 :             graph->AddNode(nodeId, node);
     256            9 :         }
     257              :     }
     258           22 :     PhyTopo::GetInstance()->AddTopoGraph(graph);
     259           34 :     HCCL_DEBUG("[PhyTopoBuilder::%s] Build physical topo graph success.", __func__);
     260           22 : }
     261              : 
     262           16 : void PhyTopoBuilder::RecoverBuild(const TopoInfo& topoInfo)
     263              : {
     264           16 :     std::lock_guard<std::mutex> lock(phyTopoMutex);
     265              : 
     266              :     // PhyTopo::GetInstance()->ResetInstance();
     267           16 :     if (PhyTopo::GetInstance()->IsInitFinished()) {
     268            1 :         return;
     269              :     }
     270           15 :     topoInfo_ = std::make_shared<TopoInfo>(topoInfo);
     271           15 :     BuildPhyTopo(topoInfo);
     272              : 
     273           15 :     PhyTopo::GetInstance()->InitFinish();
     274              : 
     275           15 :     HCCL_DEBUG("[PhyTopoBuilder::%s]build physic topo success.", __func__);
     276           15 :     PhyTopo::GetInstance()->Dump();
     277           16 : }
     278              : 
     279           16 : std::shared_ptr<TopoInfo> PhyTopoBuilder::GetTopoInfo() const { return topoInfo_; }
     280              : 
     281              : } // namespace Hccl
        

Generated by: LCOV version 2.0-1