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