LCOV - code coverage report
Current view: top level - coll_communicator_mgr/rank_graph/topo_info - topo_info.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 88.6 % 123 109
Test Date: 2026-08-25 19:18:03 Functions: 87.5 % 8 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 "topo_info.h"
      12              : #include "json_parser.h"
      13              : #include "invalid_params_exception.h"
      14              : #include "exception_util.h"
      15              : 
      16              : namespace Hccl {
      17              : 
      18              : using namespace std;
      19              : 
      20           22 : void TopoInfo::Deserialize(const nlohmann::json& topoInfoJson)
      21              : {
      22           44 :     std::string msgVersion = "[TopoInfo::Deserialize] error occurs when parser object of propName \"version\"";
      23           44 :     std::string msgPc = "[TopoInfo::Deserialize] error occurs when parser object of propName \"peer_count\"";
      24           22 :     std::string msgEc = "[TopoInfo::Deserialize] error occurs when parser object of propName \"edge_count\"";
      25           23 :     TRY_CATCH_THROW(InvalidParamsException, msgVersion, version = GetJsonProperty(topoInfoJson, "version"););
      26           21 :     TRY_CATCH_THROW(InvalidParamsException, msgPc, peerCount = GetJsonPropertyUInt(topoInfoJson, "peer_count"););
      27           21 :     TRY_CATCH_THROW(InvalidParamsException, msgEc, edgeCount = GetJsonPropertyUInt(topoInfoJson, "edge_count"););
      28              : 
      29           21 :     if (version != "2.0") {
      30            1 :         HCCL_ERROR("[TopoInfo::%s] failed with version[%s] is not \"2.0\".", __func__, version.c_str());
      31            2 :         THROW<InvalidParamsException>(StringFormat(
      32              :             "[TopoInfo::%s] failed with version[%s] is not \"2.0\" in topo file.", __func__, version.c_str()));
      33              :     }
      34              : 
      35           20 :     if (peerCount == 0 || peerCount > MAX_PEER_COUNT) {
      36            0 :         THROW<InvalidParamsException>(
      37              :             "[TopoInfo::%s] the range for the prop peer_count is [1, %u] while peer_count is %u", __func__,
      38              :             MAX_PEER_COUNT, peerCount);
      39              :     }
      40              : 
      41           20 :     if (edgeCount == 0) {
      42            4 :         HCCL_WARNING("[TopoInfo::%s]: edge_count is zero", __func__);
      43              :     }
      44              : 
      45           20 :     if (peerCount == 0 || peerCount > MAX_PEER_COUNT) {
      46            0 :         THROW<InvalidParamsException>(
      47              :             "[TopoInfo::%s] the range for the prop peer_count is [1, 65] while peer_count is %u", __func__, peerCount);
      48              :     }
      49              : 
      50           20 :     DeserializePeers(topoInfoJson);
      51           18 :     DeserializeEdges(topoInfoJson);
      52              : 
      53           14 :     u32 peer2PeerEdgeCount = 0;
      54           14 :     u32 peer2NetEdgeCount = 0;
      55          161 :     for (const auto& edge : edges) {
      56          147 :         if (edge.linkType == LinkType::PEER2PEER) {
      57           23 :             ++peer2PeerEdgeCount;
      58          124 :         } else if (edge.linkType == LinkType::PEER2NET) {
      59          124 :             ++peer2NetEdgeCount;
      60              :         }
      61              :     }
      62              : 
      63           30 :     HCCL_DEBUG(
      64              :         "[TopoInfo::%s] deserialize summary: peers[%zu], edges[%zu], PEER2PEER[%u], PEER2NET[%u]", __func__,
      65              :         peers.size(), edges.size(), peer2PeerEdgeCount, peer2NetEdgeCount);
      66           38 : }
      67              : 
      68           20 : void TopoInfo::DeserializePeers(const nlohmann::json& topoInfoJson)
      69              : {
      70           20 :     nlohmann::json peerJsons;
      71           20 :     std::string msgPl = "[TopoInfo::DeserializePeers] error occurs when parser object of propName \"peer_list\"";
      72           20 :     TRY_CATCH_THROW(InvalidParamsException, msgPl, GetJsonPropertyList(topoInfoJson, "peer_list", peerJsons););
      73          136 :     for (auto& peerJson : peerJsons) {
      74          117 :         PeerInfo peer;
      75          117 :         peer.Deserialize(peerJson);
      76              : 
      77          117 :         if (idSet.count(peer.localId) > 0) {
      78            1 :             THROW<InvalidParamsException>(
      79            3 :                 StringFormat("[TopoInfo::%s] in peers exist duplicate localId = %u.", __func__, peer.localId));
      80              :         }
      81              : 
      82          116 :         peers.emplace_back(peer);
      83          116 :         idSet.insert(peer.localId);
      84          117 :     }
      85              : 
      86           19 :     if (peerCount != peers.size()) {
      87            2 :         THROW<InvalidParamsException>(StringFormat(
      88              :             "[TopoInfo::%s] Value of peer_count[%u] is inconsistent with the size of the peer_list[%zu].", __func__,
      89              :             peerCount, peers.size()));
      90              :     }
      91           22 : }
      92              : 
      93          150 : void TopoInfo::VerifyEdges(EdgeInfo& edge)
      94              : {
      95          150 :     if (idSet.count(edge.localA) == 0 || idSet.count(edge.localB) == 0) {
      96            2 :         THROW<InvalidParamsException>(StringFormat(
      97              :             "[TopoInfo::%s] endpoint localId [%u] or [%u] is not exist in peers[%zu].", __func__, edge.localA,
      98              :             edge.localB, idSet.size()));
      99              :     }
     100              :     // net_layer 不参与边语义;线性查重合并旧 topo 重复边,复杂度 O(E²)。
     101          149 :     if (find(edges.begin(), edges.end(), edge) != edges.end()) {
     102            1 :         HCCL_DEBUG(
     103              :             "[TopoInfo::%s] ignore duplicate physical edge, linkType[%s], topoType[%s], "
     104              :             "topoInstanceId[%u], localA[%u], localB[%u].",
     105              :             __func__, edge.linkType.Describe().c_str(), edge.topoType.Describe().c_str(), edge.topoInstId, edge.localA,
     106              :             edge.localB);
     107            1 :         return;
     108              :     }
     109              : 
     110          148 :     edges.emplace_back(edge);
     111              : }
     112              : 
     113           18 : void TopoInfo::DeserializeEdges(const nlohmann::json& topoInfoJson)
     114              : {
     115           18 :     nlohmann::json edgeJsons;
     116           18 :     std::string msgPe = "[TopoInfo::DeserializeEdges] error occurs when parser object of propName \"edge_list\"";
     117           18 :     TRY_CATCH_THROW(InvalidParamsException, msgPe, GetJsonPropertyList(topoInfoJson, "edge_list", edgeJsons););
     118           18 :     if (edgeJsons.empty()) {
     119            2 :         if (edgeCount != 0) {
     120            0 :             THROW<InvalidParamsException>(StringFormat(
     121              :                 "[TopoInfo::%s] Value of edge_count[%u] is inconsistent with the size of edge_list[0].", __func__,
     122              :                 edgeCount));
     123              :         } else {
     124            2 :             HCCL_WARNING("[TopoInfo::%s] edge count is zero", __func__);
     125            2 :             return;
     126              :         }
     127              :     }
     128           16 :     if (edgeJsons.size() != edgeCount) {
     129            2 :         THROW<InvalidParamsException>(StringFormat(
     130              :             "[TopoInfo::%s] Value of edge_count[%u] is inconsistent with the size of edge_list[%zu].", __func__,
     131              :             edgeCount, edgeJsons.size()));
     132              :     }
     133          164 :     for (auto& edgeJson : edgeJsons) {
     134          152 :         EdgeInfo edge;
     135          152 :         edge.Deserialize(edgeJson);
     136          150 :         VerifyEdges(edge);
     137          152 :     }
     138              : 
     139              :     // edgeCount 对外表示去重后的物理边数量。
     140           12 :     edgeCount = static_cast<u32>(edges.size());
     141           24 : }
     142              : 
     143           13 : string TopoInfo::Describe() const
     144              : {
     145           13 :     string description = "TopoInfo{";
     146           13 :     description += StringFormat("version=%s", version.c_str());
     147           13 :     description += StringFormat(", peer_count=%u", peerCount);
     148           13 :     description += StringFormat(", edge_count=%u", edgeCount);
     149           13 :     description += StringFormat(", Peers.size=%u", peers.size());
     150           13 :     description += StringFormat(", Edges.size=%u", edges.size());
     151           13 :     description += "}";
     152           13 :     return description;
     153            0 : }
     154              : 
     155            0 : void TopoInfo::Dump() const
     156              : {
     157            0 :     HCCL_DEBUG("TopoInfo Dump:");
     158            0 :     HCCL_DEBUG("%s", Describe().c_str());
     159            0 :     HCCL_DEBUG("peers:");
     160            0 :     for (const auto& peer : peers) {
     161            0 :         HCCL_DEBUG("%s", peer.Describe().c_str());
     162              :     }
     163            0 :     HCCL_DEBUG("edges:");
     164            0 :     for (const auto& edge : edges) {
     165            0 :         HCCL_DEBUG("    %s", edge.Describe().c_str());
     166              :     }
     167            0 : }
     168              : 
     169            5 : TopoInfo::TopoInfo(BinaryStream& binaryStream)
     170              : {
     171            5 :     binaryStream >> version >> peerCount >> edgeCount;
     172            5 :     size_t peersSize = 0;
     173            5 :     binaryStream >> peersSize;
     174           78 :     for (u32 i = 0; i < peersSize; i++) {
     175           73 :         PeerInfo peer(binaryStream);
     176           73 :         peers.emplace_back(peer);
     177           73 :     }
     178            5 :     size_t edgeGroupCount = 0;
     179            5 :     binaryStream >> edgeGroupCount;
     180              : 
     181            7 :     HCCL_INFO(
     182              :         "[TopoInfo] version is [%s], peerCount is [%u], edgeCount is [%u], peers size is [%zu], "
     183              :         "edge group count is [%zu]",
     184              :         version.c_str(), peerCount, edgeCount, peers.size(), edgeGroupCount);
     185              :     // 保留旧快照分组外壳,读取后统一展开物理边。
     186           12 :     for (size_t i = 0; i < edgeGroupCount; i++) {
     187            7 :         u32 ignoredBinaryLayer = 0;
     188            7 :         size_t groupEdgeCount = 0;
     189            7 :         binaryStream >> ignoredBinaryLayer >> groupEdgeCount;
     190           83 :         for (size_t j = 0; j < groupEdgeCount; j++) {
     191           76 :             EdgeInfo edge(binaryStream);
     192              :             // 旧快照可能按 layer 重复存储同一物理边,展开时合并。
     193           76 :             if (find(edges.begin(), edges.end(), edge) == edges.end()) {
     194           75 :                 edges.emplace_back(edge);
     195              :             }
     196           76 :         }
     197              :     }
     198            5 :     edgeCount = static_cast<u32>(edges.size());
     199            5 : }
     200              : 
     201            9 : void TopoInfo::GetBinStream(BinaryStream& binaryStream) const
     202              : {
     203            9 :     binaryStream << version << peerCount << edgeCount;
     204            9 :     binaryStream << peers.size();
     205          101 :     for (auto& it : peers) {
     206           92 :         it.GetBinStream(binaryStream);
     207              :     }
     208            9 :     const size_t edgeGroupCount = edges.empty() ? 0 : 1;
     209            9 :     binaryStream << edgeGroupCount;
     210           21 :     HCCL_INFO(
     211              :         "[TopoInfo::GetBinStream] version is [%s], peerCount is [%u], edgeCount is [%u], peers size is [%zu], "
     212              :         "edges size is [%zu]",
     213              :         version.c_str(), peerCount, edgeCount, peers.size(), edges.size());
     214              :     // 新快照统一写入一个兼容分组,不恢复逻辑分层。
     215            9 :     if (!edges.empty()) {
     216            9 :         binaryStream << LEGACY_BINARY_LAYER << edges.size();
     217          156 :         for (const auto& edge : edges) {
     218          147 :             edge.GetBinStream(binaryStream);
     219              :         }
     220              :     }
     221            9 : }
     222              : 
     223              : } // namespace Hccl
        

Generated by: LCOV version 2.0-1