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
|