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 <algorithm>
12 : #include <array>
13 : #include "rank_graph_builder.h"
14 : #include "detour_service.h"
15 : #include "json_parser.h"
16 : #include "phy_topo_builder.h"
17 :
18 : namespace Hccl {
19 :
20 : using namespace std;
21 :
22 14 : unique_ptr<RankGraph> RankGraphBuilder::Build(const string& ranktableM, const string& topoPath, RankId myRank)
23 : {
24 14 : PhyTopoBuilder::GetInstance().Build(topoPath);
25 14 : topoInfo_ = PhyTopoBuilder::GetInstance().GetTopoInfo();
26 :
27 : JsonParser rankTableParser;
28 14 : RankTableInfo rankTableInfo;
29 14 : rankTableParser.ParseString(ranktableM, rankTableInfo);
30 14 : rankTable_ = make_unique<RankTableInfo>(rankTableInfo);
31 :
32 14 : this->myRank_ = myRank;
33 14 : BuildRankGraph();
34 :
35 42 : HCCL_INFO("[RankGraphBuilder] Build VirtualTopo success!");
36 14 : rankGraph_->Dump();
37 28 : return std::move(rankGraph_);
38 14 : }
39 :
40 1 : unique_ptr<RankGraph> RankGraphBuilder::Build(const RankTableInfo& ranktable, const string& topoPath, RankId myRank)
41 : {
42 1 : PhyTopoBuilder::GetInstance().Build(topoPath);
43 1 : topoInfo_ = PhyTopoBuilder::GetInstance().GetTopoInfo();
44 1 : rankTable_ = make_unique<RankTableInfo>(ranktable);
45 :
46 1 : myRank_ = myRank;
47 1 : BuildRankGraph();
48 :
49 0 : HCCL_INFO("[RankGraphBuilder] Build VirtualTopo success!");
50 0 : rankGraph_->Dump();
51 0 : return std::move(rankGraph_);
52 : }
53 :
54 60 : const RankLevelInfo& RankGraphBuilder::GetRankLevelInfoByNetLayer(const NewRankInfo& rankInfo, u32 netLayer) const
55 : {
56 60 : auto it = std::find_if(
57 150 : rankInfo.rankLevelInfos.begin(), rankInfo.rankLevelInfos.end(), [netLayer](const RankLevelInfo& levelInfo) {
58 150 : return levelInfo.netLayer == netLayer;
59 : });
60 60 : if (it == rankInfo.rankLevelInfos.end()) {
61 0 : THROW<InvalidParamsException>(StringFormat(
62 : "[RankGraphBuilder][GetRankLevelInfoByNetLayer] rankId[%u] netLayer[%u] does not exist in ranktable.",
63 0 : rankInfo.rankId, netLayer));
64 : }
65 120 : return *it;
66 : }
67 :
68 48 : std::vector<shared_ptr<PhyTopo::Link>> GetPeer2NetPhyLinks(u32 netLayer, LocalId localId)
69 : {
70 48 : const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyGraph = PhyTopo::GetInstance()->GetTopoGraph(netLayer);
71 48 : if (phyGraph == nullptr) {
72 0 : THROW<InvalidParamsException>(StringFormat(
73 : "[RankGraphBuilder][GetPhyLink] localId[%d] is not level[%u] in"
74 : " topo.json, not match rankTable.",
75 : localId, netLayer));
76 : }
77 48 : std::vector<shared_ptr<PhyTopo::Link>> links;
78 48 : phyGraph->TraverseEdge(PhyTopo::Peer::GetId(localId), [&](shared_ptr<PhyTopo::Link> link) {
79 48 : if (link != nullptr) {
80 48 : links.push_back(link);
81 : }
82 48 : });
83 :
84 48 : if (links.empty()) {
85 0 : THROW<InvalidParamsException>(
86 0 : StringFormat("[RankGraphBuilder][GetPhyLink] SourceNode localId[%d] edge does not exist.", localId));
87 : }
88 48 : return links;
89 48 : }
90 :
91 48 : void RankGraphBuilder::AddPeer2NetLink(
92 : const u32 netLayer, const string& netInstId, RankId rankId, const AddressInfo& addrInfo,
93 : const shared_ptr<NetInstance::Fabric>& fabNode, const vector<shared_ptr<PhyTopo::Link>>& links)
94 : {
95 96 : for (shared_ptr<PhyTopo::Link> link : links) {
96 48 : if (link->GetSourceIFace() == nullptr) {
97 0 : continue;
98 : }
99 48 : std::set<std::string> ports = link->GetSourceIFace()->GetPorts();
100 48 : std::set<std::string> rankGraphPorts;
101 48 : std::set_intersection(
102 : ports.begin(), ports.end(), addrInfo.ports.begin(), addrInfo.ports.end(),
103 : std::inserter(rankGraphPorts, rankGraphPorts.begin()));
104 :
105 48 : if (rankGraphPorts.empty()) {
106 : // 该地址在topo里没有对应边
107 0 : continue;
108 : }
109 : // 获取topoInstId topoType
110 48 : u32 topoInstId = link->GetTopoInstId();
111 48 : auto topoType = link->GetTopoType();
112 :
113 : // 构造 RankGraph 的 PeerIface
114 : shared_ptr<NetInstance::ConnInterface> peerIface = make_shared<NetInstance::ConnInterface>(
115 96 : addrInfo.addr, rankGraphPorts, link->GetSourceIFace()->GetPos(), LinkType::PEER2NET,
116 144 : link->GetLinkProtocols(), topoType, topoInstId);
117 : // 获取 rankId 对应 PeerNode
118 48 : shared_ptr<NetInstance::Peer> peerNode = peers_.at(rankId);
119 48 : peerNode->AddConnInterface(netLayer, peerIface);
120 :
121 : // 构造 peer2netLink 和 net2peerLink 两条link
122 : shared_ptr<NetInstance::Link> peer2netLink = make_shared<NetInstance::Link>(
123 96 : peerNode, fabNode, peerIface, nullptr, LinkType::PEER2NET, link->GetLinkProtocols(), LinkDirection::BOTH,
124 96 : 2);
125 : shared_ptr<NetInstance::Link> net2peerLink = make_shared<NetInstance::Link>(
126 96 : fabNode, peerNode, nullptr, peerIface, LinkType::PEER2NET, link->GetLinkProtocols(), LinkDirection::BOTH,
127 96 : 2);
128 :
129 : // 插入 link
130 48 : tempNetInsts_[netLayer][netInstId]->AddLink(peer2netLink);
131 48 : tempNetInsts_[netLayer][netInstId]->AddLink(net2peerLink);
132 :
133 : // 将rank插入到当前netInstance对应的topoInstance中
134 48 : tempNetInsts_[netLayer][netInstId]->UpdateTopoInst(topoInstId, topoType, rankId);
135 :
136 : // 只打印当前卡的rank_id和eid对应关系
137 48 : if (rankId == myRank_) {
138 32 : HCCL_RUN_INFO(
139 : "[RankGraphBuilder][AddPeer2NetLink] Add Peer2NetLink Net2PeerLink success. level[%u] "
140 : "netInstId[%s] rankId[%u] planeId[%s] AddrStr[%s],topoInstId[%u],topoType[%u]",
141 : netLayer, netInstId.c_str(), rankId, fabNode->GetPlaneId().c_str(), addrInfo.addr.Describe().c_str(),
142 : topoInstId, topoType);
143 : }
144 48 : }
145 48 : }
146 :
147 12 : void RankGraphBuilder::AddFabricInfo(u32 netLayer)
148 : {
149 12 : auto netInst = rankGraph_->GetNetInstanceByRankId(netLayer, myRank_);
150 12 : if (netInst == nullptr) {
151 0 : THROW<NullPtrException>(
152 0 : StringFormat("[RankGraphBuilder][AddFabricInfo] rankGraph->GetNetInstanceByRankId is nullptr"));
153 : }
154 :
155 12 : if (netInst->GetNetType() != NetType::CLOS) {
156 0 : THROW<NotSupportException>(
157 0 : StringFormat("[RankGraphBuilder][AddFabricInfo] NetInstance is not CLOS, not support add fabric."));
158 : }
159 12 : set<RankId> inRanks = netInst->GetRankIds();
160 12 : string netInstId = netInst->GetNetInstId();
161 12 : const auto& myLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[myRank_], netLayer);
162 : // 根据planeId确认Fabric个数,每个fabricId对应一个planeId
163 12 : std::map<PlaneId, FabricId> planeId2Node = GetFabricsFromAddrInfo(myLevelInfo.rankAddrs);
164 :
165 12 : if (planeId2Node.size() == 0) {
166 0 : HCCL_WARNING(
167 : "[RankGraphBuilder][AddFabricInfo] current rankId[%d] netLayer[%u] group no net plane", myRank_, netLayer);
168 0 : return;
169 : }
170 12 : vector<shared_ptr<NetInstance::Fabric>> fabNodes(planeId2Node.size(), nullptr);
171 :
172 : // 遍历每一个rankId,每个rankId都增加 peer2net 和 net2peer 两条链路
173 60 : for (RankId srcRankId : inRanks) {
174 48 : const auto& srcLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[srcRankId], netLayer);
175 48 : const vector<AddressInfo>& addrs = srcLevelInfo.rankAddrs;
176 : // rankId对应的物理逻辑localId
177 48 : LocalId localId = rankGraph_->GetLocalId(srcRankId);
178 : // 从物理拓扑图中找出 localId在 netLayer 中所有的peer2Net的边。
179 48 : std::vector<shared_ptr<PhyTopo::Link>> links = GetPeer2NetPhyLinks(netLayer, localId);
180 : // 遍历ranktable中的addr,有几个addr就有几条peer2net的边
181 96 : for (AddressInfo addrInfo : addrs) {
182 48 : if (addrInfo.addr == IpAddress()) {
183 0 : continue;
184 : }
185 :
186 48 : if (planeId2Node.count(addrInfo.planeId) == 0) {
187 0 : continue;
188 : }
189 48 : FabricId fabId = planeId2Node[addrInfo.planeId];
190 : // 若 fabNodes[fabId] 不存在则创建 如果存在则获取fabNode
191 48 : shared_ptr<NetInstance::Fabric> fabNode;
192 48 : if (fabNodes[fabId] == nullptr) {
193 12 : fabNode = make_shared<NetInstance::Fabric>(fabId, addrInfo.planeId);
194 12 : tempNetInsts_[netLayer][netInstId]->AddNode(fabNode);
195 12 : fabNodes[fabId] = fabNode;
196 : } else {
197 36 : fabNode = fabNodes[fabId];
198 : }
199 : // 插入peer和fabric的peer2net和net2peer两条link
200 48 : AddPeer2NetLink(netLayer, netInstId, srcRankId, addrInfo, fabNode, links);
201 48 : }
202 48 : }
203 :
204 32 : HCCL_DEBUG(
205 : "[RankGraphBuilder][AddFabricInfo] netLayer [%u] netInstId[%s] Add Fabric Info success!", netLayer,
206 : netInstId.c_str());
207 12 : }
208 :
209 18 : void RankGraphBuilder::AddTopoDescFabricInfo()
210 : {
211 : // 1. 获取物理拓扑图
212 18 : auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);
213 18 : if (phyTopoGraph == nullptr) {
214 0 : THROW<NullPtrException>(StringFormat("[RankGraphBuilder][AddTopoDescFabricInfo] phyTopoGraph is nullptr"));
215 : }
216 46 : HCCL_INFO("[RankGraphBuilder][AddTopoDescFabricInfo] Successfully retrieved phyTopoGraph");
217 :
218 : // 2. 获取当前 NetInstance
219 18 : NetInstance* innerNetInstance = rankGraph_->GetNetInstanceByRankId(0, myRank_);
220 18 : if (innerNetInstance == nullptr) {
221 0 : THROW<NullPtrException>(
222 0 : StringFormat("[RankGraphBuilder][AddTopoDescFabricInfo] rankGraph->GetNetInstanceByRankId is nullptr"));
223 : }
224 18 : std::string netInstId = innerNetInstance->GetNetInstId();
225 18 : std::set<RankId> rankIds = innerNetInstance->GetRankIds();
226 :
227 : // 存储所有fabric节点,key为topoInstId
228 18 : std::map<u32, std::shared_ptr<NetInstance::Fabric>> fabNodes;
229 :
230 18 : auto peer = rankGraph_->GetPeer(rankGraph_->GetMyRank());
231 18 : auto localDeviceId = peer->GetDeviceId();
232 :
233 : // 3. 遍历所有rank节点,根据topoInstId创建fabric节点
234 68 : for (RankId rankId : rankIds) {
235 50 : LocalId localId = rankGraph_->GetLocalId(rankId);
236 50 : auto peer2netEdges = phyTopoGraph->GetEdges(localId, PhyTopo::Fabric::GetId());
237 :
238 134 : HCCL_RUN_INFO(
239 : "[RankGraphBuilder][AddTopoDescFabricInfo] Processing rank %d (localId: %u), found %zu peer2net edges",
240 : rankId, localId, peer2netEdges.size());
241 :
242 126 : for (const auto& link : peer2netEdges) {
243 76 : u32 topoInstId = link->GetTopoInstId();
244 76 : auto topoType = link->GetTopoType();
245 :
246 : // 创建Fabric节点
247 76 : if (fabNodes.find(topoInstId) == fabNodes.end()) {
248 34 : auto fabNodePtr = std::make_shared<NetInstance::Fabric>(topoInstId);
249 34 : innerNetInstance->AddNode(fabNodePtr);
250 34 : fabNodes[topoInstId] = fabNodePtr;
251 98 : HCCL_INFO(
252 : "[RankGraphBuilder][AddTopoDescFabricInfo] Created new Fabric node for topoInstId: %u", topoInstId);
253 34 : }
254 :
255 : // 获取 peer 节点
256 76 : auto peerNode = peers_.at(rankId);
257 :
258 : // 构造连接接口
259 : auto peerIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(
260 76 : link->GetSourceIFace(), peerNode->GetPortAddrMapLayer0(), topoType, topoInstId, localDeviceId);
261 :
262 136 : for (const auto& iface : peerIfaces) {
263 60 : peerNode->AddConnInterface(0, iface);
264 : }
265 76 : auto fabNodePtr = fabNodes[topoInstId];
266 : // 构造 peer2netLink 和 net2peerLink(双向)
267 136 : for (const auto& iface : peerIfaces) {
268 : auto peer2netLink = std::make_shared<NetInstance::Link>(
269 120 : peerNode, fabNodePtr, iface, nullptr, LinkType::PEER2NET, link->GetLinkProtocols(),
270 120 : LinkDirection::BOTH, 2);
271 :
272 : auto net2peerLink = std::make_shared<NetInstance::Link>(
273 120 : fabNodePtr, peerNode, nullptr, iface, LinkType::PEER2NET, link->GetLinkProtocols(),
274 120 : LinkDirection::BOTH, 2);
275 :
276 : // 插入 link
277 60 : tempNetInsts_[0][netInstId]->AddLink(peer2netLink);
278 60 : tempNetInsts_[0][netInstId]->AddLink(net2peerLink);
279 60 : tempNetInsts_[0][netInstId]->UpdateTopoInst(topoInstId, topoType, rankId);
280 172 : HCCL_RUN_INFO(
281 : "[RankGraphBuilder][AddTopoDescFabricInfo] netLayer0 rankId[%u] netInstId[%s] Add Fabric "
282 : "Info success!",
283 : rankId, netInstId.c_str());
284 60 : }
285 76 : }
286 50 : }
287 46 : HCCL_INFO("[RankGraphBuilder][AddTopoDescFabricInfo] Successfully completed fabric link construction");
288 18 : }
289 :
290 12 : std::map<PlaneId, FabricId> GetFabricsFromAddrInfo(const std::vector<AddressInfo>& rankAddrs)
291 : {
292 12 : std::map<PlaneId, FabricId> planeId2FabricId;
293 24 : for (const auto& addrInfo : rankAddrs) {
294 12 : if (planeId2FabricId.count(addrInfo.planeId) == 0) {
295 12 : FabricId fabId = planeId2FabricId.size();
296 12 : planeId2FabricId[addrInfo.planeId] = fabId;
297 : }
298 : }
299 12 : return planeId2FabricId;
300 0 : }
301 :
302 99 : void RankGraphBuilder::CheckNetLayerFromPhyTopo(const u32 netLayer) const
303 : {
304 99 : if (!PhyTopo::GetInstance()->IsNetLayerExisted(netLayer)) {
305 1 : THROW<InvalidParamsException>(StringFormat(
306 : "[RankGraphBuilder][CheckNetLayerFromPhyTopo]"
307 : "netLayer[%u] not exist in topo.",
308 : netLayer));
309 : }
310 98 : }
311 :
312 : // 根据ranktable构造添加peers和NetInstances, NetInstance添加nodes和links(peer2net)
313 : // 1. 创建NetInstance ( 每个NetInstance 添加 Rank, Node, Link);
314 : // 2. RankGraph中添加NetInstance, Peer, Fabric,
315 19 : void RankGraphBuilder::BuildFromRankTable()
316 : {
317 : // 保存NetInstance指针以便后续执行Add操作
318 19 : tempNetInsts_.resize(MAX_NET_LAYER); // 为了方便修改RankGraph的NetInstance,共享指针。
319 :
320 : // 遍历rankTable每一个rank, virtualTopo添加Peers
321 69 : for (const auto& rankInfo : rankTable_->ranks) {
322 51 : updaterFor64Plus1_.SaveReplaceInfo(rankInfo); // 暂存备份替换信息
323 51 : RankId rankId = rankInfo.rankId;
324 : shared_ptr<NetInstance::Peer> peer = make_shared<NetInstance::Peer>(
325 51 : rankId, rankInfo.localId, rankInfo.replacedLocalId, rankInfo.deviceId, rankInfo.devicePort,
326 51 : rankInfo.hostPort);
327 51 : rankGraph_->AddPeer(peer);
328 51 : peers_.emplace(rankId, peer); // rankid2peer
329 :
330 : // 构造当前rank的每个LevelInfo所在NetInstance, 添加 RankId 和 Peer
331 149 : for (const auto& levelInfo : rankInfo.rankLevelInfos) {
332 : // 校验netLayer是否在topo中
333 99 : CheckNetLayerFromPhyTopo(levelInfo.netLayer);
334 : // rankLevelInfo.level、id对应NetInstance,若不存在则创建
335 : auto curNetInstance = GetOrCreateNetInstance(
336 98 : levelInfo.netLayer, levelInfo.netInstId, levelInfo.netType, tempNetInsts_, rankGraph_.get());
337 98 : if (curNetInstance == nullptr) {
338 0 : continue;
339 : }
340 : // NetInstance add Peer
341 98 : curNetInstance->AddRankId(rankId);
342 98 : curNetInstance->AddNode(peer);
343 : // Peer add NetInstance
344 98 : peer->AddNetInstance(curNetInstance);
345 98 : if (levelInfo.netLayer == 0) {
346 50 : peer->SetPortPortAddrMapLayer0(levelInfo.portAddrMap);
347 : }
348 262 : HCCL_DEBUG(
349 : "[RankGraphBuilder][BuildFromRankTable] rankLevelInfo : rankId[%d] level[%u] "
350 : "netInstId[%s] fabricType[%s].",
351 : rankId, levelInfo.netLayer, levelInfo.netInstId.c_str(), levelInfo.netType.Describe().c_str());
352 98 : }
353 51 : }
354 :
355 : // 对 myrank 所在每个level的NetInstance 添加 Fabrics 和 links(peer2net)
356 18 : set<u32> myLevels = rankGraph_->GetLevels(myRank_);
357 46 : HCCL_DEBUG("myRank netType: level size %u", myLevels.size());
358 48 : for (u32 level : myLevels) {
359 30 : if (level == 0) {
360 18 : AddTopoDescFabricInfo();
361 : } else {
362 12 : AddFabricInfo(level);
363 : }
364 : }
365 :
366 : // 初始化innerRanks
367 18 : rankGraph_->InitInnerRanks();
368 :
369 46 : HCCL_DEBUG("[RankGraphBuilder][BuildFromRankTable] Build VirtualTopo from RankTable success!");
370 18 : }
371 :
372 18 : void RankGraphBuilder::SetEndpointDesc()
373 : {
374 18 : std::shared_ptr<NetInstance::Peer> peer = peers_[myRank_];
375 18 : CHK_PRT_THROW(
376 : peer == nullptr, HCCL_ERROR("[RankGraphBuilder::%s] fail", __func__), NullPtrException, "peer is null");
377 : // 获取 peer 的 Iface
378 18 : std::set<u32> layers = peer->GetLevels();
379 48 : for (const auto& layer : layers) {
380 30 : auto ifacesVec = peer->GetIfacesByLayer(layer);
381 89 : for (const auto& iface : ifacesVec) {
382 59 : const auto& protocols = iface->GetLinkProtocols();
383 118 : for (const auto& protocol : protocols) {
384 59 : EndpointDesc desc{};
385 :
386 59 : HcclResult ret = GetCommAddr(desc.commAddr, iface->GetAddr());
387 59 : CHK_PRT_THROW(
388 : ret != HCCL_SUCCESS, HCCL_ERROR("[RankGraphBuilder::%s] fail", __func__), InternalException,
389 : "GetCommAddr fail");
390 :
391 59 : desc.protocol = LinkProtocolToCommProtocol(protocol);
392 59 : desc.loc.locType = AddrPositionToEndpointLoc(iface->GetPos());
393 :
394 165 : HCCL_INFO(
395 : "[RankGraphBuilder::SetEndpointDesc] local type[%d] protocol[%d]", desc.loc.locType, desc.protocol);
396 :
397 59 : peer->SetEndpointToIface(desc.commAddr, desc.protocol, iface);
398 : }
399 59 : }
400 30 : }
401 18 : }
402 :
403 0 : std::shared_ptr<NetInstance> RankGraphBuilder::GetNetInstance(const RankLevelInfo& levelInfo)
404 : {
405 0 : auto it = tempNetInsts_[levelInfo.netLayer].find(levelInfo.netInstId);
406 0 : if (it == tempNetInsts_[levelInfo.netLayer].end()) {
407 0 : return nullptr;
408 : }
409 : // 若NetInstance存在, type不一致则报错
410 0 : NetType netType = it->second->GetNetType();
411 0 : if (netType != levelInfo.netType) {
412 0 : HCCL_WARNING(
413 : "[CreateNetInstance]FabType [%s] and [%s] no match", netType.Describe().c_str(),
414 : levelInfo.netType.Describe().c_str());
415 0 : return nullptr;
416 : }
417 0 : return it->second;
418 : }
419 :
420 0 : std::shared_ptr<NetInstance> RankGraphBuilder::CreateNetInstance(const RankLevelInfo& levelInfo)
421 : {
422 0 : std::shared_ptr<NetInstance> netInst;
423 0 : if (levelInfo.netType == NetType::TOPO_FILE_DESC) {
424 0 : netInst = std::make_shared<InnerNetInstance>(levelInfo.netLayer, levelInfo.netInstId);
425 0 : } else if (levelInfo.netType == NetType::CLOS) {
426 0 : netInst = std::make_shared<ClosNetInstance>(levelInfo.netLayer, levelInfo.netInstId);
427 : } else {
428 0 : THROW<NotSupportException>(
429 0 : StringFormat("[RankGraphBuilder][CreateNetInstance] netType: %s is not support", levelInfo.netType));
430 : }
431 0 : return netInst;
432 0 : }
433 :
434 : // 从phytopo和ranktable中读取数据共同构建peer2peer的边。
435 18 : void RankGraphBuilder::BuildPeer2PeerLinks()
436 : {
437 18 : auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);
438 18 : if (phyTopoGraph == nullptr) {
439 0 : THROW<NullPtrException>(StringFormat("[RankGraphBuilder][BuildPeer2PeerLinks] phyTopoGraph is nullptr"));
440 : }
441 : // 遍历innerNetInstance中的每两个rankId之间是否存在边,存在则添加peer2peerlink
442 18 : NetInstance* innerNetInstance = rankGraph_->GetNetInstanceByRankId(0, myRank_);
443 18 : if (innerNetInstance == nullptr) {
444 0 : THROW<NullPtrException>(StringFormat("[RankGraphBuilder][BuildPeer2PeerLinks] innerNetInstance is nullptr"));
445 : }
446 18 : set<RankId> rankIds = innerNetInstance->GetRankIds();
447 :
448 18 : auto peer = rankGraph_->GetPeer(rankGraph_->GetMyRank());
449 18 : auto localDeviceId = peer->GetDeviceId();
450 68 : for (const auto srcRankId : rankIds) {
451 212 : for (const auto dstRankId : rankIds) {
452 162 : if (srcRankId == dstRankId) {
453 56 : continue;
454 : }
455 :
456 : // 得到phyTopoGraph中对应的localId
457 112 : LocalId srcLocalId = rankGraph_->GetLocalId(srcRankId);
458 112 : LocalId dstLocalId = rankGraph_->GetLocalId(dstRankId);
459 112 : if (srcLocalId == BACKUP_LOCAL_ID || dstLocalId == BACKUP_LOCAL_ID) {
460 6 : continue;
461 : }
462 :
463 : std::vector<shared_ptr<PhyTopo::Link>> phyLinks
464 106 : = GetPeer2PeerPhyLinks(phyTopoGraph, srcLocalId, dstLocalId);
465 : // 根据ports在ranktable找对对应的地址,几个地址就有几条link。
466 :
467 106 : shared_ptr<NetInstance::Peer> srcPeer = peers_.at(srcRankId);
468 106 : shared_ptr<NetInstance::Peer> dstPeer = peers_.at(dstRankId);
469 :
470 200 : for (shared_ptr<PhyTopo::Link> phyLink : phyLinks) {
471 : auto sourceIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(
472 188 : phyLink->GetSourceIFace(), srcPeer->GetPortAddrMapLayer0(), phyLink->GetTopoType(),
473 188 : phyLink->GetTopoInstId(), localDeviceId);
474 : auto targetIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(
475 188 : phyLink->GetTargetIFace(), dstPeer->GetPortAddrMapLayer0(), phyLink->GetTopoType(),
476 188 : phyLink->GetTopoInstId(), localDeviceId);
477 94 : if (sourceIfaces.empty() || targetIfaces.empty()) {
478 : // 没有可用的接口。
479 0 : HCCL_WARNING(
480 : "[RankGraphBuilder][BuildPeer2PeerLinks] no available interface, "
481 : "srcRankId[%u] dstRankId[%u].",
482 : srcRankId, dstRankId);
483 0 : continue;
484 0 : }
485 94 : srcPeer->AddConnInterfaces(0, sourceIfaces);
486 94 : dstPeer->AddConnInterfaces(0, targetIfaces);
487 : std::vector<shared_ptr<NetInstance::Link>> links
488 94 : = ConstructLinks(srcPeer, dstPeer, sourceIfaces, targetIfaces, phyLink);
489 188 : for (auto link : links) {
490 94 : innerNetInstance->AddLink(link);
491 94 : }
492 94 : }
493 106 : }
494 : }
495 18 : }
496 :
497 18 : void RankGraphBuilder::UpdateTopoInstForMyRankOnly()
498 : {
499 18 : auto innerNetInstance = rankGraph_->GetNetInstanceByRankId(0, myRank_);
500 18 : if (innerNetInstance == nullptr) {
501 0 : THROW<NullPtrException>(
502 0 : StringFormat("[RankGraphBuilder][UpdateTopoInstForMyRankOnly] innerNetInstance is nullptr"));
503 : }
504 :
505 18 : auto netInstId = innerNetInstance->GetNetInstId();
506 18 : set<RankId> rankIds = innerNetInstance->GetRankIds();
507 :
508 18 : auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);
509 18 : if (phyTopoGraph == nullptr) {
510 0 : THROW<NullPtrException>(
511 0 : StringFormat("[RankGraphBuilder][UpdateTopoInstForMyRankOnly] phyTopoGraph is nullptr"));
512 : }
513 18 : if (rankIds.size() == 1) {
514 : // 单卡场景直接返回1DMESH
515 2 : RankId singleId = *rankIds.begin();
516 2 : tempNetInsts_[0][netInstId]->UpdateTopoInst(0, TopoType::MESH_1D, singleId);
517 2 : return;
518 : }
519 :
520 64 : for (const auto srcRankId : rankIds) {
521 208 : for (const auto dstRankId : rankIds) {
522 : // 只处理涉及 myRank_ 的边
523 160 : if (srcRankId != myRank_ && dstRankId != myRank_) {
524 80 : continue;
525 : }
526 :
527 80 : LocalId srcLocalId = rankGraph_->GetLocalId(srcRankId);
528 80 : LocalId dstLocalId = rankGraph_->GetLocalId(dstRankId);
529 :
530 : std::vector<shared_ptr<PhyTopo::Link>> phyLinks
531 80 : = GetPeer2PeerPhyLinks(phyTopoGraph, srcLocalId, dstLocalId);
532 :
533 134 : for (shared_ptr<PhyTopo::Link> phyLink : phyLinks) {
534 54 : u32 topoInstId = phyLink->GetTopoInstId();
535 54 : auto topoType = phyLink->GetTopoType();
536 54 : tempNetInsts_[0][netInstId]->UpdateTopoInst(topoInstId, topoType, dstRankId);
537 54 : }
538 80 : }
539 : }
540 22 : }
541 :
542 264 : std::vector<std::shared_ptr<NetInstance::ConnInterface>> ConstructConnIFromPhyTopoConnIAndPortMap(
543 : std::shared_ptr<PhyTopo::ConnInterface> phyConnIFace,
544 : const std::map<std::string, std::vector<IpAddress>>& portAddrMap, const TopoType topoType, const u32 topoInstId,
545 : u32 localDeviceId)
546 : {
547 264 : std::vector<std::shared_ptr<NetInstance::ConnInterface>> netConnIFaces;
548 264 : std::set<string> phyPorts = phyConnIFace->GetPorts();
549 264 : std::map<IpAddress, std::set<string>> addr2Ports;
550 544 : for (auto port : phyPorts) {
551 280 : if (*(phyConnIFace->GetLinkProtocols().begin()) == LinkProtocol::PCIE) {
552 0 : IpAddress tempIp;
553 0 : HrtRaSocketGetVnicIpInfos(localDeviceId, DeviceIdType::DEVICE_ID_TYPE_PHY_ID, localDeviceId, tempIp);
554 0 : auto it = addr2Ports.find(tempIp);
555 0 : if (it == addr2Ports.end()) {
556 0 : std::set<std::string> newPorts;
557 0 : newPorts.insert("d2h");
558 0 : addr2Ports[tempIp] = newPorts;
559 0 : } else {
560 0 : it->second.insert("d2h");
561 : }
562 : } else {
563 280 : auto itPort = portAddrMap.find(port);
564 280 : if (itPort == portAddrMap.end()) {
565 84 : HCCL_WARNING(
566 : "[RankGraphBuilder][ConstructConnIFromPhyTopoConnIAndPortMap] topo use port [%s] not find addrs in "
567 : "ranktable.",
568 : port.c_str());
569 28 : continue;
570 28 : }
571 504 : for (auto addr : itPort->second) {
572 252 : auto it = addr2Ports.find(addr);
573 252 : if (it == addr2Ports.end()) {
574 248 : std::set<std::string> newPorts;
575 248 : newPorts.insert(port);
576 248 : addr2Ports[addr] = newPorts;
577 248 : } else {
578 12 : it->second.insert("8080");
579 : }
580 : }
581 : }
582 280 : }
583 :
584 512 : for (auto it = addr2Ports.begin(); it != addr2Ports.end(); ++it) {
585 248 : auto linkType = *(phyConnIFace->GetLinkProtocols().begin()) == LinkProtocol::PCIE ? LinkType::PEER2NET :
586 248 : LinkType::PEER2PEER;
587 : shared_ptr<NetInstance::ConnInterface> netConnIFace = make_shared<NetInstance::ConnInterface>(
588 496 : it->first, it->second, phyConnIFace->GetPos(), linkType, phyConnIFace->GetLinkProtocols(), topoType,
589 248 : topoInstId);
590 248 : netConnIFaces.push_back(netConnIFace);
591 248 : }
592 264 : return netConnIFaces;
593 264 : }
594 :
595 94 : std::vector<shared_ptr<NetInstance::Link>> ConstructLinks(
596 : shared_ptr<NetInstance::Peer> srcPeer, shared_ptr<NetInstance::Peer> dstPeer,
597 : std::vector<std::shared_ptr<NetInstance::ConnInterface>> sourceIfaces,
598 : std::vector<std::shared_ptr<NetInstance::ConnInterface>> targetIfaces, shared_ptr<PhyTopo::Link> phyLink)
599 : {
600 94 : std::vector<shared_ptr<NetInstance::Link>> links;
601 188 : for (auto sourceIFace : sourceIfaces) {
602 188 : for (auto targetIFace : targetIfaces) {
603 : shared_ptr<NetInstance::Link> link = make_shared<NetInstance::Link>(
604 94 : srcPeer, dstPeer, sourceIFace, targetIFace, LinkType::PEER2PEER, phyLink->GetLinkProtocols());
605 94 : links.push_back(link);
606 94 : }
607 94 : }
608 94 : return links;
609 0 : }
610 :
611 186 : std::vector<std::shared_ptr<PhyTopo::Link>> GetPeer2PeerPhyLinks(
612 : std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyTopoGraph, LocalId srcLocalId, LocalId dstLocalId)
613 : {
614 186 : std::vector<shared_ptr<PhyTopo::Link>> links;
615 186 : if (!phyTopoGraph->HasNode(srcLocalId) || !phyTopoGraph->HasNode(dstLocalId)) {
616 0 : HCCL_WARNING(
617 : "[RankGraphBuilder][BuildFromPhytopo] srcLocalId[%u] dstLocalId[%u] not exist in phyTopoGraph.", srcLocalId,
618 : dstLocalId);
619 0 : return links;
620 : }
621 : // 得到phyTopoGraph对应的NodeId
622 186 : NodeId srcNodeId = PhyTopo::Peer::GetId(srcLocalId);
623 186 : NodeId dstNodeId = PhyTopo::Peer::GetId(dstLocalId);
624 :
625 186 : phyTopoGraph->TraverseEdge(srcNodeId, dstNodeId, [&](shared_ptr<PhyTopo::Link> link) {
626 148 : if (link != nullptr) {
627 148 : links.push_back(link);
628 : }
629 148 : });
630 186 : if (links.empty()) {
631 90 : HCCL_WARNING(
632 : "[RankGraphBuilder][GetPeer2PeerPhyLinks] srcLocalId[%u] dstLocalId[%u] edge does not exist.", srcLocalId,
633 : dstLocalId);
634 : }
635 186 : return links;
636 0 : }
637 :
638 21 : void RankGraphBuilder::CheckMyRankInRankTable() const
639 : {
640 21 : if (myRank_ >= static_cast<s32>(rankTable_->rankCount)) {
641 1 : THROW<InvalidParamsException>(StringFormat(
642 : "[RankGraphBuilder][CheckMyRankInRankTable]"
643 : "myRank[%d] is not in rankTable rankCount[%u].",
644 1 : myRank_, rankTable_->rankCount));
645 : }
646 20 : }
647 :
648 21 : void RankGraphBuilder::BuildRankGraph()
649 : {
650 : // 创建VirtualTopo
651 21 : rankGraph_ = make_unique<RankGraph>(myRank_);
652 :
653 : // 校验myRank在rankTable中
654 21 : CheckMyRankInRankTable();
655 :
656 : // 根据ranktable构造添加peers和NetInstances, 每个NetInstance添加nodes和links(peer2net)
657 20 : BuildFromRankTable();
658 :
659 : // 根据phytopo构造添加InnerGroup中的links(peer2peer), 不包括备份节点
660 19 : BuildPeer2PeerLinks();
661 :
662 : // 使用备份D时需要修改虚拟拓扑
663 19 : updaterFor64Plus1_.UpdateRankGraph(rankGraph_.get(), rankTable_.get());
664 :
665 : // 为myrank的peer2peer更新topoInst
666 19 : UpdateTopoInstForMyRankOnly();
667 :
668 : // 添加绕路 绕路获取
669 19 : DetourService::GetInstance().InsertDetourLinks(rankGraph_.get(), rankTable_.get());
670 :
671 : // 设置endpoint
672 19 : SetEndpointDesc();
673 :
674 : // 构造完成
675 19 : rankGraph_->InitFinish();
676 19 : }
677 :
678 6 : std::unique_ptr<RankTableInfo> RankGraphBuilder::GetRankTableInfo() { return move(rankTable_); }
679 :
680 5 : std::shared_ptr<TopoInfo> RankGraphBuilder::GetTopoInfo() { return topoInfo_; }
681 :
682 : unique_ptr<RankGraph>
683 5 : RankGraphBuilder::RecoverBuild(const RankTableInfo& rankTableInfo, const TopoInfo& topoInfo, RankId myRank)
684 : {
685 5 : topoInfo_ = std::make_shared<TopoInfo>(topoInfo);
686 5 : PhyTopoBuilder::GetInstance().RecoverBuild(*topoInfo_);
687 :
688 5 : rankTable_ = make_unique<RankTableInfo>(rankTableInfo);
689 5 : HCCL_INFO(
690 : "[%s] RankTable[%s] RankTableInfo[%s]", __func__, rankTable_->Describe().c_str(),
691 : rankTableInfo.Describe().c_str());
692 :
693 5 : this->myRank_ = myRank;
694 5 : BuildRankGraph();
695 :
696 4 : HCCL_INFO("[RankGraphBuilder] Build VirtualTopo success!");
697 4 : rankGraph_->Dump();
698 4 : return std::move(rankGraph_);
699 : }
700 :
701 : } // namespace Hccl
|