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: 89.2 % 157 140
Test Date: 2026-08-18 17:47:01 Functions: 100.0 % 13 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 "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           48 : PhyTopoBuilder& PhyTopoBuilder::GetInstance()
      22              : {
      23           48 :     static PhyTopoBuilder phyTopoBuilder;
      24           48 :     return phyTopoBuilder;
      25              : }
      26              : 
      27              : // 根据nodeType和localId创建节点
      28           70 : std::shared_ptr<PhyTopo::Node> CreateNode(const PhyTopo::Node::NodeType nodeType, const LocalId localId)
      29              : {
      30           70 :     if (nodeType == PhyTopo::Node::NodeType::PEER) {
      31           54 :         return std::make_shared<PhyTopo::Peer>(localId);
      32              :     } else {
      33           16 :         return std::make_shared<PhyTopo::Fabric>();
      34              :     }
      35              : }
      36              : 
      37           15 : void PhyTopoBuilder::Build(const std::string& topoPath)
      38              : {
      39           15 :     std::lock_guard<std::mutex> lock(phyTopoMutex);
      40              : 
      41           15 :     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            4 :     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           12 :     HCCL_DEBUG("[PhyTopoBuilder::%s]Start to build physic topo.", __func__);
      57              : 
      58            4 :     auto topoInfo = LoadTopoInfo(topoPath);
      59              :     // 根据topoInfo,按netLayer构造Graph
      60           10 :     for (const auto& iter : topoInfo->edges) {
      61            6 :         auto netLayer = iter.first;
      62            6 :         auto graph = CreateGraph(iter.second);
      63            6 :         PhyTopo::GetInstance()->AddTopoGraph(netLayer, graph);
      64           18 :         HCCL_DEBUG("[PhyTopoBuilder::%s]Build netLayer[%u] topo graph success.", __func__, netLayer);
      65            6 :     }
      66              : 
      67              :     // 遍历peerList,把peerList中的localId构造peer节点,加到layer-0的graph中
      68            4 :     auto graph = PhyTopo::GetInstance()->GetTopoGraph(0);
      69            4 :     if (graph == nullptr) {
      70            0 :         HCCL_INFO("[PhyTopoBuilder::%s] layer0 graph is nullptr, build now", __func__);
      71            0 :         graph = make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
      72            0 :         PhyTopo::GetInstance()->AddTopoGraph(0, graph);
      73              :     }
      74           19 :     for (const auto& iter : topoInfo->peers) {
      75              :         // 判断当前layer0的graph有没有这个节点
      76           15 :         if (!graph->HasNode(iter.localId)) {
      77            0 :             auto node = CreateNode(PhyTopo::Node::NodeType::PEER, iter.localId);
      78            0 :             graph->AddNode(iter.localId, node);
      79            0 :         }
      80              :     }
      81              : 
      82            4 :     PhyTopo::GetInstance()->InitFinish();
      83              : 
      84           12 :     HCCL_DEBUG("[PhyTopoBuilder::%s]build physic topo success.", __func__);
      85            4 :     PhyTopo::GetInstance()->Dump();
      86           15 : }
      87              : 
      88            7 : std::shared_ptr<TopoInfo> PhyTopoBuilder::LoadTopoInfo(const std::string& topoPath)
      89              : {
      90            7 :     std::shared_ptr<TopoInfo> topoInfo = std::make_shared<TopoInfo>();
      91              :     // 检查是否为非法路径以及size的大小。
      92              :     struct stat fileStat;
      93            7 :     if (stat(topoPath.c_str(), &fileStat) != 0) {
      94            2 :         HCCL_ERROR(
      95              :             "[PhyTopoBuilder][LoadTopoInfo] Get file stat failed, file path:%s, errno:%d, error: %s", topoPath.c_str(),
      96              :             errno, strerror(errno));
      97            2 :         THROW<InvalidParamsException>(
      98              :             "[PhyTopoBuilder][LoadTopoInfo]Get file stat failed, file path:%s, errno:%d, error: %s", topoPath.c_str(),
      99            2 :             errno, strerror(errno));
     100              :     }
     101              : 
     102            5 :     u64 topoFileSize = static_cast<u64>(fileStat.st_size);
     103            5 :     if (topoFileSize > SUPPORT_MAX_TOPOFILE_SIZE || topoFileSize <= 0) {
     104            1 :         HCCL_ERROR(
     105              :             "[PhyTopoBuilder][LoadTopoInfo] topoFileSize size: %llu, topoFile must be greater than 0 and less than %u",
     106              :             topoFileSize, SUPPORT_MAX_TOPOFILE_SIZE);
     107            2 :         THROW<InvalidParamsException>(StringFormat(
     108              :             "[PhyTopoBuilder][LoadTopoInfo]file %s size (%llu bytes) exceeds max allowed size (%u bytes)",
     109              :             topoPath.c_str(), topoFileSize, SUPPORT_MAX_TOPOFILE_SIZE));
     110              :     }
     111              : 
     112              :     JsonParser topoParser;
     113            4 :     topoParser.ParseFile(topoPath, *topoInfo);
     114            4 :     topoInfo_ = topoInfo;
     115            4 :     return topoInfo;
     116            3 : }
     117              : 
     118           52 : shared_ptr<PhyTopo::Link> CreatePeer2PeerLink(const LinkParams& params)
     119              : {
     120           52 :     LinkType linkType = LinkType::PEER2PEER;
     121              :     auto srcIface
     122           52 :         = std::make_shared<PhyTopo::ConnInterface>(params.localAPorts, params.position, linkType, params.protocols);
     123              :     auto dstIface
     124           52 :         = std::make_shared<PhyTopo::ConnInterface>(params.localBPorts, params.position, linkType, params.protocols);
     125           52 :     PhyTopo::LinkAttributes linkAttrs;
     126           52 :     linkAttrs.linktype = linkType;
     127           52 :     linkAttrs.protocols = params.protocols;
     128              :     auto link = std::make_shared<PhyTopo::Link>(
     129           52 :         params.srcNode, params.dstNode, linkAttrs, params.topoType, params.topoInstanceId);
     130           52 :     link->SetSourceIface(srcIface);
     131           52 :     params.srcNode->AddConnInterface(srcIface);
     132           52 :     link->SetTargetIface(dstIface);
     133           52 :     params.dstNode->AddConnInterface(dstIface);
     134          104 :     return {link};
     135           52 : }
     136              : 
     137          116 : shared_ptr<PhyTopo::Link> CreatePeer2NetLink(const LinkParams& params)
     138              : {
     139          116 :     LinkType linkType = LinkType::PEER2NET;
     140              :     auto srcIface
     141          116 :         = std::make_shared<PhyTopo::ConnInterface>(params.localAPorts, params.position, linkType, params.protocols);
     142              :     // fabric 没有ports
     143          116 :     std::set<std::string> ports{};
     144          116 :     auto dstIface = std::make_shared<PhyTopo::ConnInterface>(ports, params.position, linkType, params.protocols);
     145          116 :     PhyTopo::LinkAttributes linkAttrs;
     146          116 :     linkAttrs.linktype = linkType;
     147          116 :     linkAttrs.protocols = params.protocols;
     148              :     auto link = std::make_shared<PhyTopo::Link>(
     149          116 :         params.srcNode, params.dstNode, linkAttrs, params.topoType, params.topoInstanceId);
     150          116 :     link->SetSourceIface(srcIface);
     151          116 :     params.srcNode->AddConnInterface(srcIface);
     152          116 :     link->SetTargetIface(dstIface);
     153          116 :     params.dstNode->AddConnInterface(dstIface);
     154          232 :     return {link};
     155          116 : }
     156              : 
     157              : // 根据链路类型建链
     158          168 : shared_ptr<PhyTopo::Link> CreateLink(const LinkType linkType, const LinkParams& params)
     159              : {
     160          168 :     if (linkType == LinkType::PEER2PEER) {
     161           52 :         return CreatePeer2PeerLink(params);
     162              :     } else {
     163          116 :         return CreatePeer2NetLink(params);
     164              :     }
     165              : }
     166              : 
     167          168 : NodeId GetNodeId(const PhyTopo::Node::NodeType nodeType, LocalId localId)
     168              : {
     169          168 :     switch (nodeType) {
     170          110 :         case PhyTopo::Node::NodeType::PEER:
     171          110 :             return PhyTopo::Peer::GetId(localId);
     172           58 :         case PhyTopo::Node::NodeType::FABRIC:
     173           58 :             return PhyTopo::Fabric::GetId();
     174            0 :         default:
     175            0 :             THROW<InvalidParamsException>(StringFormat("[PhyTopoBuilder]Invalid NodeType."));
     176              :             return 0;
     177              :     }
     178              : }
     179              : 
     180              : std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>
     181           21 : PhyTopoBuilder::CreateGraph(const std::vector<EdgeInfo>& edges) const
     182              : {
     183           21 :     auto graph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
     184              : 
     185          105 :     for (const auto& edgeInfo : edges) {
     186           84 :         std::shared_ptr<PhyTopo::Node> nodeA;
     187           84 :         std::shared_ptr<PhyTopo::Node> nodeB;
     188              : 
     189              :         // 生成 nodeAId,localA 始终为 PEER 类型
     190           84 :         NodeId nodeAId = GetNodeId(PhyTopo::Node::NodeType::PEER, edgeInfo.localA);
     191              :         // 获取或创建 nodeA
     192           84 :         if (!graph->HasNode(nodeAId)) {
     193           35 :             nodeA = CreateNode(PhyTopo::Node::NodeType::PEER, edgeInfo.localA);
     194           35 :             graph->AddNode(nodeAId, nodeA);
     195           61 :             HCCL_DEBUG("[PhyTopoBuilder::%s] Add node[%llu] success.", __func__, nodeAId);
     196              :         } else {
     197              :             // 使用 TraverseNode 查找 nodeA
     198           49 :             graph->TraverseNode([&nodeA, nodeAId](NodeId id, const std::shared_ptr<PhyTopo::Node>& n) {
     199          185 :                 if (id == nodeAId) {
     200           49 :                     nodeA = n;
     201              :                 }
     202          185 :             });
     203           49 :             if (nodeA == nullptr) {
     204            0 :                 HCCL_ERROR("[PhyTopoBuilder::CreateGraph] nodeAId [%llu] not found.", nodeAId);
     205            0 :                 THROW<NullPtrException>(
     206            0 :                     StringFormat("[PhyTopoBuilder::CreateGraph] Unable to find node [%llu].", nodeAId));
     207              :             }
     208              :         }
     209              : 
     210              :         // 根据 linkType 生成 nodeBId
     211           84 :         PhyTopo::Node::NodeType nodeBType;
     212           84 :         if (edgeInfo.linkType == LinkType::PEER2PEER) {
     213           26 :             nodeBType = PhyTopo::Node::NodeType::PEER;
     214              :         } else {
     215           58 :             nodeBType = PhyTopo::Node::NodeType::FABRIC;
     216              :         }
     217              : 
     218           84 :         NodeId nodeBId = GetNodeId(nodeBType, edgeInfo.localB);
     219              :         // 获取或创建 nodeB
     220           84 :         if (!graph->HasNode(nodeBId)) {
     221           35 :             nodeB = CreateNode(nodeBType, edgeInfo.localB);
     222           35 :             graph->AddNode(nodeBId, nodeB);
     223           63 :             HCCL_DEBUG("[PhyTopoBuilder::%s] Add node[%llu] success.", __func__, nodeBId);
     224              :         } else {
     225              :             // 使用 TraverseNode 查找 nodeB
     226           49 :             graph->TraverseNode([&nodeB, nodeBId](NodeId id, const std::shared_ptr<PhyTopo::Node>& n) {
     227          206 :                 if (id == nodeBId) {
     228           49 :                     nodeB = n;
     229              :                 }
     230          206 :             });
     231           49 :             if (nodeB == nullptr) {
     232            0 :                 HCCL_ERROR("[PhyTopoBuilder::CreateGraph] nodeBId [%llu] not found.", nodeBId);
     233            0 :                 THROW<NullPtrException>(
     234            0 :                     StringFormat("[PhyTopoBuilder::CreateGraph] Unable to find node [%llu].", nodeBId));
     235              :             }
     236              :         }
     237              : 
     238              :         // 双向分别创建link
     239              :         LinkParams abLinkParams{
     240              :             nodeA,
     241              :             nodeB,
     242           84 :             edgeInfo.localAPorts,
     243           84 :             edgeInfo.localBPorts,
     244              :             edgeInfo.position,
     245              :             edgeInfo.topoType,
     246           84 :             edgeInfo.topoInstId,
     247           84 :             edgeInfo.protocols};
     248           84 :         auto abLinks = CreateLink(edgeInfo.linkType, abLinkParams);
     249           84 :         graph->AddEdge(nodeAId, nodeBId, abLinks);
     250              :         LinkParams baLinkParams{
     251              :             nodeB,
     252              :             nodeA,
     253           84 :             edgeInfo.localBPorts,
     254           84 :             edgeInfo.localAPorts,
     255              :             edgeInfo.position,
     256              :             edgeInfo.topoType,
     257           84 :             edgeInfo.topoInstId,
     258           84 :             edgeInfo.protocols};
     259           84 :         auto baLinks = CreateLink(edgeInfo.linkType, baLinkParams);
     260           84 :         graph->AddEdge(nodeBId, nodeAId, baLinks);
     261           84 :     }
     262              : 
     263           21 :     return graph;
     264            0 : }
     265              : 
     266           11 : void PhyTopoBuilder::RecoverBuild(const TopoInfo& topoInfo)
     267              : {
     268           11 :     std::lock_guard<std::mutex> lock(phyTopoMutex);
     269              : 
     270              :     // PhyTopo::GetInstance()->ResetInstance();
     271           11 :     if (PhyTopo::GetInstance()->IsInitFinished()) {
     272            1 :         return;
     273              :     }
     274              :     // 根据topoInfo,按netLayer构造Graph
     275           21 :     for (const auto& iter : topoInfo.edges) {
     276           11 :         auto netLayer = iter.first;
     277           11 :         auto graph = CreateGraph(iter.second);
     278           11 :         PhyTopo::GetInstance()->AddTopoGraph(netLayer, graph);
     279           11 :         HCCL_DEBUG("[PhyTopoBuilder::%s]Build netLayer[%u] topo graph success.", __func__, netLayer);
     280           11 :     }
     281              : 
     282           10 :     PhyTopo::GetInstance()->InitFinish();
     283              : 
     284           10 :     HCCL_DEBUG("[PhyTopoBuilder::%s]build physic topo success.", __func__);
     285           10 :     PhyTopo::GetInstance()->Dump();
     286           11 : }
     287              : 
     288           15 : std::shared_ptr<TopoInfo> PhyTopoBuilder::GetTopoInfo() const { return topoInfo_; }
     289              : 
     290              : } // namespace Hccl
        

Generated by: LCOV version 2.0-1