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 "detour_service.h"
12 : #include "env_config/env_config_v2.h"
13 : #include "detour_rules.h"
14 : #include "not_support_exception.h"
15 :
16 : namespace Hccl {
17 :
18 : using namespace std;
19 :
20 : constexpr u32 DETOUR_NODE_NUM = 8;
21 : constexpr u32 DETOUR_NODE_NUM_2P = 2;
22 : constexpr u32 DETOUR_NODE_NUM_4P = 4;
23 :
24 19 : DetourService& DetourService::GetInstance()
25 : {
26 19 : static DetourService detourService(PhyTopo::GetInstance().get());
27 19 : return detourService;
28 : }
29 :
30 2 : DetourService::DetourService(const PhyTopo* phyTopo) { this->phyTopo = phyTopo; }
31 :
32 : struct DetourData {
33 : NodeId detourPhyPeerId{0};
34 : NodeId srcPhyPeerId{0};
35 : NodeId dstPhyPeerId{0};
36 : shared_ptr<NetInstance::Peer> srcNetInstPeer{nullptr};
37 : shared_ptr<NetInstance::Peer> dstNetInstPeer{nullptr};
38 : };
39 :
40 : vector<shared_ptr<PhyTopo::Link>>
41 0 : GetLinks(NodeId srcId, NodeId dstId, const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>& phyTopoGraph)
42 : {
43 0 : vector<shared_ptr<PhyTopo::Link>> links;
44 0 : if (phyTopoGraph == nullptr) {
45 0 : THROW<NullPtrException>(StringFormat("[GetLinks] phyTopoGraphis nullptr"));
46 : }
47 0 : phyTopoGraph->TraverseEdge(srcId, dstId, [&](shared_ptr<PhyTopo::Link> link) {
48 0 : if (link != nullptr) {
49 0 : links.emplace_back(link);
50 0 : return;
51 : }
52 : });
53 :
54 0 : return links;
55 0 : }
56 :
57 0 : void AddDetourLink(
58 : NetInstance* innerNetInst, const DetourData& data,
59 : const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>& phyTopoGraph,
60 : [[maybe_unused]] const RankTableInfo* rankTable)
61 : {
62 0 : vector<shared_ptr<PhyTopo::Link>> src2detVec = GetLinks(data.srcPhyPeerId, data.detourPhyPeerId, phyTopoGraph);
63 0 : vector<shared_ptr<PhyTopo::Link>> det2dstVec = GetLinks(data.detourPhyPeerId, data.dstPhyPeerId, phyTopoGraph);
64 0 : if (src2detVec.size() == 0 || det2dstVec.size() == 0) {
65 0 : return;
66 : }
67 0 : if (innerNetInst == nullptr) {
68 0 : THROW<NullPtrException>(StringFormat("[AddDetourLink] innerGroup is nullptr"));
69 : }
70 0 : u32 hop = 2; // 目前绕路hop一定是2
71 0 : for (const auto& src2detLink : src2detVec) {
72 0 : for (const auto& det2dstLink : det2dstVec) {
73 0 : LinkType linkType = src2detLink->GetType();
74 0 : std::set<LinkProtocol> linkProtocols = src2detLink->GetLinkProtocols();
75 0 : if (linkType != det2dstLink->GetType()) {
76 0 : HCCL_WARNING(
77 : "[DetourService][InsertDetourLinks][AddDetourLink] src2det[%s] det2dst[%s] linkType no match",
78 : linkType.Describe().c_str(), det2dstLink->GetType().Describe().c_str());
79 0 : continue;
80 0 : };
81 : // todo 是不是应该改为判断两个set是否有交集,取绕路的协议集合? 修改了一下,llt再check一下
82 0 : std::set<LinkProtocol> newLinkProtocols;
83 0 : std::set_intersection(
84 0 : linkProtocols.begin(), linkProtocols.end(), det2dstLink->GetLinkProtocols().begin(),
85 0 : det2dstLink->GetLinkProtocols().end(), std::inserter(newLinkProtocols, newLinkProtocols.begin()));
86 :
87 0 : if (newLinkProtocols.empty()) {
88 : // todo 先改编译,后面再实现日志打印
89 0 : continue;
90 : };
91 :
92 : // 从Link中获取端口集合
93 0 : if (src2detLink->GetSourceIFace() == nullptr || det2dstLink->GetTargetIFace() == nullptr) {
94 0 : THROW<InvalidParamsException>(
95 : "[DetourService][InsertDetourLinks][AddDetourLink] source ConnInterface is nullptr");
96 : }
97 0 : std::set<string> src2detPorts = src2detLink->GetSourceIFace()->GetPorts();
98 0 : std::set<string> det2dstPorts = det2dstLink->GetTargetIFace()->GetPorts();
99 0 : if (src2detPorts.size() != 1 || det2dstPorts.size() != 1) {
100 0 : THROW<InvalidParamsException>(
101 : "[DetourService][InsertDetourLinks][AddDetourLink] Peer to Peer port num error");
102 : }
103 :
104 : // 取出对应的端口,然后去ranktableInfo中查对应端口的地址信息
105 : // todo 逻辑判断一下只取第一个端口是否正确?
106 0 : IpAddress src2detAddr = data.srcNetInstPeer->GetPortAddrMapLayer0()[*src2detPorts.begin()][0];
107 0 : IpAddress det2dstAddr = data.dstNetInstPeer->GetPortAddrMapLayer0()[*det2dstPorts.begin()][0];
108 :
109 : // 构造InterFace对象用于后续生成Link
110 : shared_ptr<NetInstance::ConnInterface> sourceIface = make_shared<NetInstance::ConnInterface>(
111 0 : src2detAddr, src2detPorts, src2detLink->GetSourceIFace()->GetPos(), LinkType::PEER2PEER,
112 0 : src2detLink->GetLinkProtocols(), src2detLink->GetTopoType(), src2detLink->GetTopoInstId());
113 : shared_ptr<NetInstance::ConnInterface> targetIface = make_shared<NetInstance::ConnInterface>(
114 0 : det2dstAddr, det2dstPorts, det2dstLink->GetSourceIFace()->GetPos(), LinkType::PEER2PEER,
115 0 : det2dstLink->GetLinkProtocols(), det2dstLink->GetTopoType(), det2dstLink->GetTopoInstId());
116 :
117 : // 构造Link加入NetInstance中
118 : shared_ptr<NetInstance::Link> sendEdge = make_shared<NetInstance::Link>(
119 0 : data.srcNetInstPeer, data.dstNetInstPeer, sourceIface, targetIface, linkType, newLinkProtocols,
120 0 : LinkDirection::SEND_ONLY, hop);
121 : shared_ptr<NetInstance::Link> recvEdge = make_shared<NetInstance::Link>(
122 0 : data.dstNetInstPeer, data.srcNetInstPeer, targetIface, sourceIface, linkType, newLinkProtocols,
123 0 : LinkDirection::RECV_ONLY, hop);
124 0 : innerNetInst->AddLink(sendEdge);
125 0 : innerNetInst->AddLink(recvEdge);
126 :
127 0 : data.srcNetInstPeer->AddConnInterface(0, sourceIface);
128 0 : if (data.dstNetInstPeer == nullptr) {
129 0 : THROW<NullPtrException>(
130 0 : StringFormat("[DetourService][InsertDetourLinks][AddDetourLink] dstVirtPeer is nullptr"));
131 : }
132 0 : data.dstNetInstPeer->AddConnInterface(0, targetIface);
133 :
134 0 : HCCL_DEBUG(
135 : "[DetourService][AddDetourLink] add SEND_ONLY and RECV_ONLY two links: linkType[%s]"
136 : " sourceIfaceAddress[%s] targetIfaceAddress[%s]",
137 : linkType.Describe().c_str(), sourceIface->GetAddr().Describe().c_str(),
138 : targetIface->GetAddr().Describe().c_str());
139 0 : }
140 : }
141 :
142 0 : HCCL_DEBUG(
143 : "[DetourService][AddDetourLink] srcRankId[%llu] dstRankId[%llu] srcLocalId[%llu] detourLocalId[%llu] "
144 : "dstLocalId[%llu] src2detVec.size[%u] det2dstVec.size[%u]",
145 : data.srcNetInstPeer->GetNodeId(), data.dstNetInstPeer->GetNodeId(), data.srcPhyPeerId, data.detourPhyPeerId,
146 : data.dstPhyPeerId, src2detVec.size(), det2dstVec.size());
147 0 : }
148 :
149 18 : std::vector<LocalId> GetInnerLocalIds(const RankGraph* rankGraph)
150 : {
151 18 : if (rankGraph == nullptr) {
152 0 : THROW<NullPtrException>(StringFormat("[GetInnerLocalIds] rankGraph is nullptr"));
153 : }
154 18 : const NetInstance* innerNetInst = rankGraph->GetNetInstanceByRankId(0, rankGraph->GetMyRank());
155 18 : if (innerNetInst == nullptr) {
156 0 : THROW<NullPtrException>(StringFormat("[GetInnerLocalIds] innerNetInst is nullptr"));
157 : }
158 18 : set<RankId> innerRanks = innerNetInst->GetRankIds();
159 18 : std::vector<LocalId> localIds;
160 68 : for (auto& rankId : innerRanks) {
161 50 : localIds.emplace_back(rankGraph->GetLocalId(rankId));
162 : }
163 18 : return localIds;
164 18 : }
165 :
166 0 : bool IsInSameRow(const std::vector<LocalId>& localIds)
167 : {
168 0 : int preRowId = -1;
169 0 : for (auto& localId : localIds) {
170 0 : int curRowId = localId / DETOUR_NODE_NUM;
171 0 : if (preRowId == -1) {
172 0 : preRowId = curRowId;
173 : } else {
174 0 : if (curRowId != preRowId) {
175 0 : return false;
176 : }
177 : }
178 : }
179 0 : return true;
180 : }
181 :
182 0 : bool IsInSameCol(const std::vector<LocalId>& localIds)
183 : {
184 0 : int preColId = -1;
185 0 : for (auto& localId : localIds) {
186 0 : int curColId = localId % DETOUR_NODE_NUM;
187 0 : if (preColId == -1) {
188 0 : preColId = curColId;
189 : } else {
190 0 : if (curColId != preColId) {
191 0 : return false;
192 : }
193 : }
194 : }
195 0 : return true;
196 : }
197 :
198 0 : bool GetTableIds(
199 : const std::vector<LocalId>& localIds, std::unordered_map<LocalId, u32>& tableIds, std::set<u32>& tableIdSet)
200 : {
201 0 : if (IsInSameRow(localIds)) {
202 0 : for (auto& localId : localIds) {
203 0 : u32 tableId = localId % DETOUR_NODE_NUM;
204 0 : tableIds[localId] = tableId;
205 0 : tableIdSet.emplace(tableId);
206 : }
207 0 : } else if (IsInSameCol(localIds)) {
208 0 : for (auto& localId : localIds) {
209 0 : u32 tableId = localId / DETOUR_NODE_NUM;
210 0 : tableIds[localId] = tableId;
211 0 : tableIdSet.emplace(tableId);
212 : }
213 : } else {
214 0 : HCCL_WARNING("[DetourService][GetTableIds] The ranks localIds are not in the same row or column.");
215 0 : return false;
216 : }
217 0 : return true;
218 : }
219 :
220 4 : void SetDetourTable4P(
221 : const std::set<u32>& tableIdSet, unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable)
222 : {
223 12 : if (tableIdSet == std::set<u32>{0, 1, 2, 3}) { // tableId必须为 0 1 2 3,才能使用DETOUR4PTABLE_0123绕路
224 1 : detourTable = GetDetour4PTable0123();
225 1 : HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_0123");
226 9 : } else if (tableIdSet == std::set<u32>{4, 5, 6, 7}) { // tableId必须为 4 5 6 7,才能使用DETOUR4PTABLE_4567绕路
227 1 : detourTable = GetDetour4PTable4567();
228 1 : HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_4567");
229 6 : } else if (tableIdSet == std::set<u32>{0, 2, 4, 6}) { // tableId必须为 0 2 4 6,才能使用DETOUR4PTABLE_0246绕路
230 1 : detourTable = GetDetour4PTable0246();
231 1 : HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_0246");
232 3 : } else if (tableIdSet == std::set<u32>{1, 3, 5, 7}) { // tableId必须为 1 3 5 7,才能使用DETOUR4PTABLE_1357绕路
233 1 : detourTable = GetDetour4PTable1357();
234 1 : HCCL_DEBUG("[DetourService] selected detour table is DETOUR4PTABLE_1357");
235 : } else {
236 0 : HCCL_WARNING("no matched detourTable found");
237 : }
238 4 : }
239 :
240 2 : void SetDetourTable2P(
241 : const std::set<u32>& tableIdSet, unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable)
242 : {
243 11 : if (tableIdSet == std::set<u32>{0, 1} || tableIdSet == std::set<u32>{2, 3} || tableIdSet == std::set<u32>{4, 5}
244 7 : || tableIdSet == std::set<u32>{6, 7}) {
245 1 : detourTable = GetDetour2PTable01();
246 1 : } else if (
247 3 : tableIdSet == std::set<u32>{0, 4} || tableIdSet == std::set<u32>{1, 5} || tableIdSet == std::set<u32>{2, 6}
248 2 : || tableIdSet == std::set<u32>{3, 7}) {
249 1 : detourTable = GetDetour2PTable04();
250 : } else {
251 0 : HCCL_WARNING("[DetourService][%s]no matched detourTable found", __func__);
252 : }
253 2 : }
254 :
255 18 : void GetDetourTableAndTableIds(
256 : const std::vector<LocalId>& localIds,
257 : std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable,
258 : std::unordered_map<LocalId, u32>& tableIds, const RankTableInfo* rankTable)
259 : {
260 18 : std::set<u32> tableIdSet;
261 18 : HcclDetourType detourType = EnvConfig::GetInstance().GetDetourConfig().GetDetourType();
262 18 : if (rankTable->detour == false) {
263 4 : detourType = HcclDetourType::HCCL_DETOUR_DISABLE;
264 : }
265 18 : switch (detourType) {
266 0 : case HcclDetourType::HCCL_DETOUR_ENABLE_2P: {
267 0 : if (localIds.size() != DETOUR_NODE_NUM_2P) {
268 0 : return;
269 : }
270 0 : bool res = GetTableIds(localIds, tableIds, tableIdSet);
271 0 : if (res) {
272 0 : SetDetourTable2P(tableIdSet, detourTable);
273 0 : HCCL_DEBUG("[DetourService] selected detour type is DETOUR2PTABLE");
274 : } else {
275 0 : HCCL_WARNING("[DetourService] detourtype [%s] does not support.", detourType.Describe().c_str());
276 : }
277 0 : break;
278 : }
279 0 : case HcclDetourType::HCCL_DETOUR_ENABLE_4P: {
280 0 : if (localIds.size() != DETOUR_NODE_NUM_4P) {
281 0 : return;
282 : }
283 0 : bool res = GetTableIds(localIds, tableIds, tableIdSet);
284 0 : if (res) {
285 0 : SetDetourTable4P(tableIdSet, detourTable);
286 : } else {
287 0 : HCCL_WARNING("[DetourService] detourtype [%s] does not support.", detourType.Describe().c_str());
288 : }
289 0 : break;
290 : }
291 18 : case HcclDetourType::HCCL_DETOUR_DISABLE: {
292 46 : HCCL_DEBUG("[DetourService] detour is disable");
293 18 : break;
294 : }
295 0 : default: {
296 0 : THROW<NotSupportException>(
297 0 : StringFormat("[DetourService] detourtype [%s] does not support.", detourType.Describe().c_str()));
298 : }
299 : }
300 18 : }
301 :
302 0 : void AddDetourLinks(
303 : const PhyTopo* phyTopo, RankGraph* rankGraph,
304 : std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable,
305 : std::unordered_map<LocalId, u32>& tableIds, const RankTableInfo* rankTable)
306 : {
307 0 : auto phyTopoGraph = phyTopo->GetTopoGraph(0);
308 0 : NetInstance* innerNetInst = rankGraph->GetNetInstanceByRankId(0, rankGraph->GetMyRank());
309 0 : if (innerNetInst == nullptr) {
310 0 : THROW<NullPtrException>(StringFormat("[DetourService] innerNetInst is nullptr"));
311 : }
312 0 : set<RankId> innerRanks = innerNetInst->GetRankIds();
313 0 : for (const auto& srcRankId : innerRanks) {
314 0 : LocalId srcLocalId = rankGraph->GetLocalId(srcRankId);
315 0 : u32 srcTableId = tableIds[srcLocalId];
316 0 : for (const auto& dstRankId : innerRanks) {
317 0 : LocalId dstLocalId = rankGraph->GetLocalId(dstRankId);
318 0 : u32 dstTableId = tableIds[dstLocalId];
319 :
320 0 : if (detourTable.count(srcTableId) == 0 || detourTable[srcTableId].count(dstTableId) == 0) {
321 0 : continue;
322 : }
323 :
324 0 : auto detourTableIds = detourTable[srcTableId][dstTableId];
325 0 : for (auto& detourTableId : detourTableIds) {
326 0 : LocalId detourLocalId = detourTableId + srcLocalId - srcTableId;
327 :
328 : // 插入detourlink
329 0 : DetourData detourData;
330 0 : detourData.detourPhyPeerId = PhyTopo::Peer::GetId(detourLocalId); // 绕路可能没有绕路节点的rankid
331 0 : detourData.srcPhyPeerId = PhyTopo::Peer::GetId(srcLocalId);
332 0 : detourData.dstPhyPeerId = PhyTopo::Peer::GetId(dstLocalId);
333 0 : detourData.srcNetInstPeer = rankGraph->GetPeer(srcRankId);
334 0 : detourData.dstNetInstPeer = rankGraph->GetPeer(dstRankId);
335 :
336 0 : AddDetourLink(innerNetInst, detourData, phyTopoGraph, rankTable);
337 0 : }
338 0 : }
339 : }
340 0 : }
341 :
342 18 : void DetourService::InsertDetourLinks(RankGraph* rankGraph, const RankTableInfo* rankTable)
343 : {
344 18 : std::unordered_map<LocalId, u32> tableIds;
345 18 : std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>> detourTable;
346 :
347 : // 获取innerGroup的localIds
348 18 : std::vector<LocalId> localIds = GetInnerLocalIds(rankGraph);
349 : // 获取当前localIds的tableId和detourTable
350 18 : GetDetourTableAndTableIds(localIds, detourTable, tableIds, rankTable);
351 :
352 18 : if (!detourTable.empty()) {
353 : // 添加绕路links
354 0 : AddDetourLinks(phyTopo, rankGraph, detourTable, tableIds, rankTable);
355 : } else {
356 46 : HCCL_WARNING("no detour links found");
357 : }
358 18 : }
359 :
360 : } // namespace Hccl
|