已合并
[feat] topo.json忽略net_layer字段 #4452
x00958740创建于 8月6日
[feat] topo.json忽略net_layer字段 #4452
已合并
x00958740创建于 8月6日
共 46 个文件变更+1732-630
@@ -25,54 +25,42 @@ bool PhyTopo::IsInitFinished() const { return initFlag; }
25 25 
26void PhyTopo::Clear()26void PhyTopo::Clear()
27{27{
28- topos.clear();28+ topo_.reset();
29 initFlag = false;29 initFlag = false;
30}30}
31 31 
32-void PhyTopo::AddTopoGraph(const u32 netLayer, std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo)32+void PhyTopo::AddTopoGraph(std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo)
33{33{
34 if (!initFlag) {34 if (!initFlag) {
35- topos[netLayer] = topo;35+ // 物理拓扑只保存一张无逻辑层级的图。
36- HCCL_DEBUG("[PhyTopo]add topo success, netLayer [%u], topo size is [%zu]", netLayer, topos.size());36+ topo_ = topo;
37+ HCCL_DEBUG("[PhyTopo] add physical topo graph success.");
37 } else {38 } else {
38 THROW<InternalException>("PhyTopo AddTopoGraph fail. PhyTopo has been initialized "39 THROW<InternalException>("PhyTopo AddTopoGraph fail. PhyTopo has been initialized "
39 "and cannot be changed, please check.");40 "and cannot be changed, please check.");
40 }41 }
41}42}
42 43 
43-std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> PhyTopo::GetTopoGraph(const u32 netLayer) const44+std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> PhyTopo::GetTopoGraph() const { return topo_; }
44-{
45- if (topos.find(netLayer) == topos.end()) {
46- return nullptr;
47- }
48- return topos.at(netLayer);
49-}
50- 
51-bool PhyTopo::IsNetLayerExisted(const u32 netLayer) const
52-{
53- if (topos.find(netLayer) == topos.end()) {
54- return false;
55- }
56- return true;
57-}
58 45 
59void PhyTopo::Dump() const46void PhyTopo::Dump() const
60{47{
61 HCCL_DEBUG("PhyTopo Dump:");48 HCCL_DEBUG("PhyTopo Dump:");
62- for (auto& pair : topos) {49+ if (topo_ == nullptr) {
63- HCCL_DEBUG("netLayer[%u]:", pair.first);50+ HCCL_DEBUG("physical topo graph is nullptr.");
64- HCCL_DEBUG("nodes:");51+ return;
65- std::set<NodeId> nodeIds{};52+ }
66- pair.second->TraverseNode([&](NodeId nodeId, std::shared_ptr<PhyTopo::Node> node) {53+ HCCL_DEBUG("nodes:");
67- nodeIds.insert(nodeId);54+ std::set<NodeId> nodeIds{};
68- HCCL_DEBUG("%s", node->Describe().c_str());55+ topo_->TraverseNode([&](NodeId nodeId, std::shared_ptr<PhyTopo::Node> node) {
56+ nodeIds.insert(nodeId);
57+ HCCL_DEBUG("%s", node->Describe().c_str());
58+ });
59+ HCCL_DEBUG("links:");
60+ for (NodeId nodeId : nodeIds) {
61+ topo_->TraverseEdge(nodeId, [&](std::shared_ptr<Link> link) {
62+ HCCL_DEBUG("%s", link->Describe().c_str());
69 });63 });
70- HCCL_DEBUG("links:");
71- for (NodeId nodeId : nodeIds) {
72- pair.second->TraverseEdge(nodeId, [&](std::shared_ptr<Link> link) {
73- HCCL_DEBUG("%s", link->Describe().c_str());
74- });
75- }
76 }64 }
77}65}
78 66 
@@ -13,7 +13,6 @@
13 13 
14#include <vector>14#include <vector>
15#include <set>15#include <set>
16-#include <unordered_map>
17#include <memory>16#include <memory>
18#include "topo_common_types.h"17#include "topo_common_types.h"
19#include "iterator.h"18#include "iterator.h"
@@ -116,16 +115,15 @@ public:
116 u32 hop{1};115 u32 hop{1};
117 };116 };
118 117 
119- void AddTopoGraph(const u32 netLayer, std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo);118+ void AddTopoGraph(std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo);
120- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> GetTopoGraph(const u32 netLayer) const;119+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> GetTopoGraph() const;
121 void InitFinish();120 void InitFinish();
122 bool IsInitFinished() const;121 bool IsInitFinished() const;
123 void Clear();122 void Clear();
124 void Dump() const;123 void Dump() const;
125- bool IsNetLayerExisted(const u32 netLayer) const;
126 124 
127private:125private:
128- std::unordered_map<u32, std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>> topos;126+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo_{nullptr};
129 bool initFlag{false};127 bool initFlag{false};
130};128};
131} // namespace Hccl129} // namespace Hccl
@@ -56,28 +56,7 @@ void PhyTopoBuilder::Build(const std::string& topoPath)
56 HCCL_DEBUG("[PhyTopoBuilder::%s]Start to build physic topo.", __func__);56 HCCL_DEBUG("[PhyTopoBuilder::%s]Start to build physic topo.", __func__);
57 57 
58 auto topoInfo = LoadTopoInfo(topoPath);58 auto topoInfo = LoadTopoInfo(topoPath);
59- // 根据topoInfo,按netLayer构造Graph59+ BuildPhyTopo(*topoInfo);
60- for (const auto& iter : topoInfo->edges) {
61- auto netLayer = iter.first;
62- auto graph = CreateGraph(iter.second);
63- PhyTopo::GetInstance()->AddTopoGraph(netLayer, graph);
64- HCCL_DEBUG("[PhyTopoBuilder::%s]Build netLayer[%u] topo graph success.", __func__, netLayer);
65- }
66- 
67- // 遍历peerList,把peerList中的localId构造peer节点,加到layer-0的graph中
68- auto graph = PhyTopo::GetInstance()->GetTopoGraph(0);
69- if (graph == nullptr) {
70- HCCL_INFO("[PhyTopoBuilder::%s] layer0 graph is nullptr, build now", __func__);
71- graph = make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
72- PhyTopo::GetInstance()->AddTopoGraph(0, graph);
73- }
74- for (const auto& iter : topoInfo->peers) {
75- // 判断当前layer0的graph有没有这个节点
76- if (!graph->HasNode(iter.localId)) {
77- auto node = CreateNode(PhyTopo::Node::NodeType::PEER, iter.localId);
78- graph->AddNode(iter.localId, node);
79- }
80- }
81 60 
82 PhyTopo::GetInstance()->InitFinish();61 PhyTopo::GetInstance()->InitFinish();
83 62 
@@ -180,6 +159,7 @@ NodeId GetNodeId(const PhyTopo::Node::NodeType nodeType, LocalId localId)
180std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>159std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>
181PhyTopoBuilder::CreateGraph(const std::vector<EdgeInfo>& edges) const160PhyTopoBuilder::CreateGraph(const std::vector<EdgeInfo>& edges) const
182{161{
162+ // 所有物理边构建到同一张图,逻辑分层由 RankTable 端口确定。
183 auto graph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();163 auto graph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
184 164 
185 for (const auto& edgeInfo : edges) {165 for (const auto& edgeInfo : edges) {
@@ -263,6 +243,22 @@ PhyTopoBuilder::CreateGraph(const std::vector<EdgeInfo>& edges) const
263 return graph;243 return graph;
264}244}
265 245 
246+void PhyTopoBuilder::BuildPhyTopo(const TopoInfo& topoInfo) const
247+{
248+ // topo.json 只描述物理连接,不再划分逻辑层。
249+ auto graph = CreateGraph(topoInfo.edges);
250+ // 补齐未出现在 edge_list 中的 Peer 节点。
251+ for (const auto& peerInfo : topoInfo.peers) {
252+ NodeId nodeId = PhyTopo::Peer::GetId(peerInfo.localId);
253+ if (!graph->HasNode(nodeId)) {
254+ auto node = CreateNode(PhyTopo::Node::NodeType::PEER, peerInfo.localId);
255+ graph->AddNode(nodeId, node);
256+ }
257+ }
258+ PhyTopo::GetInstance()->AddTopoGraph(graph);
259+ HCCL_DEBUG("[PhyTopoBuilder::%s] Build physical topo graph success.", __func__);
260+}
261+ 
266void PhyTopoBuilder::RecoverBuild(const TopoInfo& topoInfo)262void PhyTopoBuilder::RecoverBuild(const TopoInfo& topoInfo)
267{263{
268 std::lock_guard<std::mutex> lock(phyTopoMutex);264 std::lock_guard<std::mutex> lock(phyTopoMutex);
@@ -271,13 +267,8 @@ void PhyTopoBuilder::RecoverBuild(const TopoInfo& topoInfo)
271 if (PhyTopo::GetInstance()->IsInitFinished()) {267 if (PhyTopo::GetInstance()->IsInitFinished()) {
272 return;268 return;
273 }269 }
274- // 根据topoInfo,按netLayer构造Graph270+ topoInfo_ = std::make_shared<TopoInfo>(topoInfo);
275- for (const auto& iter : topoInfo.edges) {271+ BuildPhyTopo(topoInfo);
276- auto netLayer = iter.first;
277- auto graph = CreateGraph(iter.second);
278- PhyTopo::GetInstance()->AddTopoGraph(netLayer, graph);
279- HCCL_DEBUG("[PhyTopoBuilder::%s]Build netLayer[%u] topo graph success.", __func__, netLayer);
280- }
281 272 
282 PhyTopo::GetInstance()->InitFinish();273 PhyTopo::GetInstance()->InitFinish();
283 274 
@@ -44,6 +44,7 @@ public:
44private:44private:
45 std::shared_ptr<TopoInfo> LoadTopoInfo(const std::string& topoPath);45 std::shared_ptr<TopoInfo> LoadTopoInfo(const std::string& topoPath);
46 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> CreateGraph(const std::vector<EdgeInfo>& edges) const;46 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> CreateGraph(const std::vector<EdgeInfo>& edges) const;
47+ void BuildPhyTopo(const TopoInfo& topoInfo) const;
47 std::shared_ptr<TopoInfo> topoInfo_;48 std::shared_ptr<TopoInfo> topoInfo_;
48 std::mutex phyTopoMutex;49 std::mutex phyTopoMutex;
49};50};
@@ -377,13 +377,13 @@ std::vector<std::shared_ptr<NetInstance::ConnInterface>> NetInstance::Node::GetI
377}377}
378 378 
379void NetInstance::Node::SetEndpointToIface(379void NetInstance::Node::SetEndpointToIface(
380- const CommAddr& commAddr, CommProtocol protocol, const std::shared_ptr<NetInstance::ConnInterface>& iface)380+ u32 netLayer, u32 topoInstId, const CommAddr& commAddr, CommProtocol protocol,
381+ const std::shared_ptr<NetInstance::ConnInterface>& iface)
381{382{
382- endpointToIfaceMap_[std::make_pair(commAddr, protocol)] = iface;383+ endpointToIfaceMap_[EndpointKey{netLayer, topoInstId, commAddr, protocol}] = iface;
383}384}
384 385 
385-const std::unordered_map<std::pair<CommAddr, CommProtocol>, std::shared_ptr<NetInstance::ConnInterface>>386+const NetInstance::Node::EndpointToIfaceMap& NetInstance::Node::GetEndpointToIfaceMap() const
386-NetInstance::Node::GetEndpointToIfaceMap() const
387{387{
388 return endpointToIfaceMap_;388 return endpointToIfaceMap_;
389}389}
@@ -450,6 +450,17 @@ std::map<std::string, std::vector<IpAddress>> NetInstance::Peer::GetPortAddrMapL
450 return portAddrMapLayer0_;450 return portAddrMapLayer0_;
451}451}
452 452 
453+bool NetInstance::Peer::TryGetLayer0Address(const std::string& port, IpAddress& addr) const
454+{
455+ // 端口归属以 RankTable layer 0 的地址映射为准。
456+ auto addrIt = portAddrMapLayer0_.find(port);
457+ if (addrIt == portAddrMapLayer0_.end() || addrIt->second.empty()) {
458+ return false;
459+ }
460+ addr = addrIt->second.front();
461+ return true;
462+}
463+ 
453PlaneId NetInstance::Fabric::GetPlaneId() const { return planeId_; }464PlaneId NetInstance::Fabric::GetPlaneId() const { return planeId_; }
454 465 
455NodeId NetInstance::Fabric::GenerateNodeId(FabricId fabricId) const466NodeId NetInstance::Fabric::GenerateNodeId(FabricId fabricId) const
@@ -23,10 +23,72 @@
23#include "ip_address.h"23#include "ip_address.h"
24#include "iterator.h"24#include "iterator.h"
25#include "types.h"25#include "types.h"
26+#include "securec.h"
26#include "topo_common_types.h"27#include "topo_common_types.h"
27 28 
28namespace Hccl {29namespace Hccl {
29constexpr u32 DEFAULT_LISTENING_PORT = 60001;30constexpr u32 DEFAULT_LISTENING_PORT = 60001;
31+// HCCL构建ChannelDesc时会完整复制EndpointLoc,使用其未占用的尾部字节传递拓扑定位信息。
32+struct EndpointTopoInfo {
33+ u32 magic;
34+ u32 netLayer;
35+ u32 topoInstId;
36+};
37+ 
38+constexpr u32 ENDPOINT_TOPO_INFO_MAGIC = 0x544F504FU;
39+constexpr size_t ENDPOINT_LOC_RAW_SIZE = sizeof(((EndpointLoc*)nullptr)->raws);
40+static_assert(ENDPOINT_LOC_RAW_SIZE >= sizeof(EndpointTopoInfo), "EndpointLoc reserved space is insufficient");
41+static_assert(
42+ ENDPOINT_LOC_RAW_SIZE - sizeof(EndpointTopoInfo) >= sizeof(((EndpointLoc*)nullptr)->device),
43+ "Endpoint topology info overlaps device location fields");
44+constexpr size_t ENDPOINT_TOPO_INFO_OFFSET = ENDPOINT_LOC_RAW_SIZE - sizeof(EndpointTopoInfo);
45+ 
46+inline HcclResult SetEndpointTopoInfo(EndpointDesc& endpointDesc, u32 netLayer, u32 topoInstId)
47+{
48+ const EndpointTopoInfo topoInfo{ENDPOINT_TOPO_INFO_MAGIC, netLayer, topoInstId};
49+ const errno_t ret
50+ = memcpy_s(endpointDesc.loc.raws + ENDPOINT_TOPO_INFO_OFFSET, sizeof(topoInfo), &topoInfo, sizeof(topoInfo));
51+ return ret == EOK ? HCCL_SUCCESS : HCCL_E_MEMORY;
52+}
53+ 
54+inline bool GetEndpointTopoInfo(const EndpointDesc& endpointDesc, u32& netLayer, u32& topoInstId)
55+{
56+ EndpointTopoInfo topoInfo{};
57+ const errno_t ret
58+ = memcpy_s(&topoInfo, sizeof(topoInfo), endpointDesc.loc.raws + ENDPOINT_TOPO_INFO_OFFSET, sizeof(topoInfo));
59+ if (ret != EOK) {
60+ return false;
61+ }
62+ if (topoInfo.magic != ENDPOINT_TOPO_INFO_MAGIC) {
63+ return false;
64+ }
65+ 
66+ netLayer = topoInfo.netLayer;
67+ topoInstId = topoInfo.topoInstId;
68+ return true;
69+}
70+ 
71+// 同一地址和协议可属于不同网络层或拓扑实例,需共同参与Endpoint定位。
72+struct EndpointKey {
73+ u32 netLayer;
74+ u32 topoInstId;
75+ CommAddr commAddr;
76+ CommProtocol protocol;
77+ 
78+ bool operator==(const EndpointKey& other) const
79+ {
80+ return netLayer == other.netLayer && topoInstId == other.topoInstId && commAddr == other.commAddr
81+ && protocol == other.protocol;
82+ }
83+};
84+ 
85+struct EndpointKeyHash {
86+ size_t operator()(const EndpointKey& key) const
87+ {
88+ return std::hash<u32>()(key.netLayer) ^ (std::hash<u32>()(key.topoInstId) << 1)
89+ ^ (std::hash<CommAddr>()(key.commAddr) << 2) ^ (std::hash<CommProtocol>()(key.protocol) << 3);
90+ }
91+};
30class NetInstance {92class NetInstance {
31public:93public:
32 class ConnInterface {94 class ConnInterface {
@@ -70,6 +132,9 @@ public:
70 132 
71 class Node {133 class Node {
72 public:134 public:
135+ using EndpointToIfaceMap
136+ = std::unordered_map<EndpointKey, std::shared_ptr<NetInstance::ConnInterface>, EndpointKeyHash>;
137+ 
73 MAKE_ENUM(NodeType, PEER, FABRIC)138 MAKE_ENUM(NodeType, PEER, FABRIC)
74 explicit Node(NodeType nodeType) : type_(nodeType) {}139 explicit Node(NodeType nodeType) : type_(nodeType) {}
75 virtual ~Node() = default;140 virtual ~Node() = default;
@@ -80,9 +145,9 @@ public:
80 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfacesByLayer(u32 layer) const;145 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfacesByLayer(u32 layer) const;
81 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfaces() const;146 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfaces() const;
82 void SetEndpointToIface(147 void SetEndpointToIface(
83- const CommAddr& commAddr, CommProtocol protocol, const std::shared_ptr<NetInstance::ConnInterface>& iface);148+ u32 netLayer, u32 topoInstId, const CommAddr& commAddr, CommProtocol protocol,
84- const std::unordered_map<std::pair<CommAddr, CommProtocol>, std::shared_ptr<NetInstance::ConnInterface>>149+ const std::shared_ptr<NetInstance::ConnInterface>& iface);
85- GetEndpointToIfaceMap() const;150+ const EndpointToIfaceMap& GetEndpointToIfaceMap() const;
86 NodeId GetNodeId() const;151 NodeId GetNodeId() const;
87 string GetNodeIdStr() const;152 string GetNodeIdStr() const;
88 const std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>>153 const std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>>
@@ -94,8 +159,7 @@ public:
94 159 
95 private:160 private:
96 std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>> interfacesMap_;161 std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>> interfacesMap_;
97- std::unordered_map<std::pair<CommAddr, CommProtocol>, std::shared_ptr<NetInstance::ConnInterface>>162+ EndpointToIfaceMap endpointToIfaceMap_;
98- endpointToIfaceMap_;
99 NodeType type_;163 NodeType type_;
100 };164 };
101 165 
@@ -126,6 +190,7 @@ public:
126 std::set<u32> GetLevels() const;190 std::set<u32> GetLevels() const;
127 NetInstancePtr GetNetInstance(u32 level) const;191 NetInstancePtr GetNetInstance(u32 level) const;
128 std::map<std::string, std::vector<IpAddress>> GetPortAddrMapLayer0() const;192 std::map<std::string, std::vector<IpAddress>> GetPortAddrMapLayer0() const;
193+ bool TryGetLayer0Address(const std::string& port, IpAddress& addr) const;
129 void SetPortPortAddrMapLayer0(std::map<std::string, std::vector<IpAddress>> portAddrMap);194 void SetPortPortAddrMapLayer0(std::map<std::string, std::vector<IpAddress>> portAddrMap);
130 std::string Describe() const override;195 std::string Describe() const override;
131 196 
@@ -414,10 +414,10 @@ RankGraph::GetEndpointDesc(uint32_t layer, uint32_t topoInstId, uint32_t* descNu
414 // 一个 iface 可能对应多个 protocol(即多个 EndpointDesc)414 // 一个 iface 可能对应多个 protocol(即多个 EndpointDesc)
415 const auto& endpointMap = peer->GetEndpointToIfaceMap();415 const auto& endpointMap = peer->GetEndpointToIfaceMap();
416 for (const auto& entry : endpointMap) {416 for (const auto& entry : endpointMap) {
417- std::pair<CommAddr, CommProtocol> endpoint = entry.first;417+ const EndpointKey& endpoint = entry.first;
418 const std::shared_ptr<NetInstance::ConnInterface>& mappedIface = entry.second;418 const std::shared_ptr<NetInstance::ConnInterface>& mappedIface = entry.second;
419 419 
420- if (mappedIface != iface) {420+ if (mappedIface != iface || endpoint.netLayer != layer || endpoint.topoInstId != topoInstId) {
421 continue;421 continue;
422 }422 }
423 423 
@@ -430,9 +430,11 @@ RankGraph::GetEndpointDesc(uint32_t layer, uint32_t topoInstId, uint32_t* descNu
430 return HCCL_E_PARA;430 return HCCL_E_PARA;
431 }431 }
432 432 
433- endpointDesc[count].commAddr = endpoint.first;433+ CHK_RET(static_cast<HcclResult>(EndpointDescInit(&endpointDesc[count], 1)));
434- endpointDesc[count].protocol = endpoint.second;434+ endpointDesc[count].commAddr = endpoint.commAddr;
435+ endpointDesc[count].protocol = endpoint.protocol;
435 endpointDesc[count].loc.locType = AddrPositionToEndpointLoc(iface->GetPos());436 endpointDesc[count].loc.locType = AddrPositionToEndpointLoc(iface->GetPos());
437+ CHK_RET(SetEndpointTopoInfo(endpointDesc[count], layer, topoInstId));
436 438 
437 HCCL_INFO(439 HCCL_INFO(
438 "[RankGraph::GetEndpointDesc] local type is %d, protocol %d", endpointDesc[count].loc.locType,440 "[RankGraph::GetEndpointDesc] local type is %d, protocol %d", endpointDesc[count].loc.locType,
@@ -459,14 +461,32 @@ HcclResult RankGraph::GetEndpointInfo(
459 }461 }
460 462 
461 // 查找接口463 // 查找接口
462- auto key = std::make_pair(endpointDesc->commAddr, endpointDesc->protocol);
463 const auto& endpointToIfaceMap = peer->GetEndpointToIfaceMap();464 const auto& endpointToIfaceMap = peer->GetEndpointToIfaceMap();
464- auto it = endpointToIfaceMap.find(key);465+ u32 endpointNetLayer = UINT32_MAX;
465- if (it == endpointToIfaceMap.end()) {466+ u32 endpointTopoInstId = UINT32_MAX;
467+ const bool hasTopoInfo = GetEndpointTopoInfo(*endpointDesc, endpointNetLayer, endpointTopoInstId);
468+ // 旧描述符未携带拓扑定位信息时仅允许唯一匹配,避免跨层静默选错接口。
469+ std::shared_ptr<NetInstance::ConnInterface> iface;
470+ for (const auto& entry : endpointToIfaceMap) {
471+ const EndpointKey& key = entry.first;
472+ if (!(key.commAddr == endpointDesc->commAddr) || key.protocol != endpointDesc->protocol) {
473+ continue;
474+ }
475+ if (hasTopoInfo && (key.netLayer != endpointNetLayer || key.topoInstId != endpointTopoInstId)) {
476+ continue;
477+ }
478+ if (iface != nullptr && iface != entry.second) {
479+ HCCL_ERROR(
480+ "[GetEndpointInfo] Ambiguous endpoint, netLayer[%u], topoInstId[%u], protocol[%d]", endpointNetLayer,
481+ endpointTopoInstId, endpointDesc->protocol);
482+ return HCCL_E_PARA;
483+ }
484+ iface = entry.second;
485+ }
486+ if (iface == nullptr) {
466 HCCL_ERROR("[GetEndpointInfo] No matching interface found");487 HCCL_ERROR("[GetEndpointInfo] No matching interface found");
467 return HCCL_E_NOT_FOUND;488 return HCCL_E_NOT_FOUND;
468 }489 }
469- const auto& iface = it->second;
470 // 填充信息490 // 填充信息
471 switch (endpointAttr) {491 switch (endpointAttr) {
472 case ENDPOINT_ATTR_BW_COEFF: {492 case ENDPOINT_ATTR_BW_COEFF: {
@@ -712,9 +732,10 @@ void RankGraph::AddSubPeers(const std::vector<RankId>& rankIds, RankGraph* subRa
712 peers.emplace(subRankId, subPeer);732 peers.emplace(subRankId, subPeer);
713 const auto& oldEndpointMap = oldPeer->GetEndpointToIfaceMap();733 const auto& oldEndpointMap = oldPeer->GetEndpointToIfaceMap();
714 for (const auto& entry : oldEndpointMap) {734 for (const auto& entry : oldEndpointMap) {
715- subPeer->SetEndpointToIface(entry.first.first, entry.first.second, entry.second);735+ subPeer->SetEndpointToIface(
736+ entry.first.netLayer, entry.first.topoInstId, entry.first.commAddr, entry.first.protocol, entry.second);
716 HCCL_DEBUG(737 HCCL_DEBUG(
717- "[SubRankGraph][AddSubPeers] endpointToIfaceMap: protocol[%d] for subRankId[%d]", entry.first.second,738+ "[SubRankGraph][AddSubPeers] endpointToIfaceMap: protocol[%d] for subRankId[%d]", entry.first.protocol,
718 subRankId);739 subRankId);
719 }740 }
720 HCCL_DEBUG(741 HCCL_DEBUG(
@@ -44,8 +44,9 @@ GetLinks(NodeId srcId, NodeId dstId, const shared_ptr<Graph<PhyTopo::Node, PhyTo
44 if (phyTopoGraph == nullptr) {44 if (phyTopoGraph == nullptr) {
45 THROW<NullPtrException>(StringFormat("[GetLinks] phyTopoGraphis nullptr"));45 THROW<NullPtrException>(StringFormat("[GetLinks] phyTopoGraphis nullptr"));
46 }46 }
47+ // 统一物理图中仅 P2P 边可作为绕路候选。
47 phyTopoGraph->TraverseEdge(srcId, dstId, [&](shared_ptr<PhyTopo::Link> link) {48 phyTopoGraph->TraverseEdge(srcId, dstId, [&](shared_ptr<PhyTopo::Link> link) {
48- if (link != nullptr) {49+ if (link != nullptr && link->GetType() == LinkType::PEER2PEER) {
49 links.emplace_back(link);50 links.emplace_back(link);
50 return;51 return;
51 }52 }
@@ -67,6 +68,10 @@ void AddDetourLink(
67 if (innerNetInst == nullptr) {68 if (innerNetInst == nullptr) {
68 THROW<NullPtrException>(StringFormat("[AddDetourLink] innerGroup is nullptr"));69 THROW<NullPtrException>(StringFormat("[AddDetourLink] innerGroup is nullptr"));
69 }70 }
71+ if (data.srcNetInstPeer == nullptr || data.dstNetInstPeer == nullptr) {
72+ THROW<NullPtrException>(
73+ StringFormat("[DetourService][InsertDetourLinks][AddDetourLink] virtual peer is nullptr"));
74+ }
70 u32 hop = 2; // 目前绕路hop一定是275 u32 hop = 2; // 目前绕路hop一定是2
71 for (const auto& src2detLink : src2detVec) {76 for (const auto& src2detLink : src2detVec) {
72 for (const auto& det2dstLink : det2dstVec) {77 for (const auto& det2dstLink : det2dstVec) {
@@ -97,14 +102,21 @@ void AddDetourLink(
97 std::set<string> src2detPorts = src2detLink->GetSourceIFace()->GetPorts();102 std::set<string> src2detPorts = src2detLink->GetSourceIFace()->GetPorts();
98 std::set<string> det2dstPorts = det2dstLink->GetTargetIFace()->GetPorts();103 std::set<string> det2dstPorts = det2dstLink->GetTargetIFace()->GetPorts();
99 if (src2detPorts.size() != 1 || det2dstPorts.size() != 1) {104 if (src2detPorts.size() != 1 || det2dstPorts.size() != 1) {
100- THROW<InvalidParamsException>(105+ HCCL_WARNING(
101- "[DetourService][InsertDetourLinks][AddDetourLink] Peer to Peer port num error");106+ "[DetourService][InsertDetourLinks][AddDetourLink] Ignore unmatched P2P candidate, "
107+ "srcPortNum[%zu] dstPortNum[%zu]",
108+ src2detPorts.size(), det2dstPorts.size());
109+ continue;
102 }110 }
atomgit-bot
atomgit-botatomgit-bot8月6日

🟡 Medium Priority

changed line:detour_service.cc 第 105-110 行,旧代码 THROW<InvalidParamsException> 在 P2P 端口数 != 1 时立即失败;新代码改为 HCCL_WARNING + continue 静默跳过该候选。

affected behavior/contract:原先 P2P 绕路候选端口数不为 1 被视为严重配置错误并终止流程;现在该候选被静默丢弃,流程继续。

failure mode:当 topo.json / RankTable 配置出现异常导致某条 P2P 边端口数不为 1 时,原先会立即暴露(进程报错退出),现会被静默跳过。如果所有候选均被跳过,绕路链路将完全不生效,而进程不会报任何错误,导致在需要绕路的故障场景下集合通信失败或性能严重降级,排查极为困难。

suggested fix:将 HCCL_WARNING 保留但额外增加计数器,在循环结束后若所有候选均被跳过(即实际添加的绕路 link 为 0),应输出 HCCL_ERROR 或抛出异常,确保异常情况不被完全淹没。

建议:添加计数器跟踪被跳过的候选数量;循环结束后若有效绕路 link 数为 0 但至少有一个候选被跳过,应记录 HCCL_ERROR 或抛出异常。

likedislike
不准确?
103 111 
104- // 取出对应的端口,然后去ranktableInfo中查对应端口的地址信息112+ // 绕路两端口均须属于 RankTable layer 0。
105- // todo 逻辑判断一下只取第一个端口是否正确?113+ IpAddress src2detAddr;
106- IpAddress src2detAddr = data.srcNetInstPeer->GetPortAddrMapLayer0()[*src2detPorts.begin()][0];114+ IpAddress det2dstAddr;
107- IpAddress det2dstAddr = data.dstNetInstPeer->GetPortAddrMapLayer0()[*det2dstPorts.begin()][0];115+ if (!data.srcNetInstPeer->TryGetLayer0Address(*src2detPorts.begin(), src2detAddr)
116+ || !data.dstNetInstPeer->TryGetLayer0Address(*det2dstPorts.begin(), det2dstAddr)) {
117+ HCCL_WARNING("[DetourService][InsertDetourLinks][AddDetourLink] Ignore P2P candidate not in layer0");
118+ continue;
119+ }
108 120 
109 // 构造InterFace对象用于后续生成Link121 // 构造InterFace对象用于后续生成Link
110 shared_ptr<NetInstance::ConnInterface> sourceIface = make_shared<NetInstance::ConnInterface>(122 shared_ptr<NetInstance::ConnInterface> sourceIface = make_shared<NetInstance::ConnInterface>(
@@ -125,10 +137,6 @@ void AddDetourLink(
125 innerNetInst->AddLink(recvEdge);137 innerNetInst->AddLink(recvEdge);
126 138 
127 data.srcNetInstPeer->AddConnInterface(0, sourceIface);139 data.srcNetInstPeer->AddConnInterface(0, sourceIface);
128- if (data.dstNetInstPeer == nullptr) {
129- THROW<NullPtrException>(
130- StringFormat("[DetourService][InsertDetourLinks][AddDetourLink] dstVirtPeer is nullptr"));
131- }
132 data.dstNetInstPeer->AddConnInterface(0, targetIface);140 data.dstNetInstPeer->AddConnInterface(0, targetIface);
133 141 
134 HCCL_DEBUG(142 HCCL_DEBUG(
@@ -304,7 +312,7 @@ void AddDetourLinks(
304 std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable,312 std::unordered_map<LocalId, unordered_map<LocalId, vector<LocalId>>>& detourTable,
305 std::unordered_map<LocalId, u32>& tableIds, const RankTableInfo* rankTable)313 std::unordered_map<LocalId, u32>& tableIds, const RankTableInfo* rankTable)
306{314{
307- auto phyTopoGraph = phyTopo->GetTopoGraph(0);315+ auto phyTopoGraph = phyTopo->GetTopoGraph();
308 NetInstance* innerNetInst = rankGraph->GetNetInstanceByRankId(0, rankGraph->GetMyRank());316 NetInstance* innerNetInst = rankGraph->GetNetInstanceByRankId(0, rankGraph->GetMyRank());
309 if (innerNetInst == nullptr) {317 if (innerNetInst == nullptr) {
310 THROW<NullPtrException>(StringFormat("[DetourService] innerNetInst is nullptr"));318 THROW<NullPtrException>(StringFormat("[DetourService] innerNetInst is nullptr"));
@@ -10,10 +10,18 @@
10 10 
11#include <algorithm>11#include <algorithm>
12#include <array>12#include <array>
13+#include <iterator>
14+#include <set>
13#include "rank_graph_builder.h"15#include "rank_graph_builder.h"
14#include "detour_service.h"16#include "detour_service.h"
17+#include "hccp_ctx.h"
15#include "json_parser.h"18#include "json_parser.h"
16#include "phy_topo_builder.h"19#include "phy_topo_builder.h"
20+#include "rdma_handle_manager.h"
21+ 
22+namespace hcomm {
23+HcclResult HccpRaGetDevBaseAttr(void* ctxHandle, struct DevBaseAttr* attr);
24+}
17 25 
18namespace Hccl {26namespace Hccl {
19 27 
@@ -65,18 +73,29 @@ const RankLevelInfo& RankGraphBuilder::GetRankLevelInfoByNetLayer(const NewRankI
65 return *it;73 return *it;
66}74}
67 75 
68-std::vector<shared_ptr<PhyTopo::Link>> GetPeer2NetPhyLinks(u32 netLayer, LocalId localId)76+u32 RankGraphBuilder::GetLocalDeviceId() const
69{77{
70- const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyGraph = PhyTopo::GetInstance()->GetTopoGraph(netLayer);78+ if (rankGraph_ == nullptr) {
79+ THROW<NullPtrException>(StringFormat("[RankGraphBuilder][GetLocalDeviceId] rankGraph is nullptr"));
80+ }
81+ auto peer = rankGraph_->GetPeer(myRank_);
82+ if (peer == nullptr) {
83+ THROW<NullPtrException>(StringFormat("[RankGraphBuilder][GetLocalDeviceId] local peer is nullptr"));
84+ }
85+ return peer->GetDeviceId();
86+}
87+ 
88+std::vector<shared_ptr<PhyTopo::Link>> GetPeer2NetPhyLinks(LocalId localId)
89+{
90+ const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyGraph = PhyTopo::GetInstance()->GetTopoGraph();
71 if (phyGraph == nullptr) {91 if (phyGraph == nullptr) {
72- THROW<InvalidParamsException>(StringFormat(92+ THROW<InvalidParamsException>(
73- "[RankGraphBuilder][GetPhyLink] localId[%d] is not level[%u] in"93+ StringFormat("[RankGraphBuilder][GetPhyLink] physical topo graph is null for localId[%d].", localId));
74- " topo.json, not match rankTable.",
75- localId, netLayer));
76 }94 }
77 std::vector<shared_ptr<PhyTopo::Link>> links;95 std::vector<shared_ptr<PhyTopo::Link>> links;
96+ // 统一物理图包含多种边,此处仅收集 PEER2NET 边。
78 phyGraph->TraverseEdge(PhyTopo::Peer::GetId(localId), [&](shared_ptr<PhyTopo::Link> link) {97 phyGraph->TraverseEdge(PhyTopo::Peer::GetId(localId), [&](shared_ptr<PhyTopo::Link> link) {
79- if (link != nullptr) {98+ if (link != nullptr && link->GetType() == LinkType::PEER2NET) {
80 links.push_back(link);99 links.push_back(link);
81 }100 }
82 });101 });
@@ -88,12 +107,223 @@ std::vector<shared_ptr<PhyTopo::Link>> GetPeer2NetPhyLinks(u32 netLayer, LocalId
88 return links;107 return links;
89}108}
90 109 
110+bool IsPeer2NetLinkMatched(const shared_ptr<PhyTopo::Link>& link, const AddressInfo& addrInfo)
111+{
112+ if (link == nullptr || link->GetType() != LinkType::PEER2NET || link->GetSourceIFace() == nullptr) {
113+ return false;
114+ }
115+ // 端口有交集时,该物理边才属于当前 RankTable 地址。
116+ const auto& phyPorts = link->GetSourceIFace()->GetPorts();
117+ return std::any_of(addrInfo.ports.begin(), addrInfo.ports.end(), [&phyPorts](const std::string& port) {
118+ return phyPorts.count(port) != 0;
119+ });
120+}
121+ 
122+std::vector<shared_ptr<PhyTopo::Link>> GetMatchedPeer2NetPhyLinks(
123+ const vector<shared_ptr<PhyTopo::Link>>& links, const AddressInfo& addrInfo,
124+ const std::map<PlaneId, LinkProtocol>& planeUbProtocols)
125+{
126+ vector<shared_ptr<PhyTopo::Link>> matchedLinks;
127+ matchedLinks.reserve(links.size());
128+ const auto protocolIter = planeUbProtocols.find(addrInfo.planeId);
129+ const bool hasPlaneUbProtocol = protocolIter != planeUbProtocols.end();
130+ const LinkProtocol planeUbProtocol
131+ = hasPlaneUbProtocol ? protocolIter->second : LinkProtocol(LinkProtocol::INVALID);
132+ std::copy_if(
133+ links.begin(), links.end(), std::back_inserter(matchedLinks),
134+ [&addrInfo, hasPlaneUbProtocol, planeUbProtocol](const shared_ptr<PhyTopo::Link>& link) {
135+ if (!IsPeer2NetLinkMatched(link, addrInfo)) {
136+ return false;
137+ }
138+ return !hasPlaneUbProtocol || link->GetLinkProtocols().count(planeUbProtocol) != 0;
139+ });
140+ return matchedLinks;
141+}
142+ 
143+namespace {
144+ 
145+ bool
146+ IsSamePhyInterface(const shared_ptr<PhyTopo::ConnInterface>& lhs, const shared_ptr<PhyTopo::ConnInterface>& rhs)
147+ {
148+ if (lhs == nullptr || rhs == nullptr) {
149+ return lhs == rhs;
150+ }
151+ return *lhs == *rhs;
152+ }
153+ 
154+ bool IsSamePeer2NetLinkExceptTopoInstId(const shared_ptr<PhyTopo::Link>& lhs, const shared_ptr<PhyTopo::Link>& rhs)
155+ {
156+ if (lhs == nullptr || rhs == nullptr) {
157+ return lhs == rhs;
158+ }
159+ return lhs->GetSourceNode() == rhs->GetSourceNode() && lhs->GetTargetNode() == rhs->GetTargetNode()
160+ && lhs->GetType() == rhs->GetType() && lhs->GetLinkProtocols() == rhs->GetLinkProtocols()
161+ && lhs->GetLinkDirection() == rhs->GetLinkDirection() && lhs->GetTopoType() == rhs->GetTopoType()
162+ && lhs->GetHop() == rhs->GetHop() && IsSamePhyInterface(lhs->GetSourceIFace(), rhs->GetSourceIFace())
163+ && IsSamePhyInterface(lhs->GetTargetIFace(), rhs->GetTargetIFace());
164+ }
165+ 
166+ std::vector<shared_ptr<PhyTopo::Link>>
167+ DeduplicatePeer2NetPhyLinks(std::vector<shared_ptr<PhyTopo::Link>> matchedLinks)
168+ {
169+ std::vector<shared_ptr<PhyTopo::Link>> uniqueLinks;
170+ uniqueLinks.reserve(matchedLinks.size());
171+ for (const auto& link : matchedLinks) {
172+ const auto duplicate
173+ = std::find_if(uniqueLinks.begin(), uniqueLinks.end(), [&link](const auto& uniqueLink) {
174+ return IsSamePeer2NetLinkExceptTopoInstId(link, uniqueLink);
175+ });
176+ if (duplicate == uniqueLinks.end()) {
177+ uniqueLinks.emplace_back(link);
178+ continue;
179+ }
180+ const u32 oldTopoInstId = (*duplicate)->GetTopoInstId();
181+ const u32 newTopoInstId = link->GetTopoInstId();
182+ if (newTopoInstId < oldTopoInstId) {
183+ *duplicate = link;
184+ }
185+ // 等价物理边共用一条逻辑边,并保留较小的拓扑实例 ID。
186+ HCCL_DEBUG(
187+ "[RankGraphBuilder][DeduplicatePeer2NetPhyLinks] ignore topoInstId[%u], keep topoInstId[%u].",
188+ std::max(oldTopoInstId, newTopoInstId), std::min(oldTopoInstId, newTopoInstId));
189+ }
190+ return uniqueLinks;
191+ }
192+ 
193+ std::vector<shared_ptr<PhyTopo::Link>> GetMatchedPeer2NetPhyLinksForLayer(
194+ u32 netLayer, const vector<shared_ptr<PhyTopo::Link>>& links, const AddressInfo& addrInfo,
195+ const std::map<PlaneId, LinkProtocol>& planeUbProtocols)
196+ {
197+ std::vector<shared_ptr<PhyTopo::Link>> matchedLinks
198+ = GetMatchedPeer2NetPhyLinks(links, addrInfo, planeUbProtocols);
199+ if (netLayer == 0) {
200+ // layer 0 保持 topo 描述语义,只对 RankTable 定义的高层网络去重。
201+ return matchedLinks;
202+ }
203+ return DeduplicatePeer2NetPhyLinks(std::move(matchedLinks));
204+ }
205+ 
206+ shared_ptr<NetInstance::Fabric> GetOrCreateFabricNode(
207+ FabricId fabId, const PlaneId& planeId, vector<shared_ptr<NetInstance::Fabric>>& fabNodes,
208+ const shared_ptr<NetInstance>& netInst)
209+ {
210+ if (fabNodes[fabId] == nullptr) {
211+ fabNodes[fabId] = make_shared<NetInstance::Fabric>(fabId, planeId);
212+ netInst->AddNode(fabNodes[fabId]);
213+ }
214+ return fabNodes[fabId];
215+ }
216+ 
217+} // namespace
218+ 
219+const vector<shared_ptr<PhyTopo::Link>>& RankGraphBuilder::GetPeer2NetPhyLinksCached(LocalId localId)
220+{
221+ auto iter = peer2NetPhyLinksCache_.find(localId);
222+ if (iter == peer2NetPhyLinksCache_.end()) {
223+ iter = peer2NetPhyLinksCache_.emplace(localId, GetPeer2NetPhyLinks(localId)).first;
224+ }
225+ return iter->second;
226+}
227+ 
228+LinkProtocol RankGraphBuilder::ResolveUbProtocolByEid(const AddressInfo& addrInfo, bool& supportsRtp) const
229+{
230+ if (addrInfo.addrType != AddrType::EID) {
231+ THROW<InvalidParamsException>(StringFormat(
232+ "[RankGraphBuilder][ResolveUbProtocolByEid] addr[%s] is not an EID, cannot distinguish UB protocol.",
233+ addrInfo.addr.Describe().c_str()));
234+ }
235+ 
236+ const auto rdmaHandle = RdmaHandleManager::GetInstance().GetByIp(GetLocalDeviceId(), addrInfo.addr);
237+ if (rdmaHandle == nullptr) {
238+ THROW<NullPtrException>(StringFormat(
239+ "[RankGraphBuilder][ResolveUbProtocolByEid] get context failed for EID[%s].",
240+ addrInfo.addr.Describe().c_str()));
241+ }
242+ 
243+ DevBaseAttr devBaseAttr{};
244+ const HcclResult ret = hcomm::HccpRaGetDevBaseAttr(rdmaHandle, &devBaseAttr);
245+ if (ret != HCCL_SUCCESS) {
246+ THROW<InternalException>(StringFormat(
247+ "[RankGraphBuilder][ResolveUbProtocolByEid] get device base attr failed for EID[%s], ret[%d].",
248+ addrInfo.addr.Describe().c_str(), static_cast<int>(ret)));
249+ }
250+ 
251+ bool hasCtp = false;
252+ bool hasRtp = false;
253+ for (u32 priority = 0U; priority < static_cast<u32>(MAX_PRIORITY_CNT); ++priority) {
254+ const CtxSlInfo& priorityInfo = devBaseAttr.ub.priorityInfo[priority];
255+ hasCtp = hasCtp || priorityInfo.tpType.bs.ctp != 0;
256+ hasRtp = hasRtp || priorityInfo.tpType.bs.rtp != 0;
257+ }
258+ 
259+ // topo 中 UB_CTP 边同时承载 UB_MEM;EID 支持 CTP 时优先保留该边,
260+ // 仅当 EID 不支持 CTP 但支持 RTP 时匹配 UB_TP 边。
261+ supportsRtp = hasRtp;
262+ if (hasCtp) {
263+ HCCL_INFO(
264+ "[RankGraphBuilder][ResolveUbProtocolByEid] EID[%s] protocol[UB_CTP], hasCtp[%d], hasRtp[%d].",
265+ addrInfo.addr.Describe().c_str(), static_cast<int>(hasCtp), static_cast<int>(hasRtp));
266+ return LinkProtocol::UB_CTP;
267+ }
268+ if (hasRtp) {
269+ HCCL_INFO(
270+ "[RankGraphBuilder][ResolveUbProtocolByEid] EID[%s] protocol[UB_TP], hasCtp[%d], hasRtp[%d].",
271+ addrInfo.addr.Describe().c_str(), static_cast<int>(hasCtp), static_cast<int>(hasRtp));
272+ return LinkProtocol::UB_TP;
273+ }
274+ 
275+ THROW<InvalidParamsException>(StringFormat(
276+ "[RankGraphBuilder][ResolveUbProtocolByEid] EID[%s] has neither CTP nor RTP in priorityInfo.",
277+ addrInfo.addr.Describe().c_str()));
278+}
279+ 
280+std::map<PlaneId, LinkProtocol> RankGraphBuilder::ResolvePlaneUbProtocols(u32 netLayer, std::set<PlaneId>& ctpRtpPlanes)
281+{
282+ const auto& levelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[myRank_], netLayer);
283+ 
284+ ctpRtpPlanes.clear();
285+ std::map<PlaneId, LinkProtocol> planeProtocols;
286+ std::map<PlaneId, bool> planeExposeUbTp;
287+ for (const AddressInfo& addrInfo : levelInfo.rankAddrs) {
288+ if (addrInfo.addr == IpAddress() || addrInfo.addrType != AddrType::EID) {
289+ continue;
290+ }
291+ bool supportsRtp = false;
292+ const LinkProtocol currentProtocol = ResolveUbProtocolByEid(addrInfo, supportsRtp);
293+ const bool exposeUbTp = currentProtocol == LinkProtocol::UB_CTP && supportsRtp;
294+ HCCL_INFO(
295+ "[RankGraphBuilder][ResolvePlaneUbProtocols] netLayer[%u] planeId[%s] EID[%s] protocol[%s].", netLayer,
296+ addrInfo.planeId.c_str(), addrInfo.addr.Describe().c_str(), currentProtocol.Describe().c_str());
297+ const auto result = planeProtocols.emplace(addrInfo.planeId, currentProtocol);
298+ if (!result.second && result.first->second != currentProtocol) {
299+ THROW<InvalidParamsException>(StringFormat(
300+ "[RankGraphBuilder][ResolvePlaneUbProtocols] netLayer[%u] planeId[%s] contains mixed UB "
301+ "protocols[%s, %s].",
302+ netLayer, addrInfo.planeId.c_str(), result.first->second.Describe().c_str(),
303+ currentProtocol.Describe().c_str()));
304+ }
305+ const auto capabilityResult = planeExposeUbTp.emplace(addrInfo.planeId, exposeUbTp);
306+ if (!capabilityResult.second && capabilityResult.first->second != exposeUbTp) {
307+ THROW<InvalidParamsException>(StringFormat(
308+ "[RankGraphBuilder][ResolvePlaneUbProtocols] netLayer[%u] planeId[%s] contains mixed UB "
309+ "capabilities, exposeUbTp[%d, %d].",
310+ netLayer, addrInfo.planeId.c_str(), static_cast<int>(capabilityResult.first->second),
311+ static_cast<int>(exposeUbTp)));
312+ }
313+ if (exposeUbTp) {
314+ ctpRtpPlanes.insert(addrInfo.planeId);
315+ }
316+ }
317+ return planeProtocols;
318+}
319+ 
91void RankGraphBuilder::AddPeer2NetLink(320void RankGraphBuilder::AddPeer2NetLink(
92 const u32 netLayer, const string& netInstId, RankId rankId, const AddressInfo& addrInfo,321 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)322+ const shared_ptr<NetInstance::Fabric>& fabNode, const vector<shared_ptr<PhyTopo::Link>>& matchedLinks,
323+ bool exposeUbTp)
94{324{
95- for (shared_ptr<PhyTopo::Link> link : links) {325+ for (shared_ptr<PhyTopo::Link> link : matchedLinks) {
96- if (link->GetSourceIFace() == nullptr) {326+ if (link == nullptr || link->GetSourceIFace() == nullptr) {
97 continue;327 continue;
98 }328 }
99 std::set<std::string> ports = link->GetSourceIFace()->GetPorts();329 std::set<std::string> ports = link->GetSourceIFace()->GetPorts();
@@ -109,22 +339,25 @@ void RankGraphBuilder::AddPeer2NetLink(
109 // 获取topoInstId topoType339 // 获取topoInstId topoType
110 u32 topoInstId = link->GetTopoInstId();340 u32 topoInstId = link->GetTopoInstId();
111 auto topoType = link->GetTopoType();341 auto topoType = link->GetTopoType();
342+ std::set<LinkProtocol> linkProtocols = link->GetLinkProtocols();
343+ if (exposeUbTp && linkProtocols.count(LinkProtocol::UB_CTP) != 0) {
344+ // CTP/RTP 共存时仍复用 CTP 物理边,仅扩展逻辑协议能力。
345+ linkProtocols.insert(LinkProtocol::UB_TP);
346+ }
112 347 
113 // 构造 RankGraph 的 PeerIface348 // 构造 RankGraph 的 PeerIface
114 shared_ptr<NetInstance::ConnInterface> peerIface = make_shared<NetInstance::ConnInterface>(349 shared_ptr<NetInstance::ConnInterface> peerIface = make_shared<NetInstance::ConnInterface>(
115- addrInfo.addr, rankGraphPorts, link->GetSourceIFace()->GetPos(), LinkType::PEER2NET,350+ addrInfo.addr, rankGraphPorts, link->GetSourceIFace()->GetPos(), LinkType::PEER2NET, linkProtocols,
116- link->GetLinkProtocols(), topoType, topoInstId);351+ topoType, topoInstId);
117 // 获取 rankId 对应 PeerNode352 // 获取 rankId 对应 PeerNode
118 shared_ptr<NetInstance::Peer> peerNode = peers_.at(rankId);353 shared_ptr<NetInstance::Peer> peerNode = peers_.at(rankId);
119 peerNode->AddConnInterface(netLayer, peerIface);354 peerNode->AddConnInterface(netLayer, peerIface);
120 355 
121 // 构造 peer2netLink 和 net2peerLink 两条link356 // 构造 peer2netLink 和 net2peerLink 两条link
122 shared_ptr<NetInstance::Link> peer2netLink = make_shared<NetInstance::Link>(357 shared_ptr<NetInstance::Link> peer2netLink = make_shared<NetInstance::Link>(
123- peerNode, fabNode, peerIface, nullptr, LinkType::PEER2NET, link->GetLinkProtocols(), LinkDirection::BOTH,358+ peerNode, fabNode, peerIface, nullptr, LinkType::PEER2NET, linkProtocols, LinkDirection::BOTH, 2);
124- 2);
125 shared_ptr<NetInstance::Link> net2peerLink = make_shared<NetInstance::Link>(359 shared_ptr<NetInstance::Link> net2peerLink = make_shared<NetInstance::Link>(
126- fabNode, peerNode, nullptr, peerIface, LinkType::PEER2NET, link->GetLinkProtocols(), LinkDirection::BOTH,360+ fabNode, peerNode, nullptr, peerIface, LinkType::PEER2NET, linkProtocols, LinkDirection::BOTH, 2);
127- 2);
128 361 
129 // 插入 link362 // 插入 link
130 tempNetInsts_[netLayer][netInstId]->AddLink(peer2netLink);363 tempNetInsts_[netLayer][netInstId]->AddLink(peer2netLink);
@@ -156,7 +389,6 @@ void RankGraphBuilder::AddFabricInfo(u32 netLayer)
156 THROW<NotSupportException>(389 THROW<NotSupportException>(
157 StringFormat("[RankGraphBuilder][AddFabricInfo] NetInstance is not CLOS, not support add fabric."));390 StringFormat("[RankGraphBuilder][AddFabricInfo] NetInstance is not CLOS, not support add fabric."));
158 }391 }
159- set<RankId> inRanks = netInst->GetRankIds();
160 string netInstId = netInst->GetNetInstId();392 string netInstId = netInst->GetNetInstId();
161 const auto& myLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[myRank_], netLayer);393 const auto& myLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[myRank_], netLayer);
162 // 根据planeId确认Fabric个数,每个fabricId对应一个planeId394 // 根据planeId确认Fabric个数,每个fabricId对应一个planeId
@@ -167,37 +399,37 @@ void RankGraphBuilder::AddFabricInfo(u32 netLayer)
167 "[RankGraphBuilder][AddFabricInfo] current rankId[%d] netLayer[%u] group no net plane", myRank_, netLayer);399 "[RankGraphBuilder][AddFabricInfo] current rankId[%d] netLayer[%u] group no net plane", myRank_, netLayer);
168 return;400 return;
169 }401 }
402+ // topo 不再携带 net_layer;以本地 EID 的协议查询结果筛选对应物理边。
403+ std::set<PlaneId> ctpRtpPlanes;
404+ const std::map<PlaneId, LinkProtocol> planeUbProtocols = ResolvePlaneUbProtocols(netLayer, ctpRtpPlanes);
170 vector<shared_ptr<NetInstance::Fabric>> fabNodes(planeId2Node.size(), nullptr);405 vector<shared_ptr<NetInstance::Fabric>> fabNodes(planeId2Node.size(), nullptr);
406+ const shared_ptr<NetInstance>& buildingNetInst = tempNetInsts_[netLayer][netInstId];
171 407 
172 // 遍历每一个rankId,每个rankId都增加 peer2net 和 net2peer 两条链路408 // 遍历每一个rankId,每个rankId都增加 peer2net 和 net2peer 两条链路
173- for (RankId srcRankId : inRanks) {409+ for (RankId srcRankId : netInst->GetRankIds()) {
174 const auto& srcLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[srcRankId], netLayer);410 const auto& srcLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[srcRankId], netLayer);
175- const vector<AddressInfo>& addrs = srcLevelInfo.rankAddrs;
176 // rankId对应的物理逻辑localId411 // rankId对应的物理逻辑localId
177 LocalId localId = rankGraph_->GetLocalId(srcRankId);412 LocalId localId = rankGraph_->GetLocalId(srcRankId);
178- // 从物理拓扑图中找出 localId在 netLayer 中所有的peer2Net的边。413+ // 从物理拓扑图中找出 localId 的所有 peer2Net 边。
179- std::vector<shared_ptr<PhyTopo::Link>> links = GetPeer2NetPhyLinks(netLayer, localId);414+ const auto& links = GetPeer2NetPhyLinksCached(localId);
180 // 遍历ranktable中的addr,有几个addr就有几条peer2net的边415 // 遍历ranktable中的addr,有几个addr就有几条peer2net的边
181- for (AddressInfo addrInfo : addrs) {416+ for (const AddressInfo& addrInfo : srcLevelInfo.rankAddrs) {
182- if (addrInfo.addr == IpAddress()) {417+ if (addrInfo.addr == IpAddress() || planeId2Node.count(addrInfo.planeId) == 0) {
183 continue;418 continue;
184 }419 }
185- 420+ const vector<shared_ptr<PhyTopo::Link>> matchedLinks
186- if (planeId2Node.count(addrInfo.planeId) == 0) {421+ = GetMatchedPeer2NetPhyLinksForLayer(netLayer, links, addrInfo, planeUbProtocols);
422+ if (matchedLinks.empty()) {
187 continue;423 continue;
188 }424 }
189 FabricId fabId = planeId2Node[addrInfo.planeId];425 FabricId fabId = planeId2Node[addrInfo.planeId];
190 // 若 fabNodes[fabId] 不存在则创建 如果存在则获取fabNode426 // 若 fabNodes[fabId] 不存在则创建 如果存在则获取fabNode
191- shared_ptr<NetInstance::Fabric> fabNode;427+ shared_ptr<NetInstance::Fabric> fabNode
192- if (fabNodes[fabId] == nullptr) {428+ = GetOrCreateFabricNode(fabId, addrInfo.planeId, fabNodes, buildingNetInst);
193- fabNode = make_shared<NetInstance::Fabric>(fabId, addrInfo.planeId);
194- tempNetInsts_[netLayer][netInstId]->AddNode(fabNode);
195- fabNodes[fabId] = fabNode;
196- } else {
197- fabNode = fabNodes[fabId];
198- }
199 // 插入peer和fabric的peer2net和net2peer两条link429 // 插入peer和fabric的peer2net和net2peer两条link
200- AddPeer2NetLink(netLayer, netInstId, srcRankId, addrInfo, fabNode, links);430+ AddPeer2NetLink(
431+ netLayer, netInstId, srcRankId, addrInfo, fabNode, matchedLinks,
432+ ctpRtpPlanes.count(addrInfo.planeId) != 0);
201 }433 }
202 }434 }
203 435 
@@ -209,7 +441,7 @@ void RankGraphBuilder::AddFabricInfo(u32 netLayer)
209void RankGraphBuilder::AddTopoDescFabricInfo()441void RankGraphBuilder::AddTopoDescFabricInfo()
210{442{
211 // 1. 获取物理拓扑图443 // 1. 获取物理拓扑图
212- auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);444+ auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph();
213 if (phyTopoGraph == nullptr) {445 if (phyTopoGraph == nullptr) {
214 THROW<NullPtrException>(StringFormat("[RankGraphBuilder][AddTopoDescFabricInfo] phyTopoGraph is nullptr"));446 THROW<NullPtrException>(StringFormat("[RankGraphBuilder][AddTopoDescFabricInfo] phyTopoGraph is nullptr"));
215 }447 }
@@ -224,15 +456,19 @@ void RankGraphBuilder::AddTopoDescFabricInfo()
224 std::string netInstId = innerNetInstance->GetNetInstId();456 std::string netInstId = innerNetInstance->GetNetInstId();
225 std::set<RankId> rankIds = innerNetInstance->GetRankIds();457 std::set<RankId> rankIds = innerNetInstance->GetRankIds();
226 458 
227- // 存储所有fabric节点,key为topoInstId459+ // Fabric 的归属以 RankTable planeId 为准,topoInstId 仅保留为拓扑实例属性。
228- std::map<u32, std::shared_ptr<NetInstance::Fabric>> fabNodes;460+ const auto& myLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[myRank_], 0);
461+ const std::map<PlaneId, FabricId> planeId2Node = GetFabricsFromAddrInfo(myLevelInfo.rankAddrs);
462+ if (planeId2Node.empty()) {
463+ HCCL_WARNING("[RankGraphBuilder][AddTopoDescFabricInfo] rankId[%u] layer0 has no plane", myRank_);
464+ return;
465+ }
466+ vector<shared_ptr<NetInstance::Fabric>> fabNodes(planeId2Node.size(), nullptr);
229 467 
230- auto peer = rankGraph_->GetPeer(rankGraph_->GetMyRank());468+ // 3. 遍历所有 rank 节点,根据端口匹配到的 planeId 创建 Fabric。
231- auto localDeviceId = peer->GetDeviceId();
232- 
233- // 3. 遍历所有rank节点,根据topoInstId创建fabric节点
234 for (RankId rankId : rankIds) {469 for (RankId rankId : rankIds) {
235 LocalId localId = rankGraph_->GetLocalId(rankId);470 LocalId localId = rankGraph_->GetLocalId(rankId);
471+ const auto& levelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[rankId], 0);
236 auto peer2netEdges = phyTopoGraph->GetEdges(localId, PhyTopo::Fabric::GetId());472 auto peer2netEdges = phyTopoGraph->GetEdges(localId, PhyTopo::Fabric::GetId());
237 473 
238 HCCL_RUN_INFO(474 HCCL_RUN_INFO(
@@ -240,47 +476,30 @@ void RankGraphBuilder::AddTopoDescFabricInfo()
240 rankId, localId, peer2netEdges.size());476 rankId, localId, peer2netEdges.size());
241 477 
242 for (const auto& link : peer2netEdges) {478 for (const auto& link : peer2netEdges) {
243- u32 topoInstId = link->GetTopoInstId();479+ if (link == nullptr || link->GetType() != LinkType::PEER2NET || link->GetSourceIFace() == nullptr) {
244- auto topoType = link->GetTopoType();480+ continue;
245- 
246- // 创建Fabric节点
247- if (fabNodes.find(topoInstId) == fabNodes.end()) {
248- auto fabNodePtr = std::make_shared<NetInstance::Fabric>(topoInstId);
249- innerNetInstance->AddNode(fabNodePtr);
250- fabNodes[topoInstId] = fabNodePtr;
251- HCCL_INFO(
252- "[RankGraphBuilder][AddTopoDescFabricInfo] Created new Fabric node for topoInstId: %u", topoInstId);
253 }481 }
482+ for (const auto& addrInfo : levelInfo.rankAddrs) {
483+ auto planeIter = planeId2Node.find(addrInfo.planeId);
484+ if (addrInfo.addr == IpAddress() || planeIter == planeId2Node.end()
485+ || !IsPeer2NetLinkMatched(link, addrInfo)) {
486+ continue;
487+ }
254 488 
255- // 获取 peer 节点489+ FabricId fabId = planeIter->second;
256- auto peerNode = peers_.at(rankId);490+ shared_ptr<NetInstance::Fabric> fabNode = fabNodes[fabId];
491+ if (fabNode == nullptr) {
492+ fabNode = make_shared<NetInstance::Fabric>(fabId, addrInfo.planeId);
493+ innerNetInstance->AddNode(fabNode);
494+ fabNodes[fabId] = fabNode;
495+ HCCL_INFO(
496+ "[RankGraphBuilder][AddTopoDescFabricInfo] create Fabric for planeId[%s], "
497+ "fabricId[%u]",
498+ addrInfo.planeId.c_str(), fabId);
499+ }
257 500 
258- // 构造连接接口501+ const vector<shared_ptr<PhyTopo::Link>> matchedLinks = {link};
严正行
严正行严正行8月7日

[LOW] AddTopoDescFabricInfo 每次 addrInfo 迭代创建临时 vector,嵌套循环中产生分配抖动

第 395 行 const vector<shared_ptr<PhyTopo::Link>> matchedLinks = {link}; 在 rankId→link→addrInfo 的三重嵌套循环中每次创建一个单元素 vector(含 shared_ptr 引用计数原子操作),随即传入 AddPeer2NetLink 后销毁。虽然功能正确,但在大规模拓扑下产生不必要的堆分配与引用计数开销。

建议修复: AddPeer2NetLink 可增加一个接受单个 shared_ptr<PhyTopo::Link> 的重载,或在此处直接内联处理逻辑,避免临时 vector 构造。

likedislike
259- auto peerIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(502+ AddPeer2NetLink(0, netInstId, rankId, addrInfo, fabNode, matchedLinks, false);
260- link->GetSourceIFace(), peerNode->GetPortAddrMapLayer0(), topoType, topoInstId, localDeviceId);
261- 
262- for (const auto& iface : peerIfaces) {
263- peerNode->AddConnInterface(0, iface);
264- }
265- auto fabNodePtr = fabNodes[topoInstId];
266- // 构造 peer2netLink 和 net2peerLink(双向)
267- for (const auto& iface : peerIfaces) {
268- auto peer2netLink = std::make_shared<NetInstance::Link>(
269- peerNode, fabNodePtr, iface, nullptr, LinkType::PEER2NET, link->GetLinkProtocols(),
270- LinkDirection::BOTH, 2);
271- 
272- auto net2peerLink = std::make_shared<NetInstance::Link>(
273- fabNodePtr, peerNode, nullptr, iface, LinkType::PEER2NET, link->GetLinkProtocols(),
274- LinkDirection::BOTH, 2);
275- 
276- // 插入 link
277- tempNetInsts_[0][netInstId]->AddLink(peer2netLink);
278- tempNetInsts_[0][netInstId]->AddLink(net2peerLink);
279- tempNetInsts_[0][netInstId]->UpdateTopoInst(topoInstId, topoType, rankId);
280- HCCL_RUN_INFO(
281- "[RankGraphBuilder][AddTopoDescFabricInfo] netLayer0 rankId[%u] netInstId[%s] Add Fabric "
282- "Info success!",
283- rankId, netInstId.c_str());
284 }503 }
285 }504 }
286 }505 }
@@ -299,21 +518,12 @@ std::map<PlaneId, FabricId> GetFabricsFromAddrInfo(const std::vector<AddressInfo
299 return planeId2FabricId;518 return planeId2FabricId;
300}519}
301 520 
302-void RankGraphBuilder::CheckNetLayerFromPhyTopo(const u32 netLayer) const
303-{
304- if (!PhyTopo::GetInstance()->IsNetLayerExisted(netLayer)) {
305- THROW<InvalidParamsException>(StringFormat(
306- "[RankGraphBuilder][CheckNetLayerFromPhyTopo]"
307- "netLayer[%u] not exist in topo.",
308- netLayer));
309- }
310-}
311- 
312// 根据ranktable构造添加peers和NetInstances, NetInstance添加nodes和links(peer2net)521// 根据ranktable构造添加peers和NetInstances, NetInstance添加nodes和links(peer2net)
313// 1. 创建NetInstance ( 每个NetInstance 添加 Rank, Node, Link);522// 1. 创建NetInstance ( 每个NetInstance 添加 Rank, Node, Link);
314// 2. RankGraph中添加NetInstance, Peer, Fabric,523// 2. RankGraph中添加NetInstance, Peer, Fabric,
315void RankGraphBuilder::BuildFromRankTable()524void RankGraphBuilder::BuildFromRankTable()
316{525{
526+ peer2NetPhyLinksCache_.clear();
317 // 保存NetInstance指针以便后续执行Add操作527 // 保存NetInstance指针以便后续执行Add操作
318 tempNetInsts_.resize(MAX_NET_LAYER); // 为了方便修改RankGraph的NetInstance,共享指针。528 tempNetInsts_.resize(MAX_NET_LAYER); // 为了方便修改RankGraph的NetInstance,共享指针。
319 529 
@@ -329,8 +539,6 @@ void RankGraphBuilder::BuildFromRankTable()
329 539 
330 // 构造当前rank的每个LevelInfo所在NetInstance, 添加 RankId 和 Peer540 // 构造当前rank的每个LevelInfo所在NetInstance, 添加 RankId 和 Peer
331 for (const auto& levelInfo : rankInfo.rankLevelInfos) {541 for (const auto& levelInfo : rankInfo.rankLevelInfos) {
332- // 校验netLayer是否在topo中
333- CheckNetLayerFromPhyTopo(levelInfo.netLayer);
334 // rankLevelInfo.level、id对应NetInstance,若不存在则创建542 // rankLevelInfo.level、id对应NetInstance,若不存在则创建
335 auto curNetInstance = GetOrCreateNetInstance(543 auto curNetInstance = GetOrCreateNetInstance(
336 levelInfo.netLayer, levelInfo.netInstId, levelInfo.netType, tempNetInsts_, rankGraph_.get());544 levelInfo.netLayer, levelInfo.netInstId, levelInfo.netType, tempNetInsts_, rankGraph_.get());
@@ -379,6 +587,18 @@ void RankGraphBuilder::SetEndpointDesc()
379 for (const auto& layer : layers) {587 for (const auto& layer : layers) {
380 auto ifacesVec = peer->GetIfacesByLayer(layer);588 auto ifacesVec = peer->GetIfacesByLayer(layer);
381 for (const auto& iface : ifacesVec) {589 for (const auto& iface : ifacesVec) {
590+ const auto& ports = iface->GetPorts();
591+ std::string portsStr;
592+ for (auto portIter = ports.begin(); portIter != ports.end(); ++portIter) {
593+ if (portIter != ports.begin()) {
594+ portsStr += ",";
595+ }
596+ portsStr += *portIter;
597+ }
598+ HCCL_INFO(
599+ "[RankGraphBuilder::SetEndpointDesc] layer[%u] topoInstId[%u] bwCoeff[%zu] ports[%s]", layer,
600+ iface->GetTopoInstId(), ports.size(), portsStr.c_str());
601+ 
382 const auto& protocols = iface->GetLinkProtocols();602 const auto& protocols = iface->GetLinkProtocols();
383 for (const auto& protocol : protocols) {603 for (const auto& protocol : protocols) {
384 EndpointDesc desc{};604 EndpointDesc desc{};
@@ -394,7 +614,7 @@ void RankGraphBuilder::SetEndpointDesc()
394 HCCL_INFO(614 HCCL_INFO(
395 "[RankGraphBuilder::SetEndpointDesc] local type[%d] protocol[%d]", desc.loc.locType, desc.protocol);615 "[RankGraphBuilder::SetEndpointDesc] local type[%d] protocol[%d]", desc.loc.locType, desc.protocol);
396 616 
397- peer->SetEndpointToIface(desc.commAddr, desc.protocol, iface);617+ peer->SetEndpointToIface(layer, iface->GetTopoInstId(), desc.commAddr, desc.protocol, iface);
398 }618 }
399 }619 }
400 }620 }
@@ -434,7 +654,7 @@ std::shared_ptr<NetInstance> RankGraphBuilder::CreateNetInstance(const RankLevel
434// 从phytopo和ranktable中读取数据共同构建peer2peer的边。654// 从phytopo和ranktable中读取数据共同构建peer2peer的边。
435void RankGraphBuilder::BuildPeer2PeerLinks()655void RankGraphBuilder::BuildPeer2PeerLinks()
436{656{
437- auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);657+ auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph();
438 if (phyTopoGraph == nullptr) {658 if (phyTopoGraph == nullptr) {
439 THROW<NullPtrException>(StringFormat("[RankGraphBuilder][BuildPeer2PeerLinks] phyTopoGraph is nullptr"));659 THROW<NullPtrException>(StringFormat("[RankGraphBuilder][BuildPeer2PeerLinks] phyTopoGraph is nullptr"));
440 }660 }
@@ -445,8 +665,7 @@ void RankGraphBuilder::BuildPeer2PeerLinks()
445 }665 }
446 set<RankId> rankIds = innerNetInstance->GetRankIds();666 set<RankId> rankIds = innerNetInstance->GetRankIds();
447 667 
448- auto peer = rankGraph_->GetPeer(rankGraph_->GetMyRank());668+ auto localDeviceId = GetLocalDeviceId();
449- auto localDeviceId = peer->GetDeviceId();
450 for (const auto srcRankId : rankIds) {669 for (const auto srcRankId : rankIds) {
451 for (const auto dstRankId : rankIds) {670 for (const auto dstRankId : rankIds) {
452 if (srcRankId == dstRankId) {671 if (srcRankId == dstRankId) {
@@ -462,7 +681,7 @@ void RankGraphBuilder::BuildPeer2PeerLinks()
462 681 
463 std::vector<shared_ptr<PhyTopo::Link>> phyLinks682 std::vector<shared_ptr<PhyTopo::Link>> phyLinks
464 = GetPeer2PeerPhyLinks(phyTopoGraph, srcLocalId, dstLocalId);683 = GetPeer2PeerPhyLinks(phyTopoGraph, srcLocalId, dstLocalId);
465- // 根据ports在ranktable找对对应的地址,几个地址就有几条link。684+ // 按 RankTable layer 0 端口筛选物理 P2P 边并补齐地址。
466 685 
467 shared_ptr<NetInstance::Peer> srcPeer = peers_.at(srcRankId);686 shared_ptr<NetInstance::Peer> srcPeer = peers_.at(srcRankId);
468 shared_ptr<NetInstance::Peer> dstPeer = peers_.at(dstRankId);687 shared_ptr<NetInstance::Peer> dstPeer = peers_.at(dstRankId);
@@ -505,7 +724,8 @@ void RankGraphBuilder::UpdateTopoInstForMyRankOnly()
505 auto netInstId = innerNetInstance->GetNetInstId();724 auto netInstId = innerNetInstance->GetNetInstId();
506 set<RankId> rankIds = innerNetInstance->GetRankIds();725 set<RankId> rankIds = innerNetInstance->GetRankIds();
507 726 
508- auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);727+ auto localDeviceId = GetLocalDeviceId();
728+ auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph();
509 if (phyTopoGraph == nullptr) {729 if (phyTopoGraph == nullptr) {
510 THROW<NullPtrException>(730 THROW<NullPtrException>(
511 StringFormat("[RankGraphBuilder][UpdateTopoInstForMyRankOnly] phyTopoGraph is nullptr"));731 StringFormat("[RankGraphBuilder][UpdateTopoInstForMyRankOnly] phyTopoGraph is nullptr"));
@@ -520,20 +740,34 @@ void RankGraphBuilder::UpdateTopoInstForMyRankOnly()
520 for (const auto srcRankId : rankIds) {740 for (const auto srcRankId : rankIds) {
521 for (const auto dstRankId : rankIds) {741 for (const auto dstRankId : rankIds) {
522 // 只处理涉及 myRank_ 的边742 // 只处理涉及 myRank_ 的边
523- if (srcRankId != myRank_ && dstRankId != myRank_) {743+ if (srcRankId == dstRankId || (srcRankId != myRank_ && dstRankId != myRank_)) {
524 continue;744 continue;
525 }745 }
526 746 
527 LocalId srcLocalId = rankGraph_->GetLocalId(srcRankId);747 LocalId srcLocalId = rankGraph_->GetLocalId(srcRankId);
528 LocalId dstLocalId = rankGraph_->GetLocalId(dstRankId);748 LocalId dstLocalId = rankGraph_->GetLocalId(dstRankId);
749+ if (srcLocalId == BACKUP_LOCAL_ID || dstLocalId == BACKUP_LOCAL_ID) {
750+ continue;
751+ }
529 752 
530 std::vector<shared_ptr<PhyTopo::Link>> phyLinks753 std::vector<shared_ptr<PhyTopo::Link>> phyLinks
531 = GetPeer2PeerPhyLinks(phyTopoGraph, srcLocalId, dstLocalId);754 = GetPeer2PeerPhyLinks(phyTopoGraph, srcLocalId, dstLocalId);
755+ // 通过 RankTable layer 0 端口映射物理 P2P 链路。
756+ const auto& srcLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[srcRankId], 0);
757+ const auto& dstLevelInfo = GetRankLevelInfoByNetLayer(rankTable_->ranks[dstRankId], 0);
532 758 
533 for (shared_ptr<PhyTopo::Link> phyLink : phyLinks) {759 for (shared_ptr<PhyTopo::Link> phyLink : phyLinks) {
534- u32 topoInstId = phyLink->GetTopoInstId();760+ auto sourceIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(
严正行
严正行严正行8月7日

[MEDIUM] UpdateTopoInstForMyRankOnly 构造 ConnInterface 后丢弃,仅为空检查触发无意义分配与系统调用

第 626-636 行在 UpdateTopoInstForMyRankOnly 中调用 ConstructConnIFromPhyTopoConnIAndPortMap 构造 sourceIfaces/targetIfaces,但构造完成后仅检查 .empty() 就将其丢弃,未传给 AddConnInterface 或 ConstructLinks。ConstructConnIFromPhyTopoConnIAndPortMap 内部通过 make_shared 分配 ConnInterface 对象,且对 PCIe 链路会调用 HrtRaSocketGetVnicIpInfos 系统调用查询 VNIC 信息——这些分配与系统调用的结果被直接丢弃。

问题分析:

  • 第 626-628 行:构造 sourceIfaces,分配 shared_ptr 并可能触发 VNIC 查询。
  • 第 629-631 行:构造 targetIfaces,同上。
  • 第 632-634 行:仅检查 empty(),若非空则直接调用 UpdateTopoInst,不使用构造的接口对象。
  • 旧代码直接调用 UpdateTopoInst(topoInstId, topoType, dstRankId),不构造接口。
  • 在大拓扑(多 rank、多 P2P 边)的嵌套循环中,每次迭代浪费的分配与系统调用累积显著。

建议修复: 用一个轻量的端口匹配检查替代完整 ConnInterface 构造:

// 仅检查物理端口是否在 RankTable 中有对应地址
auto phyPorts = phyLink->GetSourceIFace()->GetPorts();
bool srcMatched = std::any_of(phyPorts.begin(), phyPorts.end(),
    [&srcLevelInfo](const std::string& p) { return srcLevelInfo.portAddrMap.count(p) > 0; });
// 同理检查 target
if (!srcMatched || !tgtMatched) { continue; }
likedislike
535- auto topoType = phyLink->GetTopoType();761+ phyLink->GetSourceIFace(), srcLevelInfo.portAddrMap, phyLink->GetTopoType(),
536- tempNetInsts_[0][netInstId]->UpdateTopoInst(topoInstId, topoType, dstRankId);762+ phyLink->GetTopoInstId(), localDeviceId);
763+ auto targetIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(
764+ phyLink->GetTargetIFace(), dstLevelInfo.portAddrMap, phyLink->GetTopoType(),
765+ phyLink->GetTopoInstId(), localDeviceId);
766+ if (sourceIfaces.empty() || targetIfaces.empty()) {
767+ continue;
768+ }
769+ tempNetInsts_[0][netInstId]->UpdateTopoInst(
770+ phyLink->GetTopoInstId(), phyLink->GetTopoType(), dstRankId);
537 }771 }
538 }772 }
539 }773 }
@@ -547,6 +781,7 @@ std::vector<std::shared_ptr<NetInstance::ConnInterface>> ConstructConnIFromPhyTo
547 std::vector<std::shared_ptr<NetInstance::ConnInterface>> netConnIFaces;781 std::vector<std::shared_ptr<NetInstance::ConnInterface>> netConnIFaces;
548 std::set<string> phyPorts = phyConnIFace->GetPorts();782 std::set<string> phyPorts = phyConnIFace->GetPorts();
549 std::map<IpAddress, std::set<string>> addr2Ports;783 std::map<IpAddress, std::set<string>> addr2Ports;
784+ // 非 PCIe 端口仅保留 RankTable 中存在的物理端口。
550 for (auto port : phyPorts) {785 for (auto port : phyPorts) {
551 if (*(phyConnIFace->GetLinkProtocols().begin()) == LinkProtocol::PCIE) {786 if (*(phyConnIFace->GetLinkProtocols().begin()) == LinkProtocol::PCIE) {
552 IpAddress tempIp;787 IpAddress tempIp;
@@ -623,7 +858,7 @@ std::vector<std::shared_ptr<PhyTopo::Link>> GetPeer2PeerPhyLinks(
623 NodeId dstNodeId = PhyTopo::Peer::GetId(dstLocalId);858 NodeId dstNodeId = PhyTopo::Peer::GetId(dstLocalId);
624 859 
625 phyTopoGraph->TraverseEdge(srcNodeId, dstNodeId, [&](shared_ptr<PhyTopo::Link> link) {860 phyTopoGraph->TraverseEdge(srcNodeId, dstNodeId, [&](shared_ptr<PhyTopo::Link> link) {
626- if (link != nullptr) {861+ if (link != nullptr && link->GetType() == LinkType::PEER2PEER) {
627 links.push_back(link);862 links.push_back(link);
628 }863 }
629 });864 });
@@ -13,6 +13,7 @@
13 13 
14#include <memory>14#include <memory>
15#include <map>15#include <map>
16+#include <set>
16#include <string>17#include <string>
17#include <vector>18#include <vector>
18 19 
@@ -42,28 +43,33 @@ private:
42 std::unique_ptr<RankGraph> rankGraph_;43 std::unique_ptr<RankGraph> rankGraph_;
43 RankId2PeerMap peers_;44 RankId2PeerMap peers_;
44 Level2Id2NetInst tempNetInsts_;45 Level2Id2NetInst tempNetInsts_;
46+ std::map<LocalId, std::vector<std::shared_ptr<PhyTopo::Link>>> peer2NetPhyLinksCache_;
45 RankId myRank_;47 RankId myRank_;
46 std::shared_ptr<TopoInfo> topoInfo_;48 std::shared_ptr<TopoInfo> topoInfo_;
47 UpdaterFor64Plus1 updaterFor64Plus1_{};49 UpdaterFor64Plus1 updaterFor64Plus1_{};
48 50 
49 void CheckMyRankInRankTable() const;51 void CheckMyRankInRankTable() const;
50- void CheckNetLayerFromPhyTopo(const u32 netLayer) const;
51 void BuildRankGraph();52 void BuildRankGraph();
52 void BuildFromRankTable();53 void BuildFromRankTable();
53 void BuildPeer2PeerLinks();54 void BuildPeer2PeerLinks();
54 void AddFabricInfo(u32 level);55 void AddFabricInfo(u32 level);
56+ LinkProtocol ResolveUbProtocolByEid(const AddressInfo& addrInfo, bool& supportsRtp) const;
57+ std::map<PlaneId, LinkProtocol> ResolvePlaneUbProtocols(u32 netLayer, std::set<PlaneId>& ctpRtpPlanes);
58+ const std::vector<std::shared_ptr<PhyTopo::Link>>& GetPeer2NetPhyLinksCached(LocalId localId);
55 void AddPeer2NetLink(59 void AddPeer2NetLink(
56 const u32 netLayer, const std::string& netInstId, RankId rankId, const AddressInfo& addrInfo,60 const u32 netLayer, const std::string& netInstId, RankId rankId, const AddressInfo& addrInfo,
57- const std::shared_ptr<NetInstance::Fabric>& fabNode, const std::vector<std::shared_ptr<PhyTopo::Link>>& links);61+ const std::shared_ptr<NetInstance::Fabric>& fabNode,
62+ const std::vector<std::shared_ptr<PhyTopo::Link>>& matchedLinks, bool exposeUbTp);
58 void AddTopoDescFabricInfo();63 void AddTopoDescFabricInfo();
59 void UpdateTopoInstForMyRankOnly();64 void UpdateTopoInstForMyRankOnly();
65+ u32 GetLocalDeviceId() const;
60 const RankLevelInfo& GetRankLevelInfoByNetLayer(const NewRankInfo& rankInfo, u32 netLayer) const;66 const RankLevelInfo& GetRankLevelInfoByNetLayer(const NewRankInfo& rankInfo, u32 netLayer) const;
61 std::shared_ptr<NetInstance> GetNetInstance(const RankLevelInfo& levelInfo);67 std::shared_ptr<NetInstance> GetNetInstance(const RankLevelInfo& levelInfo);
62 std::shared_ptr<NetInstance> CreateNetInstance(const RankLevelInfo& levelInfo);68 std::shared_ptr<NetInstance> CreateNetInstance(const RankLevelInfo& levelInfo);
63};69};
64 70 
65std::map<PlaneId, FabricId> GetFabricsFromAddrInfo(const std::vector<AddressInfo>& rankAddrs);71std::map<PlaneId, FabricId> GetFabricsFromAddrInfo(const std::vector<AddressInfo>& rankAddrs);
66-std::vector<std::shared_ptr<PhyTopo::Link>> GetPeer2NetPhyLinks(u32 netLayer, LocalId localId);72+std::vector<std::shared_ptr<PhyTopo::Link>> GetPeer2NetPhyLinks(LocalId localId);
67std::vector<std::shared_ptr<NetInstance::ConnInterface>> ConstructConnIFromPhyTopoConnIAndPortMap(73std::vector<std::shared_ptr<NetInstance::ConnInterface>> ConstructConnIFromPhyTopoConnIAndPortMap(
68 std::shared_ptr<PhyTopo::ConnInterface> phyConnIFace,74 std::shared_ptr<PhyTopo::ConnInterface> phyConnIFace,
69 const std::map<std::string, std::vector<IpAddress>>& portAddrMap, const TopoType topoType, const u32 topoInstId,75 const std::map<std::string, std::vector<IpAddress>>& portAddrMap, const TopoType topoType, const u32 topoInstId,
@@ -8,6 +8,8 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11+#include <algorithm>
12+ 
11#include "../rank_graph_builder/updater_for_64_plus_1.h"13#include "../rank_graph_builder/updater_for_64_plus_1.h"
12#include "topo_common_types.h"14#include "topo_common_types.h"
13#include "exception_util.h"15#include "exception_util.h"
@@ -17,6 +19,40 @@ namespace Hccl {
17 19 
18using namespace std;20using namespace std;
19 21 
22+namespace {
23+ 
24+ bool HasLayer0Port(const shared_ptr<NetInstance::Peer>& peer, const set<string>& ports)
25+ {
26+ if (peer == nullptr || ports.empty()) {
27+ return false;
28+ }
29+ IpAddress addr;
30+ return any_of(ports.begin(), ports.end(), [&peer, &addr](const string& port) {
31+ return peer->TryGetLayer0Address(port, addr);
32+ });
33+ }
34+ 
35+ bool HasLayer0Peer2PeerLink(
36+ const shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>& phyTopoGraph, const shared_ptr<NetInstance::Peer>& peer,
37+ LocalId replacedLocalId)
38+ {
39+ if (phyTopoGraph == nullptr || peer == nullptr) {
40+ return false;
41+ }
42+ bool matched = false;
43+ phyTopoGraph->TraverseEdge(
44+ PhyTopo::Peer::GetId(peer->GetLocalId()), PhyTopo::Peer::GetId(replacedLocalId),
45+ [&peer, &matched](const shared_ptr<PhyTopo::Link>& link) {
46+ if (link == nullptr || link->GetType() != LinkType::PEER2PEER || link->GetSourceIFace() == nullptr) {
47+ return;
48+ }
49+ matched = matched || HasLayer0Port(peer, link->GetSourceIFace()->GetPorts());
50+ });
51+ return matched;
52+ }
53+ 
54+} // namespace
55+ 
20void UpdaterFor64Plus1::SaveReplaceInfo(const NewRankInfo& rank)56void UpdaterFor64Plus1::SaveReplaceInfo(const NewRankInfo& rank)
21{57{
22 if (rank.localId != BACKUP_LOCAL_ID) {58 if (rank.localId != BACKUP_LOCAL_ID) {
@@ -72,7 +108,7 @@ void UpdaterFor64Plus1::UpdateNetInstance(
72 if (netInstance == nullptr) {108 if (netInstance == nullptr) {
73 THROW<NullPtrException>(StringFormat("[UpdaterFor64Plus1][%s] netInstance is nullptr", __func__));109 THROW<NullPtrException>(StringFormat("[UpdaterFor64Plus1][%s] netInstance is nullptr", __func__));
74 }110 }
75- auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);111+ auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph();
76 if (phyTopoGraph == nullptr) {112 if (phyTopoGraph == nullptr) {
77 THROW<NullPtrException>(StringFormat("[UpdaterFor64Plus1][%s] phyTopoGraph is nullptr", __func__));113 THROW<NullPtrException>(StringFormat("[UpdaterFor64Plus1][%s] phyTopoGraph is nullptr", __func__));
78 }114 }
@@ -92,7 +128,7 @@ void UpdaterFor64Plus1::UpdateNetInstance(
92 if (!IsSameX(peer->GetLocalId(), replacedLocalId) && !IsSameY(peer->GetLocalId(), replacedLocalId)) {128 if (!IsSameX(peer->GetLocalId(), replacedLocalId) && !IsSameY(peer->GetLocalId(), replacedLocalId)) {
93 continue;129 continue;
94 }130 }
95- if (!phyTopoGraph->HasEdge(PhyTopo::Peer::GetId(peer->GetLocalId()), PhyTopo::Peer::GetId(replacedLocalId))) {131+ if (!HasLayer0Peer2PeerLink(phyTopoGraph, peer, replacedLocalId)) {
96 continue;132 continue;
97 }133 }
98 backupLinkedPeers.emplace_back(peer);134 backupLinkedPeers.emplace_back(peer);
@@ -108,16 +144,7 @@ void UpdaterFor64Plus1::AddPeer2BackupLinks(
108 shared_ptr<NetInstance::Peer> peer, shared_ptr<NetInstance::Peer> backupPeer, LocalId replacedLocalId,144 shared_ptr<NetInstance::Peer> peer, shared_ptr<NetInstance::Peer> backupPeer, LocalId replacedLocalId,
109 NetInstance* netInstance, [[maybe_unused]] const RankTableInfo* rankTable) const145 NetInstance* netInstance, [[maybe_unused]] const RankTableInfo* rankTable) const
110{146{
111- auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph(0);147+ auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph();
112- 
113- std::unordered_map<u64, u64> fabricIds;
114- auto peer2AllPlaneEdges
115- = phyTopoGraph->GetEdges(PhyTopo::Peer::GetId(backupPeer->GetLocalId()), PhyTopo::Fabric::GetId());
116- for (auto edge : peer2AllPlaneEdges) {
117- auto topoInstId = edge->GetTopoInstId();
118- auto fabricId = static_cast<u64>(topoInstId) | (static_cast<u64>(1) << 32);
119- fabricIds[topoInstId] = fabricId;
120- }
121 148 
122 auto idx = GetLinkIndex(peer->GetLocalId(), replacedLocalId);149 auto idx = GetLinkIndex(peer->GetLocalId(), replacedLocalId);
123 auto backupPlaneId = idx.first;150 auto backupPlaneId = idx.first;
@@ -129,8 +156,10 @@ void UpdaterFor64Plus1::AddPeer2BackupLinks(
129 // 先获取phyTopoGraph中备份面和备份D的连接,因为只有一个fabric,所以会获取到全量16条备份面和备份D的连接156 // 先获取phyTopoGraph中备份面和备份D的连接,因为只有一个fabric,所以会获取到全量16条备份面和备份D的连接
130 // Edges中可能包含多个连接,但是在phytopo中保存为一条连接,内部有多个连接的端口157 // Edges中可能包含多个连接,但是在phytopo中保存为一条连接,内部有多个连接的端口
131 // 拿到物理边后,根据backupPlaneId匹配,选择对应的一条物理边158 // 拿到物理边后,根据backupPlaneId匹配,选择对应的一条物理边
132- std::shared_ptr<PhyTopo::Link> backD2PlaneEdges = GetPeer2PlaneEdges(backupPlaneId, backupPeer, phyTopoGraph);159+ std::shared_ptr<PhyTopo::Link> backD2PlaneEdges
133- std::shared_ptr<PhyTopo::Link> peer2PlaneEdges = GetPeer2PlaneEdges(backupPlaneId, peer, phyTopoGraph);160+ = GetPeer2PlaneEdges(backupPlaneId, backupPeer, phyTopoGraph, BACKUP_TO_PLANE_ADDR_NUM);
161+ std::shared_ptr<PhyTopo::Link> peer2PlaneEdges
162+ = GetPeer2PlaneEdges(backupPlaneId, peer, phyTopoGraph, 1, backD2PlaneEdges->GetLinkProtocols());
134 163 
135 // 取得端口列表,根据backupLinkIdx去选择对应的端口164 // 取得端口列表,根据backupLinkIdx去选择对应的端口
136 std::set<std::string> backD2PlanePorts = backD2PlaneEdges->GetSourceIFace()->GetPorts();165 std::set<std::string> backD2PlanePorts = backD2PlaneEdges->GetSourceIFace()->GetPorts();
@@ -151,10 +180,14 @@ void UpdaterFor64Plus1::AddPeer2BackupLinks(
151 std::string backD2PlanePort = GetPortFromSet(backD2PlanePorts, backupLinkIdx);180 std::string backD2PlanePort = GetPortFromSet(backD2PlanePorts, backupLinkIdx);
152 std::string peer2PlanePort = GetPortFromSet(peer2PlanePorts, 0);181 std::string peer2PlanePort = GetPortFromSet(peer2PlanePorts, 0);
153 182 
154- // 匹配了对应的端口后,去ranktableinfo中查对应端口的地址信息183+ // 最终选中的端口必须能在 RankTable layer 0 中找到地址。
155- // todo 加一下peer->GetPortAddrMapLayer0()是否能找到port对应的地址。184+ IpAddress backD2PlaneAddr;
156- IpAddress backD2PlaneAddr = backupPeer->GetPortAddrMapLayer0()[backD2PlanePort][0];185+ IpAddress peer2PlaneAddr;
157- IpAddress peer2PlaneAddr = peer->GetPortAddrMapLayer0()[peer2PlanePort][0];186+ if (backupPeer == nullptr || peer == nullptr || !backupPeer->TryGetLayer0Address(backD2PlanePort, backD2PlaneAddr)
187+ || !peer->TryGetLayer0Address(peer2PlanePort, peer2PlaneAddr)) {
188+ THROW<InvalidParamsException>(
189+ StringFormat("[UpdaterFor64Plus1][%s] selected port does not belong to layer0", __func__));
190+ }
158 191 
159 // 组装成NetInstance的conninterface,加入peer和backupPeer192 // 组装成NetInstance的conninterface,加入peer和backupPeer
160 if (backD2PlaneEdges->GetSourceIFace() == nullptr || peer2PlaneEdges->GetSourceIFace() == nullptr) {193 if (backD2PlaneEdges->GetSourceIFace() == nullptr || peer2PlaneEdges->GetSourceIFace() == nullptr) {
@@ -182,29 +215,44 @@ void UpdaterFor64Plus1::AddPeer2BackupLinks(
182 backupPeer, peer, backupIface, peerIface, LinkType::PEER2PEER, backD2PlaneEdges->GetLinkProtocols());215 backupPeer, peer, backupIface, peerIface, LinkType::PEER2PEER, backD2PlaneEdges->GetLinkProtocols());
183 netInstance->AddLink(backup2Peer);216 netInstance->AddLink(backup2Peer);
184 217 
185- // peer2peer建立后删除graph中DB到所选planeId的对应的peer2net链路218+ // 删除备份 D 到所有 Fabric 的链路;Fabric 由 planeId 生成,不能用 topoInstId 推导节点 ID。
186- // 直接删除备份d和fabric的链接保证GetLinks接口只能获取到peer2db的一条peer2peer219+ for (const auto& fabric : netInstance->GetFabrics()) {
187- // 删除peer到fabric用到的peer2net220+ if (fabric == nullptr) {
188- for (auto id : fabricIds) {221+ continue;
189- netInstance->DeleteLink(backupPeer->GetNodeId(), id.second);222+ }
223+ netInstance->DeleteLink(backupPeer->GetNodeId(), fabric->GetNodeId());
190 }224 }
191}225}
192 226 
193std::shared_ptr<PhyTopo::Link> UpdaterFor64Plus1::GetPeer2PlaneEdges(227std::shared_ptr<PhyTopo::Link> UpdaterFor64Plus1::GetPeer2PlaneEdges(
194 u32 backupPlaneId, shared_ptr<NetInstance::Peer> peer,228 u32 backupPlaneId, shared_ptr<NetInstance::Peer> peer,
195- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyTopoGraph) const229+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyTopoGraph, u32 expectedPortNum,
230+ const std::set<LinkProtocol>& expectedProtocols) const
196{231{
197 std::shared_ptr<PhyTopo::Link> peer2PlaneEdges = nullptr;232 std::shared_ptr<PhyTopo::Link> peer2PlaneEdges = nullptr;
198 auto peer2AllPlaneEdges233 auto peer2AllPlaneEdges
199 = phyTopoGraph->GetEdges(PhyTopo::Peer::GetId(peer->GetLocalId()), PhyTopo::Fabric::GetId());234 = phyTopoGraph->GetEdges(PhyTopo::Peer::GetId(peer->GetLocalId()), PhyTopo::Fabric::GetId());
200- if (peer2AllPlaneEdges.size() != BACKUP_PLANE_NUM) {235+ std::set<u32> backupPlaneIds;
201- THROW<InvalidParamsException>("[UpdaterFor64Plus1][%s] BackupPlane num error", __func__);236+ for (const auto& edge : peer2AllPlaneEdges) {
202- }237+ // 按物理属性统计合法备份面,避免 RankTable 仅提供部分备份端口时漏计。
203- for (auto& edges : peer2AllPlaneEdges) {238+ if (edge == nullptr || edge->GetType() != LinkType::PEER2NET || edge->GetSourceIFace() == nullptr
204- if (edges->GetTopoInstId() == backupPlaneId) {239+ || edge->GetSourceIFace()->GetPorts().size() != expectedPortNum
205- peer2PlaneEdges = edges;240+ || (!expectedProtocols.empty() && edge->GetLinkProtocols() != expectedProtocols)
206- break;241+ || edge->GetTopoInstId() >= BACKUP_PLANE_NUM) {
242+ continue;
207 }243 }
244+ backupPlaneIds.insert(edge->GetTopoInstId());
245+ // 真正选中的边必须命中 RankTable layer 0 端口。
246+ if (edge->GetTopoInstId() == backupPlaneId && HasLayer0Port(peer, edge->GetSourceIFace()->GetPorts())) {
247+ if (peer2PlaneEdges != nullptr) {
248+ THROW<InvalidParamsException>(
249+ "[UpdaterFor64Plus1][%s] BackupPlane[%u] is ambiguous", __func__, backupPlaneId);
250+ }
251+ peer2PlaneEdges = edge;
252+ }
253+ }
254+ if (backupPlaneIds.size() != BACKUP_PLANE_NUM) {
255+ THROW<InvalidParamsException>("[UpdaterFor64Plus1][%s] BackupPlane num error", __func__);
208 }256 }
209 if (peer2PlaneEdges == nullptr) {257 if (peer2PlaneEdges == nullptr) {
210 THROW<NullPtrException>(StringFormat("[UpdaterFor64Plus1][%s] peer2PlaneEdges is nullptr", __func__));258 THROW<NullPtrException>(StringFormat("[UpdaterFor64Plus1][%s] peer2PlaneEdges is nullptr", __func__));
@@ -14,6 +14,7 @@
14#include <string>14#include <string>
15#include <memory>15#include <memory>
16#include <unordered_map>16#include <unordered_map>
17+#include <set>
17#include "rank_table_info.h"18#include "rank_table_info.h"
18#include "rank_gph.h"19#include "rank_gph.h"
19#include "phy_topo.h"20#include "phy_topo.h"
@@ -41,7 +42,8 @@ private:
41 std::string GetPortFromSet(std::set<string>& ports, u32 linkIdx) const;42 std::string GetPortFromSet(std::set<string>& ports, u32 linkIdx) const;
42 std::shared_ptr<PhyTopo::Link> GetPeer2PlaneEdges(43 std::shared_ptr<PhyTopo::Link> GetPeer2PlaneEdges(
43 u32 backupPlaneId, shared_ptr<NetInstance::Peer> peer,44 u32 backupPlaneId, shared_ptr<NetInstance::Peer> peer,
44- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyTopoGraph) const;45+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> phyTopoGraph, u32 expectedPortNum,
46+ const std::set<LinkProtocol>& expectedProtocols = {}) const;
45 void AddPeer2BackupLinks(47 void AddPeer2BackupLinks(
46 std::shared_ptr<NetInstance::Peer> peer, std::shared_ptr<NetInstance::Peer> backupPeer, LocalId replacedLocalId,48 std::shared_ptr<NetInstance::Peer> peer, std::shared_ptr<NetInstance::Peer> backupPeer, LocalId replacedLocalId,
47 NetInstance* netInstance, const RankTableInfo* rankTable) const;49 NetInstance* netInstance, const RankTableInfo* rankTable) const;
@@ -42,13 +42,7 @@ const unordered_map<string, AddrPosition> EdgeInfo::strToAddrPosition
42 42 
43void EdgeInfo::Deserialize(const nlohmann::json& edgeInfoJson)43void EdgeInfo::Deserialize(const nlohmann::json& edgeInfoJson)
44{44{
45- std::string msgNetLayer = "[EdgeInfo::Deserialize] error occurs when parser object of propName \"net_layer\"";45+ // net_layer 不再解析,物理边只保留连接属性。
46- TRY_CATCH_THROW(InvalidParamsException, msgNetLayer, netLayer = GetJsonPropertyUInt(edgeInfoJson, "net_layer"););
47- if (netLayer > MAX_VALUE_LEVEL) {
48- THROW<InvalidParamsException>(StringFormat(
49- "[EdgeInfo::%s] netLayer value[%u] is out of range[0, %u].", __func__, netLayer, MAX_VALUE_LEVEL));
50- }
51- 
52 DeserializeProtocol(edgeInfoJson);46 DeserializeProtocol(edgeInfoJson);
53 47 
54 if (edgeInfoJson.contains("topo_type")) {48 if (edgeInfoJson.contains("topo_type")) {
@@ -174,9 +168,8 @@ void EdgeInfo::DeserializePort(const nlohmann::json& edgeInfoJson, std::string p
174 168 
175bool EdgeInfo::operator==(const EdgeInfo& other) const169bool EdgeInfo::operator==(const EdgeInfo& other) const
176{170{
177- return netLayer == other.netLayer && linkType == other.linkType && protocols == other.protocols171+ return linkType == other.linkType && protocols == other.protocols && topoType == other.topoType
178- && topoType == other.topoType && topoInstId == other.topoInstId && CompareEndpoints(other)172+ && topoInstId == other.topoInstId && CompareEndpoints(other) && position == other.position;
179- && position == other.position;
180}173}
181 174 
182// 比较EndpointA和B175// 比较EndpointA和B
@@ -255,7 +248,6 @@ std::string EdgeInfo::Describe() const
255 string localBPortsStr = DescribePorts(localBPorts);248 string localBPortsStr = DescribePorts(localBPorts);
256 249 
257 std::string description = "EdgeInfo{";250 std::string description = "EdgeInfo{";
258- description += StringFormat("netLayer=%u", netLayer);
259 description += StringFormat("topoType=%s", topoType.Describe().c_str());251 description += StringFormat("topoType=%s", topoType.Describe().c_str());
260 description += StringFormat(", topoInstanceId=%u", topoInstId);252 description += StringFormat(", topoInstanceId=%u", topoInstId);
261 description += StringFormat(", protocols=%s", protocolStr.str().c_str());253 description += StringFormat(", protocols=%s", protocolStr.str().c_str());
@@ -285,7 +277,8 @@ std::string EdgeInfo::DescribePorts(std::set<std::string> ports) const
285 277 
286void EdgeInfo::GetBinStream(BinaryStream& binaryStream) const278void EdgeInfo::GetBinStream(BinaryStream& binaryStream) const
287{279{
288- binaryStream << netLayer << static_cast<u32>(linkType) << static_cast<u32>(topoType) << topoInstId;280+ // 保留旧快照占位字段,不参与拓扑语义。
281+ binaryStream << LEGACY_BINARY_LAYER << static_cast<u32>(linkType) << static_cast<u32>(topoType) << topoInstId;
289 binaryStream << protocols.size();282 binaryStream << protocols.size();
290 for (LinkProtocol protocol : protocols) {283 for (LinkProtocol protocol : protocols) {
291 binaryStream << static_cast<u32>(protocol);284 binaryStream << static_cast<u32>(protocol);
@@ -308,7 +301,8 @@ void EdgeInfo::GetBinStream(BinaryStream& binaryStream) const
308 301 
309EdgeInfo::EdgeInfo(BinaryStream& binaryStream)302EdgeInfo::EdgeInfo(BinaryStream& binaryStream)
310{303{
311- binaryStream >> netLayer;304+ u32 ignoredBinaryLayer;
305+ binaryStream >> ignoredBinaryLayer;
312 u32 linkTypeTmp;306 u32 linkTypeTmp;
313 binaryStream >> linkTypeTmp;307 binaryStream >> linkTypeTmp;
314 linkType = static_cast<LinkType::Value>(linkTypeTmp);308 linkType = static_cast<LinkType::Value>(linkTypeTmp);
@@ -21,9 +21,9 @@
21 21 
22namespace Hccl {22namespace Hccl {
23 23 
24-constexpr unsigned int MAX_VALUE_LEVEL = 7;
25constexpr u32 PORT_MAX_LENGTH = 32;24constexpr u32 PORT_MAX_LENGTH = 32;
26constexpr u32 MAX_PORTS_SIZE = 64;25constexpr u32 MAX_PORTS_SIZE = 64;
26+constexpr u32 LEGACY_BINARY_LAYER = 0;
27 27 
28class EdgeInfo {28class EdgeInfo {
29public:29public:
@@ -31,7 +31,6 @@ public:
31 EdgeInfo(BinaryStream& binaryStream);31 EdgeInfo(BinaryStream& binaryStream);
32 ~EdgeInfo() {};32 ~EdgeInfo() {};
33 33 
34- u32 netLayer{0};
35 LinkType linkType;34 LinkType linkType;
36 TopoType topoType{TopoType::CLOS};35 TopoType topoType{TopoType::CLOS};
37 u32 topoInstId{0};36 u32 topoInstId{0};
@@ -49,6 +49,20 @@ void TopoInfo::Deserialize(const nlohmann::json& topoInfoJson)
49 49 
50 DeserializePeers(topoInfoJson);50 DeserializePeers(topoInfoJson);
51 DeserializeEdges(topoInfoJson);51 DeserializeEdges(topoInfoJson);
52+ 
53+ u32 peer2PeerEdgeCount = 0;
54+ u32 peer2NetEdgeCount = 0;
55+ for (const auto& edge : edges) {
56+ if (edge.linkType == LinkType::PEER2PEER) {
57+ ++peer2PeerEdgeCount;
58+ } else if (edge.linkType == LinkType::PEER2NET) {
59+ ++peer2NetEdgeCount;
60+ }
61+ }
62+ 
63+ HCCL_DEBUG(
64+ "[TopoInfo::%s] deserialize summary: peers[%zu], edges[%zu], PEER2PEER[%u], PEER2NET[%u]", __func__,
65+ peers.size(), edges.size(), peer2PeerEdgeCount, peer2NetEdgeCount);
52}66}
53 67 
54void TopoInfo::DeserializePeers(const nlohmann::json& topoInfoJson)68void TopoInfo::DeserializePeers(const nlohmann::json& topoInfoJson)
@@ -83,20 +97,17 @@ void TopoInfo::VerifyEdges(EdgeInfo& edge)
83 "[TopoInfo::%s] endpoint localId [%u] or [%u] is not exist in peers[%zu].", __func__, edge.localA,97 "[TopoInfo::%s] endpoint localId [%u] or [%u] is not exist in peers[%zu].", __func__, edge.localA,
84 edge.localB, idSet.size()));98 edge.localB, idSet.size()));
85 }99 }
86- // 检查edge.netLayer这一层级是否存在,不存在则初始化100+ // net_layer 不参与边语义;线性查重合并旧 topo 重复边,复杂度 O(E²)。
87- if (edges.find(edge.netLayer) == edges.end()) {101+ if (find(edges.begin(), edges.end(), edge) != edges.end()) {
严正行
严正行严正行8月7日

[LOW] VerifyEdges 线性查重 O(E²),大拓扑下性能退化

第 105 行 find(edges.begin(), edges.end(), edge) 在循环中对 std::vector<EdgeInfo> 做线性查找,整体复杂度 O(E²)。旧代码按 netLayer 分桶(std::map<u32, vector<EdgeInfo>>),每桶内边数较少;合并为单向量后全量边在同一桶中查重,退化因子等于旧分桶数。注释已标注 O(E²),典型规模下可接受,但拓扑边数增长时性能线性恶化。

建议修复: 若未来拓扑边数可能达数百级,可引入 std::unordered_set<EdgeInfo, EdgeInfoHash> 将查重降至 O(E) 均摊。当前规模下可保留 vector 但在注释中标注预期边数上限。

likedislike
88- edges[edge.netLayer] = vector<EdgeInfo>();102+ HCCL_DEBUG(
89- }103+ "[TopoInfo::%s] ignore duplicate physical edge, linkType[%s], topoType[%s], "
90- // 判断edge.netLayer该层级是否存在重复edge104+ "topoInstanceId[%u], localA[%u], localB[%u].",
91- if (find(edges[edge.netLayer].begin(), edges[edge.netLayer].end(), edge) != edges[edge.netLayer].end()) {105+ __func__, edge.linkType.Describe().c_str(), edge.topoType.Describe().c_str(), edge.topoInstId, edge.localA,
92- THROW<InvalidParamsException>(StringFormat(106+ edge.localB);
93- "[TopoInfo::%s] exist duplicate edges. Location information:{edge.netLayer=%u, edge.linkType=%s, "107+ return;
94- "edge.topoType=%s, edge.topoInstanceId=%u, localA=%u, localB=%u}",
95- __func__, edge.netLayer, edge.linkType.Describe().c_str(), edge.topoType.Describe().c_str(),
96- edge.topoInstId, edge.localA, edge.localB));
97 }108 }
atomgit-bot
atomgit-botatomgit-bot8月6日

🟡 Medium Priority

changed line:VerifyEdges 中第 105-111 行,旧代码遇到重复边会 THROW<InvalidParamsException> 强制终止,新代码改为 HCCL_DEBUG 日志后直接 return 静默丢弃。

affected behavior/contract:旧 topo.json 在同一 netLayer 内出现重复边会被立即检测并报错退出;新代码对任意重复边(跨层或同层)均静默忽略,不再报错。

failure mode:如果 topo.json 因生成工具 BUG 或人工编辑错误包含了不应存在的重复边(例如端口集合不同但其他字段相同的"假重复"),这些边会被静默丢弃,导致物理拓扑图中缺失合法边,进而可能造成 RankGraph 构建不完整、集合通信链路缺失或性能下降,且排查困难。

suggested fix:保留重复边合并的语义,但应当通过 HCCL_WARNING 级别日志(而非 DEBUG)输出被合并的边信息,或在首次遇到重复时至少记录 WARNING,确保运维可观测。如果确定重复边是合法场景,也可考虑增加 HCCL_INFO 汇总合并数量。

建议:将 HCCL_DEBUG 提升为 HCCL_WARNING 或 HCCL_INFO,确保运维可感知边被合并。可考虑在 DeserializeEdges 末尾汇总合并数量并记录 WARNING。

likedislike
不准确?
98 109 
99- edges[edge.netLayer].emplace_back(edge);110+ edges.emplace_back(edge);
100}111}
101 112 
102void TopoInfo::DeserializeEdges(const nlohmann::json& topoInfoJson)113void TopoInfo::DeserializeEdges(const nlohmann::json& topoInfoJson)
@@ -114,21 +125,19 @@ void TopoInfo::DeserializeEdges(const nlohmann::json& topoInfoJson)
114 return;125 return;
115 }126 }
116 }127 }
128+ if (edgeJsons.size() != edgeCount) {
129+ 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+ }
117 for (auto& edgeJson : edgeJsons) {133 for (auto& edgeJson : edgeJsons) {
118 EdgeInfo edge;134 EdgeInfo edge;
119 edge.Deserialize(edgeJson);135 edge.Deserialize(edgeJson);
120 VerifyEdges(edge);136 VerifyEdges(edge);
121 }137 }
122 138 
123- size_t sumEdge = 0;139+ // edgeCount 对外表示去重后的物理边数量。
124- for (const auto& entry : edges) {140+ edgeCount = static_cast<u32>(edges.size());
125- sumEdge += entry.second.size();
126- }
127- if (sumEdge != edgeCount) {
128- THROW<InvalidParamsException>(StringFormat(
129- "[TopoInfo::%s] Value of edge_count[%u] is inconsistent with the size of edge_list[%zu].", __func__,
130- edgeCount, sumEdge));
131- }
132}141}
133 142 
134string TopoInfo::Describe() const143string TopoInfo::Describe() const
@@ -152,11 +161,8 @@ void TopoInfo::Dump() const
152 HCCL_DEBUG("%s", peer.Describe().c_str());161 HCCL_DEBUG("%s", peer.Describe().c_str());
153 }162 }
154 HCCL_DEBUG("edges:");163 HCCL_DEBUG("edges:");
155- for (const auto& itor : edges) {164+ for (const auto& edge : edges) {
156- HCCL_DEBUG("netLayer[%u]:", itor.first);165+ HCCL_DEBUG(" %s", edge.Describe().c_str());
157- for (const auto& edge : itor.second) {
158- HCCL_DEBUG(" %s", edge.Describe().c_str());
159- }
160 }166 }
161}167}
162 168 
@@ -169,23 +175,27 @@ TopoInfo::TopoInfo(BinaryStream& binaryStream)
169 PeerInfo peer(binaryStream);175 PeerInfo peer(binaryStream);
170 peers.emplace_back(peer);176 peers.emplace_back(peer);
171 }177 }
172- size_t edgesSize = 0;178+ size_t edgeGroupCount = 0;
173- binaryStream >> edgesSize;179+ binaryStream >> edgeGroupCount;
174 180 
175 HCCL_INFO(181 HCCL_INFO(
176- "[TopoInfo] version is [%s], peerCount is [%u], edgeCount is [%u], peers size is [%u], edges size is [%u]",182+ "[TopoInfo] version is [%s], peerCount is [%u], edgeCount is [%u], peers size is [%zu], "
177- version.c_str(), peerCount, edgeCount, peers.size(), edgesSize);183+ "edge group count is [%zu]",
178- for (u32 i = 0; i < edgesSize; i++) {184+ version.c_str(), peerCount, edgeCount, peers.size(), edgeGroupCount);
179- u32 edgeInfoIndex = 0;185+ // 保留旧快照分组外壳,读取后统一展开物理边。
180- binaryStream >> edgeInfoIndex; // key186+ for (size_t i = 0; i < edgeGroupCount; i++) {
181- size_t edgeSize = 0;187+ u32 ignoredBinaryLayer = 0;
182- binaryStream >> edgeSize;188+ size_t groupEdgeCount = 0;
183- HCCL_INFO("[TopoInfo] edges key is [%u], value size is [%u]", edgeInfoIndex, edgeSize);189+ binaryStream >> ignoredBinaryLayer >> groupEdgeCount;
184- for (u32 j = 0; j < edgeSize; j++) { // value190+ for (size_t j = 0; j < groupEdgeCount; j++) {
185 EdgeInfo edge(binaryStream);191 EdgeInfo edge(binaryStream);
186- edges[edgeInfoIndex].emplace_back(edge);192+ // 旧快照可能按 layer 重复存储同一物理边,展开时合并。
193+ if (find(edges.begin(), edges.end(), edge) == edges.end()) {
194+ edges.emplace_back(edge);
195+ }
187 }196 }
188 }197 }
198+ edgeCount = static_cast<u32>(edges.size());
189}199}
190 200 
191void TopoInfo::GetBinStream(BinaryStream& binaryStream) const201void TopoInfo::GetBinStream(BinaryStream& binaryStream) const
@@ -195,16 +205,16 @@ void TopoInfo::GetBinStream(BinaryStream& binaryStream) const
195 for (auto& it : peers) {205 for (auto& it : peers) {
196 it.GetBinStream(binaryStream);206 it.GetBinStream(binaryStream);
197 }207 }
198- binaryStream << edges.size();208+ const size_t edgeGroupCount = edges.empty() ? 0 : 1;
209+ binaryStream << edgeGroupCount;
199 HCCL_INFO(210 HCCL_INFO(
200- "[TopoInfo::GetBinStream] version is [%s], peerCount is [%u], edgeCount is [%u], peers size is [%u], edges "211+ "[TopoInfo::GetBinStream] version is [%s], peerCount is [%u], edgeCount is [%u], peers size is [%zu], "
201- "size is [%u]",212+ "edges size is [%zu]",
202 version.c_str(), peerCount, edgeCount, peers.size(), edges.size());213 version.c_str(), peerCount, edgeCount, peers.size(), edges.size());
203- for (auto& it : edges) {214+ // 新快照统一写入一个兼容分组,不恢复逻辑分层。
204- binaryStream << it.first;215+ if (!edges.empty()) {
205- binaryStream << it.second.size();216+ binaryStream << LEGACY_BINARY_LAYER << edges.size();
206- HCCL_INFO("[TopoInfo::GetBinStream] edges key is [%u], value size is [%u]", it.first, it.second.size());217+ for (const auto& edge : edges) {
207- for (auto& edge : it.second) {
208 edge.GetBinStream(binaryStream);218 edge.GetBinStream(binaryStream);
209 }219 }
210 }220 }
@@ -11,7 +11,6 @@
11#ifndef NEW_TOPO_INFO_H11#ifndef NEW_TOPO_INFO_H
12#define NEW_TOPO_INFO_H12#define NEW_TOPO_INFO_H
13 13 
14-#include <map>
15#include <vector>14#include <vector>
16#include <unordered_set>15#include <unordered_set>
17 16 
@@ -28,7 +27,7 @@ public:
28 u32 peerCount{0};27 u32 peerCount{0};
29 u32 edgeCount{0};28 u32 edgeCount{0};
30 std::vector<PeerInfo> peers;29 std::vector<PeerInfo> peers;
31- std::map<u32, std::vector<EdgeInfo>> edges;30+ std::vector<EdgeInfo> edges;
32 void Deserialize(const nlohmann::json& topoInfoJson);31 void Deserialize(const nlohmann::json& topoInfoJson);
33 std::string Describe() const;32 std::string Describe() const;
34 void Dump() const;33 void Dump() const;
@@ -8,6 +8,7 @@
8 * See LICENSE in the root of the software repository for the full text of the License.8 * See LICENSE in the root of the software repository for the full text of the License.
9 */9 */
10 10 
11+#include <algorithm>
11#include <thread>12#include <thread>
12#include <cstdlib>13#include <cstdlib>
13#include <fstream>14#include <fstream>
@@ -145,6 +146,25 @@ namespace {
145 CheckTopoFilePath(topoFilePath);146 CheckTopoFilePath(topoFilePath);
146 return topoFilePath;147 return topoFilePath;
147 }148 }
149+ 
150+ bool IsHostRdmaLink(const std::shared_ptr<PhyTopo::Link>& link)
151+ {
152+ if (link == nullptr || link->GetSourceIFace() == nullptr
153+ || link->GetSourceIFace()->GetPos() != AddrPosition::HOST) {
154+ return false;
155+ }
156+ const std::set<LinkProtocol>& protocols = link->GetLinkProtocols();
157+ return std::any_of(protocols.begin(), protocols.end(), [](const LinkProtocol& protocol) {
158+ return LinkProtocol2LinkProtoType(protocol) == LinkProtoType::RDMA;
159+ });
160+ }
161+ 
162+ bool HasMatchingPort(const AddressInfo& addrInfo, const std::set<std::string>& phyPorts)
163+ {
164+ return std::any_of(addrInfo.ports.begin(), addrInfo.ports.end(), [&phyPorts](const std::string& port) {
165+ return phyPorts.count(port) != 0;
166+ });
167+ }
148} // namespace168} // namespace
149 169 
150void RankInfoDetectClient::Setup(RankTableInfo& rankTable)170void RankInfoDetectClient::Setup(RankTableInfo& rankTable)
@@ -721,30 +741,33 @@ void RankInfoDetectClient::HostListenPortDetect(NewRankInfo& rankInfo)
721 auto devLogicId = HrtGetDevice();741 auto devLogicId = HrtGetDevice();
722 u32 devPhyId = rankInfo.deviceId;742 u32 devPhyId = rankInfo.deviceId;
723 for (auto& rankLevelInfo : rankInfo.rankLevelInfos) {743 for (auto& rankLevelInfo : rankInfo.rankLevelInfos) {
724- shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> graph744+ // 物理图不区分逻辑层,按 RankTable 端口匹配当前层。
725- = PhyTopo::GetInstance()->GetTopoGraph(rankLevelInfo.netLayer);745+ auto graph = PhyTopo::GetInstance()->GetTopoGraph();
726 if (graph == nullptr) {746 if (graph == nullptr) {
727- HCCL_DEBUG("[RankInfoDetectClient::%s]Can't find the layout %u Graph!", __func__, rankLevelInfo.netLayer);747+ HCCL_DEBUG("[RankInfoDetectClient::%s] Physical topo graph is nullptr.", __func__);
728 continue;748 continue;
729 }749 }
730 std::vector<std::shared_ptr<PhyTopo::Link>> links = graph->GetEdges(rankInfo.localId);750 std::vector<std::shared_ptr<PhyTopo::Link>> links = graph->GetEdges(rankInfo.localId);
731 for (auto& link : links) {751 for (auto& link : links) {
732- if (link->GetSourceIFace()->GetPos() != AddrPosition::HOST) {752+ if (!IsHostRdmaLink(link)) {
733 continue;753 continue;
734 }754 }
735- const std::set<LinkProtocol>& protocols = link->GetLinkProtocols();755+ const auto& phyPorts = link->GetSourceIFace()->GetPorts();
736- for (auto& protocol : protocols) {756+ // 使用物理 Host RDMA 端口对应的地址,不默认取首个地址。
737- LinkProtoType protoType = LinkProtocol2LinkProtoType(protocol);757+ auto addrIt = std::find_if(
738- if (protoType != LinkProtoType::RDMA || rankLevelInfo.rankAddrs.empty()) {758+ rankLevelInfo.rankAddrs.begin(), rankLevelInfo.rankAddrs.end(),
739- continue;759+ [&phyPorts](const AddressInfo& addrInfo) {
740- }760+ return HasMatchingPort(addrInfo, phyPorts);
741- HCCL_DEBUG("[SocketManager::%s] find the host rdma link %s", __func__, link->Describe().c_str());761+ });
742- const IpAddress& hostIp = rankLevelInfo.rankAddrs[0].addr;762+ if (addrIt == rankLevelInfo.rankAddrs.end()) {
743- uint32_t hostPort = 0;763+ continue;
744- SetupHostListenPort(devLogicId, devPhyId, hostIp, hostPort);
745- rankInfo.hostPort = hostPort;
746- return;
747 }764 }
765+ HCCL_DEBUG("[SocketManager::%s] find the host rdma link %s", __func__, link->Describe().c_str());
766+ const IpAddress& hostIp = addrIt->addr;
767+ uint32_t hostPort = 0;
768+ SetupHostListenPort(devLogicId, devPhyId, hostIp, hostPort);
769+ rankInfo.hostPort = hostPort;
770+ return;
748 }771 }
749 }772 }
750}773}
@@ -3820,7 +3820,7 @@ HcclResult CommunicatorImpl::GetInstSizeListByNetLayer(uint32_t netLayer, uint32
3820 }3820 }
3821}3821}
3822 3822 
3823-static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<CommLink>& linkListVec)3823+static HcclResult InsertInnerLink(u32 netLayer, const NetInstance::Path& path, std::vector<CommLink>& linkListVec)
3824{3824{
3825 for (const auto& link : path.links) {3825 for (const auto& link : path.links) {
3826 const NetInstance::Link* peer2peer = &link;3826 const NetInstance::Link* peer2peer = &link;
@@ -3839,6 +3839,7 @@ static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<Com
3839 HcclResult result = GetCommAddr(commLink.srcEndpointDesc.commAddr, srcConnInterface->GetAddr());3839 HcclResult result = GetCommAddr(commLink.srcEndpointDesc.commAddr, srcConnInterface->GetAddr());
3840 if (result != HCCL_SUCCESS)3840 if (result != HCCL_SUCCESS)
3841 return result;3841 return result;
3842+ CHK_RET(SetEndpointTopoInfo(commLink.srcEndpointDesc, netLayer, srcConnInterface->GetTopoInstId()));
3842 3843 
3843 // 设置目标端点3844 // 设置目标端点
3844 std::shared_ptr<NetInstance::ConnInterface> dstConnInterface = link.GetTargetIface();3845 std::shared_ptr<NetInstance::ConnInterface> dstConnInterface = link.GetTargetIface();
@@ -3846,6 +3847,7 @@ static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<Com
3846 result = GetCommAddr(commLink.dstEndpointDesc.commAddr, dstConnInterface->GetAddr());3847 result = GetCommAddr(commLink.dstEndpointDesc.commAddr, dstConnInterface->GetAddr());
3847 if (result != HCCL_SUCCESS)3848 if (result != HCCL_SUCCESS)
3848 return result;3849 return result;
3850+ CHK_RET(SetEndpointTopoInfo(commLink.dstEndpointDesc, netLayer, dstConnInterface->GetTopoInstId()));
3849 3851 
3850 linkListVec.emplace_back(std::move(commLink));3852 linkListVec.emplace_back(std::move(commLink));
3851 }3853 }
@@ -3854,7 +3856,7 @@ static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<Com
3854 return HCCL_SUCCESS;3856 return HCCL_SUCCESS;
3855}3857}
3856 3858 
3857-static HcclResult InsertClosLinks(const NetInstance::Path& path, std::vector<CommLink>& linkListVec)3859+static HcclResult InsertClosLinks(u32 netLayer, const NetInstance::Path& path, std::vector<CommLink>& linkListVec)
3858{3860{
3859 const NetInstance::Link* peer2net = nullptr;3861 const NetInstance::Link* peer2net = nullptr;
3860 const NetInstance::Link* net2peer = nullptr;3862 const NetInstance::Link* net2peer = nullptr;
@@ -3886,10 +3888,12 @@ static HcclResult InsertClosLinks(const NetInstance::Path& path, std::vector<Com
3886 HcclResult result = GetCommAddr(commLink.srcEndpointDesc.commAddr, srcInterface->GetAddr());3888 HcclResult result = GetCommAddr(commLink.srcEndpointDesc.commAddr, srcInterface->GetAddr());
3887 if (result != HCCL_SUCCESS)3889 if (result != HCCL_SUCCESS)
3888 return result;3890 return result;
3891+ CHK_RET(SetEndpointTopoInfo(commLink.srcEndpointDesc, netLayer, srcInterface->GetTopoInstId()));
3889 // 设置目标端点3892 // 设置目标端点
3890 result = GetCommAddr(commLink.dstEndpointDesc.commAddr, dstInterface->GetAddr());3893 result = GetCommAddr(commLink.dstEndpointDesc.commAddr, dstInterface->GetAddr());
3891 if (result != HCCL_SUCCESS)3894 if (result != HCCL_SUCCESS)
3892 return result;3895 return result;
3896+ CHK_RET(SetEndpointTopoInfo(commLink.dstEndpointDesc, netLayer, dstInterface->GetTopoInstId()));
3893 linkListVec.emplace_back(std::move(commLink));3897 linkListVec.emplace_back(std::move(commLink));
3894 }3898 }
3895 return HCCL_SUCCESS;3899 return HCCL_SUCCESS;
@@ -3915,12 +3919,12 @@ HcclResult CommunicatorImpl::GetLinks(
3915 }3919 }
3916 if (!isClos) {3920 if (!isClos) {
3917 // Peer2Peer网络:直接处理每条link3921 // Peer2Peer网络:直接处理每条link
3918- HcclResult ret = InsertInnerLink(path, linkListVec);3922+ HcclResult ret = InsertInnerLink(netLayer, path, linkListVec);
3919 if (ret != HCCL_SUCCESS)3923 if (ret != HCCL_SUCCESS)
3920 return ret;3924 return ret;
3921 } else {3925 } else {
3922 // Clos网络:找到peer2net和net2peer,组合成一条链路3926 // Clos网络:找到peer2net和net2peer,组合成一条链路
3923- HcclResult ret = InsertClosLinks(path, linkListVec);3927+ HcclResult ret = InsertClosLinks(netLayer, path, linkListVec);
3924 if (ret != HCCL_SUCCESS)3928 if (ret != HCCL_SUCCESS)
3925 return ret;3929 return ret;
3926 }3930 }
@@ -258,10 +258,10 @@ void SocketManager::ServerInitAll(NewRankInfo& rankInfo)
258 u32 localId = rankInfo.localId;258 u32 localId = rankInfo.localId;
259 u32 devicePhyId = rankInfo.deviceId;259 u32 devicePhyId = rankInfo.deviceId;
260 for (auto& rankLevelInfo : rankInfo.rankLevelInfos) {260 for (auto& rankLevelInfo : rankInfo.rankLevelInfos) {
261- shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> graph261+ // 物理图不区分逻辑层,按 RankTable 端口筛选当前层链路。
262- = PhyTopo::GetInstance()->GetTopoGraph(rankLevelInfo.netLayer);262+ auto graph = PhyTopo::GetInstance()->GetTopoGraph();
263 if (graph == nullptr) {263 if (graph == nullptr) {
264- HCCL_DEBUG("[SocketManager::%s]Can't find the layout %u Graph!", __func__, rankLevelInfo.netLayer);264+ HCCL_DEBUG("[SocketManager::%s] Physical topo graph is nullptr.", __func__);
265 continue;265 continue;
266 }266 }
267 std::vector<std::shared_ptr<PhyTopo::Link>> links = graph->GetEdges(localId);267 std::vector<std::shared_ptr<PhyTopo::Link>> links = graph->GetEdges(localId);
@@ -276,7 +276,7 @@ void SocketManager::ServerInitAll(NewRankInfo& rankInfo)
276 LinkProtoType protoType = LinkProtocol2LinkProtoType(protocol);276 LinkProtoType protoType = LinkProtocol2LinkProtoType(protocol);
277 const std::set<std::string>& ports = link->GetSourceIFace()->GetPorts();277 const std::set<std::string>& ports = link->GetSourceIFace()->GetPorts();
278 for (auto& rankAddr : rankLevelInfo.rankAddrs) {278 for (auto& rankAddr : rankLevelInfo.rankAddrs) {
279- // topo查得网口使用则打开建链279+ // 仅为当前 RankTable 层命中的物理端口创建监听。
280 std::set<std::string> intersectSet;280 std::set<std::string> intersectSet;
281 std::set_intersection(281 std::set_intersection(
282 ports.begin(), ports.end(), rankAddr.ports.begin(), rankAddr.ports.end(),282 ports.begin(), ports.end(), rankAddr.ports.begin(), rankAddr.ports.end(),
@@ -13,7 +13,6 @@
13 13 
14#include <vector>14#include <vector>
15#include <set>15#include <set>
16-#include <unordered_map>
17#include <memory>16#include <memory>
18#include "topo_common_types.h"17#include "topo_common_types.h"
19#include "iterator.h"18#include "iterator.h"
@@ -116,16 +115,15 @@ public:
116 u32 hop{1};115 u32 hop{1};
117 };116 };
118 117 
119- void AddTopoGraph(const u32 netLayer, std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo);118+ void AddTopoGraph(std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo);
120- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> GetTopoGraph(const u32 netLayer) const;119+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> GetTopoGraph() const;
121 void InitFinish();120 void InitFinish();
122 bool IsInitFinished() const;121 bool IsInitFinished() const;
123 void Clear();122 void Clear();
124 void Dump() const;123 void Dump() const;
125- bool IsNetLayerExisted(const u32 netLayer) const;
126 124 
127private:125private:
128- std::unordered_map<u32, std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>>> topos;126+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo_{nullptr};
129 bool initFlag{false};127 bool initFlag{false};
130};128};
131} // namespace Hccl129} // namespace Hccl
@@ -44,6 +44,7 @@ public:
44private:44private:
45 std::shared_ptr<TopoInfo> LoadTopoInfo(const std::string& topoPath);45 std::shared_ptr<TopoInfo> LoadTopoInfo(const std::string& topoPath);
46 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> CreateGraph(const std::vector<EdgeInfo>& edges) const;46 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> CreateGraph(const std::vector<EdgeInfo>& edges) const;
47+ void BuildPhyTopo(const TopoInfo& topoInfo) const;
47 std::shared_ptr<TopoInfo> topoInfo_;48 std::shared_ptr<TopoInfo> topoInfo_;
48 std::mutex phyTopoMutex;49 std::mutex phyTopoMutex;
49};50};
@@ -23,10 +23,72 @@
23#include "ip_address.h"23#include "ip_address.h"
24#include "iterator.h"24#include "iterator.h"
25#include "types.h"25#include "types.h"
26+#include "securec.h"
26#include "topo_common_types.h"27#include "topo_common_types.h"
27 28 
28namespace Hccl {29namespace Hccl {
29constexpr u32 DEFAULT_LISTENING_PORT = 60001;30constexpr u32 DEFAULT_LISTENING_PORT = 60001;
31+// HCCL构建ChannelDesc时会完整复制EndpointLoc,使用其未占用的尾部字节传递拓扑定位信息。
32+struct EndpointTopoInfo {
33+ u32 magic;
34+ u32 netLayer;
35+ u32 topoInstId;
36+};
37+ 
38+constexpr u32 ENDPOINT_TOPO_INFO_MAGIC = 0x544F504FU;
39+constexpr size_t ENDPOINT_LOC_RAW_SIZE = sizeof(((EndpointLoc*)nullptr)->raws);
40+static_assert(ENDPOINT_LOC_RAW_SIZE >= sizeof(EndpointTopoInfo), "EndpointLoc reserved space is insufficient");
41+static_assert(
42+ ENDPOINT_LOC_RAW_SIZE - sizeof(EndpointTopoInfo) >= sizeof(((EndpointLoc*)nullptr)->device),
43+ "Endpoint topology info overlaps device location fields");
44+constexpr size_t ENDPOINT_TOPO_INFO_OFFSET = ENDPOINT_LOC_RAW_SIZE - sizeof(EndpointTopoInfo);
45+ 
46+inline HcclResult SetEndpointTopoInfo(EndpointDesc& endpointDesc, u32 netLayer, u32 topoInstId)
47+{
48+ const EndpointTopoInfo topoInfo{ENDPOINT_TOPO_INFO_MAGIC, netLayer, topoInstId};
49+ const errno_t ret
50+ = memcpy_s(endpointDesc.loc.raws + ENDPOINT_TOPO_INFO_OFFSET, sizeof(topoInfo), &topoInfo, sizeof(topoInfo));
51+ return ret == EOK ? HCCL_SUCCESS : HCCL_E_MEMORY;
52+}
53+ 
54+inline bool GetEndpointTopoInfo(const EndpointDesc& endpointDesc, u32& netLayer, u32& topoInstId)
55+{
56+ EndpointTopoInfo topoInfo{};
57+ const errno_t ret
58+ = memcpy_s(&topoInfo, sizeof(topoInfo), endpointDesc.loc.raws + ENDPOINT_TOPO_INFO_OFFSET, sizeof(topoInfo));
59+ if (ret != EOK) {
60+ return false;
61+ }
62+ if (topoInfo.magic != ENDPOINT_TOPO_INFO_MAGIC) {
63+ return false;
64+ }
65+ 
66+ netLayer = topoInfo.netLayer;
67+ topoInstId = topoInfo.topoInstId;
68+ return true;
69+}
70+ 
71+// 同一地址和协议可属于不同网络层或拓扑实例,需共同参与Endpoint定位。
72+struct EndpointKey {
73+ u32 netLayer;
74+ u32 topoInstId;
75+ CommAddr commAddr;
76+ CommProtocol protocol;
77+ 
78+ bool operator==(const EndpointKey& other) const
79+ {
80+ return netLayer == other.netLayer && topoInstId == other.topoInstId && commAddr == other.commAddr
81+ && protocol == other.protocol;
82+ }
83+};
84+ 
85+struct EndpointKeyHash {
86+ size_t operator()(const EndpointKey& key) const
87+ {
88+ return std::hash<u32>()(key.netLayer) ^ (std::hash<u32>()(key.topoInstId) << 1)
89+ ^ (std::hash<CommAddr>()(key.commAddr) << 2) ^ (std::hash<CommProtocol>()(key.protocol) << 3);
90+ }
91+};
30class NetInstance {92class NetInstance {
31public:93public:
32 class ConnInterface {94 class ConnInterface {
@@ -70,6 +132,9 @@ public:
70 132 
71 class Node {133 class Node {
72 public:134 public:
135+ using EndpointToIfaceMap
136+ = std::unordered_map<EndpointKey, std::shared_ptr<NetInstance::ConnInterface>, EndpointKeyHash>;
137+ 
73 MAKE_ENUM(NodeType, PEER, FABRIC)138 MAKE_ENUM(NodeType, PEER, FABRIC)
74 explicit Node(NodeType nodeType) : type_(nodeType) {}139 explicit Node(NodeType nodeType) : type_(nodeType) {}
75 virtual ~Node() = default;140 virtual ~Node() = default;
@@ -80,9 +145,9 @@ public:
80 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfacesByLayer(u32 layer) const;145 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfacesByLayer(u32 layer) const;
81 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfaces() const;146 std::vector<std::shared_ptr<NetInstance::ConnInterface>> GetIfaces() const;
82 void SetEndpointToIface(147 void SetEndpointToIface(
83- const CommAddr& commAddr, CommProtocol protocol, const std::shared_ptr<NetInstance::ConnInterface>& iface);148+ u32 netLayer, u32 topoInstId, const CommAddr& commAddr, CommProtocol protocol,
84- const std::unordered_map<std::pair<CommAddr, CommProtocol>, std::shared_ptr<NetInstance::ConnInterface>>149+ const std::shared_ptr<NetInstance::ConnInterface>& iface);
85- GetEndpointToIfaceMap() const;150+ const EndpointToIfaceMap& GetEndpointToIfaceMap() const;
86 NodeId GetNodeId() const;151 NodeId GetNodeId() const;
87 string GetNodeIdStr() const;152 string GetNodeIdStr() const;
88 const std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>>153 const std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>>
@@ -94,8 +159,7 @@ public:
94 159 
95 private:160 private:
96 std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>> interfacesMap_;161 std::unordered_map<u32, std::vector<std::shared_ptr<NetInstance::ConnInterface>>> interfacesMap_;
97- std::unordered_map<std::pair<CommAddr, CommProtocol>, std::shared_ptr<NetInstance::ConnInterface>>162+ EndpointToIfaceMap endpointToIfaceMap_;
98- endpointToIfaceMap_;
99 NodeType type_;163 NodeType type_;
100 };164 };
101 165 
@@ -126,6 +190,7 @@ public:
126 std::set<u32> GetLevels() const;190 std::set<u32> GetLevels() const;
127 NetInstancePtr GetNetInstance(u32 level) const;191 NetInstancePtr GetNetInstance(u32 level) const;
128 std::map<std::string, std::vector<IpAddress>> GetPortAddrMapLayer0() const;192 std::map<std::string, std::vector<IpAddress>> GetPortAddrMapLayer0() const;
193+ bool TryGetLayer0Address(const std::string& port, IpAddress& addr) const;
129 void SetPortPortAddrMapLayer0(std::map<std::string, std::vector<IpAddress>> portAddrMap);194 void SetPortPortAddrMapLayer0(std::map<std::string, std::vector<IpAddress>> portAddrMap);
130 std::string Describe() const override;195 std::string Describe() const override;
131 196 
@@ -21,9 +21,9 @@
21 21 
22namespace Hccl {22namespace Hccl {
23 23 
24-constexpr unsigned int MAX_VALUE_LEVEL = 7;
25constexpr u32 PORT_MAX_LENGTH = 32;24constexpr u32 PORT_MAX_LENGTH = 32;
26constexpr u32 MAX_PORTS_SIZE = 64;25constexpr u32 MAX_PORTS_SIZE = 64;
26+constexpr u32 LEGACY_BINARY_LAYER = 0;
27 27 
28class EdgeInfo {28class EdgeInfo {
29public:29public:
@@ -31,7 +31,6 @@ public:
31 EdgeInfo(BinaryStream& binaryStream);31 EdgeInfo(BinaryStream& binaryStream);
32 ~EdgeInfo() {};32 ~EdgeInfo() {};
33 33 
34- u32 netLayer{0};
35 LinkType linkType;34 LinkType linkType;
36 TopoType topoType{TopoType::CLOS};35 TopoType topoType{TopoType::CLOS};
37 u32 topoInstId{0};36 u32 topoInstId{0};
@@ -11,7 +11,6 @@
11#ifndef NEW_TOPO_INFO_H11#ifndef NEW_TOPO_INFO_H
12#define NEW_TOPO_INFO_H12#define NEW_TOPO_INFO_H
13 13 
14-#include <map>
15#include <vector>14#include <vector>
16#include <unordered_set>15#include <unordered_set>
17 16 
@@ -28,7 +27,7 @@ public:
28 u32 peerCount{0};27 u32 peerCount{0};
29 u32 edgeCount{0};28 u32 edgeCount{0};
30 std::vector<PeerInfo> peers;29 std::vector<PeerInfo> peers;
31- std::map<u32, std::vector<EdgeInfo>> edges;30+ std::vector<EdgeInfo> edges;
32 void Deserialize(const nlohmann::json& topoInfoJson);31 void Deserialize(const nlohmann::json& topoInfoJson);
33 std::string Describe() const;32 std::string Describe() const;
34 void Dump() const;33 void Dump() const;
@@ -210,7 +210,7 @@ static HcclResult SetEndpointLoc(EndpointLocType& locType, const AddrPosition& p
210 return HCCL_SUCCESS;210 return HCCL_SUCCESS;
211}211}
212 212 
213-static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<CommLink>& linkListVec)213+static HcclResult InsertInnerLink(u32 netLayer, const NetInstance::Path& path, std::vector<CommLink>& linkListVec)
214{214{
215 for (const auto& link : path.links) {215 for (const auto& link : path.links) {
216 const NetInstance::Link* peer2peer = &link;216 const NetInstance::Link* peer2peer = &link;
@@ -234,6 +234,7 @@ static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<Com
234 return result;234 return result;
235 }235 }
236 CHK_RET(SetEndpointLoc(commLink.srcEndpointDesc.loc.locType, srcConnInterface->GetPos()));236 CHK_RET(SetEndpointLoc(commLink.srcEndpointDesc.loc.locType, srcConnInterface->GetPos()));
237+ CHK_RET(SetEndpointTopoInfo(commLink.srcEndpointDesc, netLayer, srcConnInterface->GetTopoInstId()));
237 238 
238 // 设置目标端点239 // 设置目标端点
239 std::shared_ptr<NetInstance::ConnInterface> dstConnInterface = link.GetTargetIface();240 std::shared_ptr<NetInstance::ConnInterface> dstConnInterface = link.GetTargetIface();
@@ -247,6 +248,7 @@ static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<Com
247 }248 }
248 249 
249 CHK_RET(SetEndpointLoc(commLink.dstEndpointDesc.loc.locType, dstConnInterface->GetPos()));250 CHK_RET(SetEndpointLoc(commLink.dstEndpointDesc.loc.locType, dstConnInterface->GetPos()));
251+ CHK_RET(SetEndpointTopoInfo(commLink.dstEndpointDesc, netLayer, dstConnInterface->GetTopoInstId()));
250 252 
251 if (commLink.srcEndpointDesc.loc.locType == ENDPOINT_LOC_TYPE_DEVICE) {253 if (commLink.srcEndpointDesc.loc.locType == ENDPOINT_LOC_TYPE_DEVICE) {
252 std::shared_ptr<NetInstance::Node> srcNode = peer2peer->GetSourceNode();254 std::shared_ptr<NetInstance::Node> srcNode = peer2peer->GetSourceNode();
@@ -264,7 +266,7 @@ static HcclResult InsertInnerLink(const NetInstance::Path& path, std::vector<Com
264 return HCCL_SUCCESS;266 return HCCL_SUCCESS;
265}267}
266 268 
267-static HcclResult InsertClosLinks(const NetInstance::Path& path, std::vector<CommLink>& linkListVec)269+static HcclResult InsertClosLinks(u32 netLayer, const NetInstance::Path& path, std::vector<CommLink>& linkListVec)
268{270{
269 const NetInstance::Link* peer2net = nullptr;271 const NetInstance::Link* peer2net = nullptr;
270 const NetInstance::Link* net2peer = nullptr;272 const NetInstance::Link* net2peer = nullptr;
@@ -297,6 +299,7 @@ static HcclResult InsertClosLinks(const NetInstance::Path& path, std::vector<Com
297 // 设置源端点299 // 设置源端点
298 CHK_RET(SetCommAddress(commLink.srcEndpointDesc.commAddr, srcInterface->GetAddr()));300 CHK_RET(SetCommAddress(commLink.srcEndpointDesc.commAddr, srcInterface->GetAddr()));
299 CHK_RET(SetEndpointLoc(commLink.srcEndpointDesc.loc.locType, srcInterface->GetPos()));301 CHK_RET(SetEndpointLoc(commLink.srcEndpointDesc.loc.locType, srcInterface->GetPos()));
302+ CHK_RET(SetEndpointTopoInfo(commLink.srcEndpointDesc, netLayer, srcInterface->GetTopoInstId()));
300 if (commLink.srcEndpointDesc.loc.locType == ENDPOINT_LOC_TYPE_DEVICE) {303 if (commLink.srcEndpointDesc.loc.locType == ENDPOINT_LOC_TYPE_DEVICE) {
301 std::shared_ptr<NetInstance::Node> srcNode = peer2net->GetSourceNode();304 std::shared_ptr<NetInstance::Node> srcNode = peer2net->GetSourceNode();
302 std::shared_ptr<NetInstance::Peer> srcPeer = std::dynamic_pointer_cast<NetInstance::Peer>(srcNode);305 std::shared_ptr<NetInstance::Peer> srcPeer = std::dynamic_pointer_cast<NetInstance::Peer>(srcNode);
@@ -306,6 +309,7 @@ static HcclResult InsertClosLinks(const NetInstance::Path& path, std::vector<Com
306 // 设置目标端点309 // 设置目标端点
307 CHK_RET(SetCommAddress(commLink.dstEndpointDesc.commAddr, dstInterface->GetAddr()));310 CHK_RET(SetCommAddress(commLink.dstEndpointDesc.commAddr, dstInterface->GetAddr()));
308 CHK_RET(SetEndpointLoc(commLink.dstEndpointDesc.loc.locType, dstInterface->GetPos()));311 CHK_RET(SetEndpointLoc(commLink.dstEndpointDesc.loc.locType, dstInterface->GetPos()));
312+ CHK_RET(SetEndpointTopoInfo(commLink.dstEndpointDesc, netLayer, dstInterface->GetTopoInstId()));
309 if (commLink.dstEndpointDesc.loc.locType == ENDPOINT_LOC_TYPE_DEVICE) {313 if (commLink.dstEndpointDesc.loc.locType == ENDPOINT_LOC_TYPE_DEVICE) {
310 std::shared_ptr<NetInstance::Node> dstNode = net2peer->GetTargetNode();314 std::shared_ptr<NetInstance::Node> dstNode = net2peer->GetTargetNode();
311 std::shared_ptr<NetInstance::Peer> dstPeer = std::dynamic_pointer_cast<NetInstance::Peer>(dstNode);315 std::shared_ptr<NetInstance::Peer> dstPeer = std::dynamic_pointer_cast<NetInstance::Peer>(dstNode);
@@ -343,7 +347,7 @@ IRankGraph::GetLinks(uint32_t netLayer, uint32_t srcRank, uint32_t dstRank, Comm
343 }347 }
344 if (!isClos) {348 if (!isClos) {
345 // Peer2Peer网络:直接处理每条link349 // Peer2Peer网络:直接处理每条link
346- HcclResult ret = InsertInnerLink(path, linkListVec_);350+ HcclResult ret = InsertInnerLink(netLayer, path, linkListVec_);
347 CHK_PRT_RET(351 CHK_PRT_RET(
348 ret != HCCL_SUCCESS,352 ret != HCCL_SUCCESS,
349 HCCL_ERROR(353 HCCL_ERROR(
@@ -352,7 +356,7 @@ IRankGraph::GetLinks(uint32_t netLayer, uint32_t srcRank, uint32_t dstRank, Comm
352 ret);356 ret);
353 } else {357 } else {
354 // Clos网络:找到peer2net和net2peer,组合成一条链路358 // Clos网络:找到peer2net和net2peer,组合成一条链路
355- HcclResult ret = InsertClosLinks(path, linkListVec_);359+ HcclResult ret = InsertClosLinks(netLayer, path, linkListVec_);
356 CHK_PRT_RET(360 CHK_PRT_RET(
357 ret != HCCL_SUCCESS,361 ret != HCCL_SUCCESS,
358 HCCL_ERROR(362 HCCL_ERROR(
@@ -16,7 +16,7 @@
16 {16 {
17 "addr_type": "IPV4",17 "addr_type": "IPV4",
18 "addr": "223.0.0.28",18 "addr": "223.0.0.28",
19- "ports": [ "0/0" ]19+ "ports": [ "0/2" ]
20 }20 }
21 ]21 ]
22 }22 }
@@ -36,7 +36,7 @@
36 {36 {
37 "addr_type": "IPV4",37 "addr_type": "IPV4",
38 "addr": "223.0.0.10",38 "addr": "223.0.0.10",
39- "ports": [ "0/1" ]39+ "ports": [ "0/5" ]
40 }40 }
41 ]41 ]
42 }42 }
@@ -16,7 +16,7 @@
16 {16 {
17 "addr_type": "IPV4",17 "addr_type": "IPV4",
18 "addr": "223.0.0.10",18 "addr": "223.0.0.10",
19- "ports": [ "0/0" ]19+ "ports": [ "1/1", "0/1" ]
20 },{20 },{
21 "addr_type": "IPV4",21 "addr_type": "IPV4",
22 "addr": "223.0.0.15",22 "addr": "223.0.0.15",
@@ -41,7 +41,7 @@
41 {41 {
42 "addr_type": "IPV4",42 "addr_type": "IPV4",
43 "addr": "223.0.0.28",43 "addr": "223.0.0.28",
44- "ports": [ "0/0" ]44+ "ports": [ "1/7", "0/2" ]
45 },{45 },{
46 "addr_type": "IPV4",46 "addr_type": "IPV4",
47 "addr": "223.0.0.33",47 "addr": "223.0.0.33",
@@ -66,7 +66,7 @@
66 {66 {
67 "addr_type": "IPV4",67 "addr_type": "IPV4",
68 "addr": "223.0.1.10",68 "addr": "223.0.1.10",
69- "ports": [ "0/0" ]69+ "ports": [ "0/1", "1/1" ]
70 },{70 },{
71 "addr_type": "IPV4",71 "addr_type": "IPV4",
72 "addr": "223.0.1.15",72 "addr": "223.0.1.15",
@@ -92,7 +92,7 @@
92 {92 {
93 "addr_type": "IPV4",93 "addr_type": "IPV4",
94 "addr": "223.0.1.28",94 "addr": "223.0.1.28",
95- "ports": [ "0/0" ]95+ "ports": [ "0/2", "1/7" ]
96 },{96 },{
97 "addr_type": "IPV4",97 "addr_type": "IPV4",
98 "addr": "223.0.1.33",98 "addr": "223.0.1.33",
@@ -176,3 +176,17 @@ HcclResult HrtRaGetTpAttrAsync(
176}176}
177 177 
178} // namespace Hccl178} // namespace Hccl
179+ 
180+// legacy ST 会调用 base_comm 的协议查询逻辑,此处模拟设备支持 CTP。
181+namespace hcomm {
182+ 
183+HcclResult HccpRaGetDevBaseAttr(void* ctxHandle, struct DevBaseAttr* attr)
184+{
185+ (void)ctxHandle;
186+ if (attr != nullptr) {
187+ attr->ub.priorityInfo[0].tpType.bs.ctp = 1;
188+ }
189+ return HCCL_SUCCESS;
190+}
191+ 
192+} // namespace hcomm
@@ -214,34 +214,26 @@ protected:
214 void TearDown() override {}214 void TearDown() override {}
215};215};
216 216 
217-TEST_F(PhyTopoTest, St_AddTopoGraph_When_TopoNotNullAndNetLayerNotExist_Expect_ReturnTopo)217+TEST_F(PhyTopoTest, St_AddTopoGraph_When_TopoNotNull_Expect_ReturnTopo)
218{218{
219 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();219 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
220- u32 netLayer = 1;220+ phyTopo.AddTopoGraph(topo);
221- phyTopo.AddTopoGraph(netLayer, topo);221+ EXPECT_EQ(phyTopo.GetTopoGraph(), topo);
222- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer), topo);
223}222}
224 223 
225-TEST_F(PhyTopoTest, St_GetTopoGraph_When_NetLayerExist_Expect_ReturnTopo)224+TEST_F(PhyTopoTest, St_GetTopoGraph_When_TopoNotAdded_Expect_ReturnNullptr)
226{225{
227- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo1226+ EXPECT_EQ(phyTopo.GetTopoGraph(), nullptr);
228- = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
229- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo2
230- = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
231- u32 netLayer1 = 1;
232- u32 netLayer2 = 2;
233- phyTopo.AddTopoGraph(netLayer1, topo1);
234- phyTopo.AddTopoGraph(netLayer2, topo2);
235- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer1), topo1);
236- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer2), topo2);
237}227}
238 228 
239-TEST_F(PhyTopoTest, St_GetTopoGraph_When_NetLayerNoExist_Expect_ReturnNullptr)229+TEST_F(PhyTopoTest, St_Clear_When_TopoAdded_Expect_ResetTopoAndInitFlag)
240{230{
241- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo1231+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
242- = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();232+ phyTopo.AddTopoGraph(topo);
243- u32 netLayer1 = 1;233+ phyTopo.InitFinish();
244- u32 netLayer2 = 2;234+ 
245- phyTopo.AddTopoGraph(netLayer1, topo1);235+ phyTopo.Clear();
246- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer2), nullptr);236+ 
237+ EXPECT_EQ(phyTopo.GetTopoGraph(), nullptr);
238+ EXPECT_FALSE(phyTopo.IsInitFinished());
247}239}
@@ -214,13 +214,8 @@ std::unique_ptr<PhyTopo> PhyTopoBuilderBuildStub(const std::string& topoPath)
214 std::unique_ptr<PhyTopo> phyTopo = std::make_unique<PhyTopo>();214 std::unique_ptr<PhyTopo> phyTopo = std::make_unique<PhyTopo>();
215 PhyTopoBuilder phyTopoBuilder;215 PhyTopoBuilder phyTopoBuilder;
216 auto topoInfo = phyTopoBuilder.LoadTopoInfo(topoPath);216 auto topoInfo = phyTopoBuilder.LoadTopoInfo(topoPath);
217- // 根据topoInfo,按netLayer构造Graph217+ auto graph = phyTopoBuilder.CreateGraph(topoInfo->edges);
218- for (const auto& iter : topoInfo->edges) {218+ phyTopo->AddTopoGraph(graph);
219- auto netLayer = iter.first;
220- auto graph = phyTopoBuilder.CreateGraph(iter.second);
221- phyTopo->AddTopoGraph(netLayer, graph);
222- HCCL_DEBUG("[PhyTopoBuilder::%s]Build netLayer[%u] topo graph success.", __func__, netLayer);
223- }
224 return phyTopo;219 return phyTopo;
225}220}
226 221 
@@ -268,7 +263,7 @@ TEST_F(PhyTopoBuilderTest, St_PhyTopoBuilder_When_ValidTopoPath_Expect_ReturnEdg
268 std::string topoPath = "./topo.json";263 std::string topoPath = "./topo.json";
269 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoStub));264 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoStub));
270 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);265 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);
271- auto graph = phyTopo->GetTopoGraph(0);266+ auto graph = phyTopo->GetTopoGraph();
272 size_t totalEdgeNum = 0;267 size_t totalEdgeNum = 0;
273 268 
274 // 遍历所有源节点269 // 遍历所有源节点
@@ -296,7 +291,7 @@ TEST_F(PhyTopoBuilderTest, St_PhyTopoBuilder_When_DiffProtocols_Expect_ReturnEdg
296 std::string topoPath = "./topo.json";291 std::string topoPath = "./topo.json";
297 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoWithDiffProtocols));292 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoWithDiffProtocols));
298 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);293 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);
299- auto graph = phyTopo->GetTopoGraph(0);294+ auto graph = phyTopo->GetTopoGraph();
300 size_t totalEdgeNum = 0;295 size_t totalEdgeNum = 0;
301 296 
302 // 遍历所有源节点297 // 遍历所有源节点
@@ -40,7 +40,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_Normal_Expect_Success)
40 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));40 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));
41 41 
42 std::string edgeString = R"({42 std::string edgeString = R"({
43- "net_layer": 0,
44 "link_type": "PEER2PEER",43 "link_type": "PEER2PEER",
45 "protocols": ["UB_CTP"], 44 "protocols": ["UB_CTP"],
46 "topo_type": "1DMESH",45 "topo_type": "1DMESH",
@@ -57,7 +56,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_Normal_Expect_Success)
57 topoParser.ParseString(edgeString, edgeInfo);56 topoParser.ParseString(edgeString, edgeInfo);
58 57 
59 EdgeInfo edge0;58 EdgeInfo edge0;
60- edge0.netLayer = 0;
61 edge0.protocols.emplace(LinkProtocol::UB_CTP);59 edge0.protocols.emplace(LinkProtocol::UB_CTP);
62 edge0.linkType = LinkType::PEER2PEER;60 edge0.linkType = LinkType::PEER2PEER;
63 edge0.topoType = TopoType::MESH_1D;61 edge0.topoType = TopoType::MESH_1D;
@@ -93,7 +91,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_OptionalFieldsMissing_Expect_Success)
93 topoParser.ParseString(edgeString, edgeInfo);91 topoParser.ParseString(edgeString, edgeInfo);
94 92 
95 EdgeInfo edge0;93 EdgeInfo edge0;
96- edge0.netLayer = 0;
97 edge0.protocols.emplace(LinkProtocol::UB_CTP);94 edge0.protocols.emplace(LinkProtocol::UB_CTP);
98 edge0.linkType = LinkType::PEER2PEER;95 edge0.linkType = LinkType::PEER2PEER;
99 edge0.topoType = TopoType::CLOS;96 edge0.topoType = TopoType::CLOS;
@@ -131,7 +128,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_PEER2NET_ExistB_Expect_Warning)
131 topoParser.ParseString(edgeString, edgeInfo);128 topoParser.ParseString(edgeString, edgeInfo);
132 129 
133 EdgeInfo edge0;130 EdgeInfo edge0;
134- edge0.netLayer = 0;
135 edge0.protocols.emplace(LinkProtocol::UB_CTP);131 edge0.protocols.emplace(LinkProtocol::UB_CTP);
136 edge0.linkType = LinkType::PEER2NET;132 edge0.linkType = LinkType::PEER2NET;
137 edge0.topoType = TopoType::MESH_1D;133 edge0.topoType = TopoType::MESH_1D;
@@ -165,7 +161,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_NormalPeer2Net_Expect_Success)
165 topoParser.ParseString(edgeString, edgeInfo);161 topoParser.ParseString(edgeString, edgeInfo);
166 162 
167 EdgeInfo edge0;163 EdgeInfo edge0;
168- edge0.netLayer = 0;
169 edge0.protocols.emplace(LinkProtocol::UB_CTP);164 edge0.protocols.emplace(LinkProtocol::UB_CTP);
170 edge0.linkType = LinkType::PEER2NET;165 edge0.linkType = LinkType::PEER2NET;
171 edge0.topoType = TopoType::MESH_1D;166 edge0.topoType = TopoType::MESH_1D;
@@ -194,14 +189,13 @@ TEST_F(EdgeParserTest, St_Deserialize_When_NeededFieldMissing_Expect_Exception)
194 EXPECT_THROW(edgeParser.ParseString(edgeString, edgeInfo), InvalidParamsException);189 EXPECT_THROW(edgeParser.ParseString(edgeString, edgeInfo), InvalidParamsException);
195}190}
196 191 
197-// net_layer = 8192+// 旧 topo.json 中不同或越界的 net_layer 都应被忽略,解析结果与不带该字段时一致
198-TEST_F(EdgeParserTest, St_Deserialize_When_InvalidNetLayer_Expect_Exception)193+TEST_F(EdgeParserTest, St_Deserialize_When_LegacyNetLayerDifferentOrOutOfRange_Expect_SameEdge)
199{194{
200 DevType devType = DevType::DEV_TYPE_910A;195 DevType devType = DevType::DEV_TYPE_910A;
201 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));196 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));
202 197 
203- std::string edgeString = R"({198+ std::string edgeStringWithoutNetLayer = R"({
204- "net_layer": 8,
205 "link_type": "PEER2PEER",199 "link_type": "PEER2PEER",
206 "protocols": ["UB_CTP"],200 "protocols": ["UB_CTP"],
207 "topo_type": "1DMESH",201 "topo_type": "1DMESH",
@@ -213,9 +207,21 @@ TEST_F(EdgeParserTest, St_Deserialize_When_InvalidNetLayer_Expect_Exception)
213 "position": "DEVICE"207 "position": "DEVICE"
214 })";208 })";
215 209 
210+ nlohmann::json edgeJsonWithoutNetLayer = nlohmann::json::parse(edgeStringWithoutNetLayer);
211+ nlohmann::json edgeJsonWithDifferentNetLayer = edgeJsonWithoutNetLayer;
212+ nlohmann::json edgeJsonWithOutOfRangeNetLayer = edgeJsonWithoutNetLayer;
213+ edgeJsonWithDifferentNetLayer["net_layer"] = 1;
214+ edgeJsonWithOutOfRangeNetLayer["net_layer"] = 8;
215+ 
216 JsonParser edgeParser;216 JsonParser edgeParser;
217- EdgeInfo edgeInfo;217+ EdgeInfo edgeWithoutNetLayer;
218- EXPECT_THROW(edgeParser.ParseString(edgeString, edgeInfo), InvalidParamsException);218+ EdgeInfo edgeWithDifferentNetLayer;
219+ EdgeInfo edgeWithOutOfRangeNetLayer;
220+ EXPECT_NO_THROW(edgeParser.ParseString(edgeStringWithoutNetLayer, edgeWithoutNetLayer));
221+ EXPECT_NO_THROW(edgeParser.ParseString(edgeJsonWithDifferentNetLayer.dump(), edgeWithDifferentNetLayer));
222+ EXPECT_NO_THROW(edgeParser.ParseString(edgeJsonWithOutOfRangeNetLayer.dump(), edgeWithOutOfRangeNetLayer));
223+ EXPECT_TRUE(edgeWithoutNetLayer == edgeWithDifferentNetLayer);
224+ EXPECT_TRUE(edgeWithoutNetLayer == edgeWithOutOfRangeNetLayer);
219}225}
220 226 
221// 无效的LinkProtocol227// 无效的LinkProtocol
@@ -266,7 +272,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_ToManyLinkProtocols_Expect_Exception)
266 edgeParser.ParseString(edgeString, edgeInfo);272 edgeParser.ParseString(edgeString, edgeInfo);
267 273 
268 EdgeInfo edge0;274 EdgeInfo edge0;
269- edge0.netLayer = 2;
270 edge0.protocols.emplace(LinkProtocol::UB_CTP);275 edge0.protocols.emplace(LinkProtocol::UB_CTP);
271 edge0.protocols.emplace(LinkProtocol::ROCE);276 edge0.protocols.emplace(LinkProtocol::ROCE);
272 edge0.linkType = LinkType::PEER2PEER;277 edge0.linkType = LinkType::PEER2PEER;
@@ -426,7 +431,6 @@ TEST_F(EdgeParserTest, St_Deserialize_When_InvalidPosition_Expect_Exception)
426TEST_F(EdgeParserTest, St_BinaryStream_When_GetBinStreamToReBuild_Expect_Success)431TEST_F(EdgeParserTest, St_BinaryStream_When_GetBinStreamToReBuild_Expect_Success)
427{432{
428 EdgeInfo edge0;433 EdgeInfo edge0;
429- edge0.netLayer = 0;
430 edge0.protocols.emplace(LinkProtocol::UB_CTP);434 edge0.protocols.emplace(LinkProtocol::UB_CTP);
431 edge0.linkType = LinkType::PEER2PEER;435 edge0.linkType = LinkType::PEER2PEER;
432 edge0.topoType = TopoType::MESH_1D;436 edge0.topoType = TopoType::MESH_1D;
@@ -126,11 +126,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
126 expectTopoInfo.peers.emplace_back(peer2);126 expectTopoInfo.peers.emplace_back(peer2);
127 127 
128 expectTopoInfo.edgeCount = 5;128 expectTopoInfo.edgeCount = 5;
129- expectTopoInfo.edges[0] = std::vector<EdgeInfo>();
130- expectTopoInfo.edges[1] = std::vector<EdgeInfo>();
131- expectTopoInfo.edges[2] = std::vector<EdgeInfo>();
132 EdgeInfo edge0;129 EdgeInfo edge0;
133- edge0.netLayer = 0;
134 edge0.linkType = LinkType::PEER2PEER;130 edge0.linkType = LinkType::PEER2PEER;
135 edge0.protocols.emplace(LinkProtocol::UB_CTP);131 edge0.protocols.emplace(LinkProtocol::UB_CTP);
136 edge0.topoType = TopoType::MESH_1D;132 edge0.topoType = TopoType::MESH_1D;
@@ -140,10 +136,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
140 edge0.localB = 1;136 edge0.localB = 1;
141 edge0.localBPorts.emplace("0/1");137 edge0.localBPorts.emplace("0/1");
142 edge0.position = AddrPosition::DEVICE;138 edge0.position = AddrPosition::DEVICE;
143- expectTopoInfo.edges[0].emplace_back(edge0);139+ expectTopoInfo.edges.emplace_back(edge0);
144 140 
145 EdgeInfo edge1;141 EdgeInfo edge1;
146- edge1.netLayer = 0;
147 edge1.linkType = LinkType::PEER2PEER;142 edge1.linkType = LinkType::PEER2PEER;
148 edge1.protocols.emplace(LinkProtocol::UB_MEM);143 edge1.protocols.emplace(LinkProtocol::UB_MEM);
149 edge1.topoType = TopoType::MESH_1D;144 edge1.topoType = TopoType::MESH_1D;
@@ -153,10 +148,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
153 edge1.localB = 2;148 edge1.localB = 2;
154 edge1.localBPorts.emplace("0/1");149 edge1.localBPorts.emplace("0/1");
155 edge1.position = AddrPosition::DEVICE;150 edge1.position = AddrPosition::DEVICE;
156- expectTopoInfo.edges[0].emplace_back(edge1);151+ expectTopoInfo.edges.emplace_back(edge1);
157 152 
158 EdgeInfo edge2;153 EdgeInfo edge2;
159- edge2.netLayer = 0;
160 edge2.linkType = LinkType::PEER2NET;154 edge2.linkType = LinkType::PEER2NET;
161 edge2.protocols.emplace(LinkProtocol::UB_CTP);155 edge2.protocols.emplace(LinkProtocol::UB_CTP);
162 edge2.topoType = TopoType::MESH_1D;156 edge2.topoType = TopoType::MESH_1D;
@@ -164,10 +158,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
164 edge2.localA = 0;158 edge2.localA = 0;
165 edge2.localAPorts.emplace("0/0");159 edge2.localAPorts.emplace("0/0");
166 edge2.position = AddrPosition::HOST;160 edge2.position = AddrPosition::HOST;
167- expectTopoInfo.edges[0].emplace_back(edge2);161+ expectTopoInfo.edges.emplace_back(edge2);
168 162 
169 EdgeInfo edge3;163 EdgeInfo edge3;
170- edge3.netLayer = 1;
171 edge3.linkType = LinkType::PEER2PEER;164 edge3.linkType = LinkType::PEER2PEER;
172 edge3.protocols.emplace(LinkProtocol::UB_TP);165 edge3.protocols.emplace(LinkProtocol::UB_TP);
173 edge3.topoType = TopoType::MESH_1D;166 edge3.topoType = TopoType::MESH_1D;
@@ -177,10 +170,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
177 edge3.localB = 2;170 edge3.localB = 2;
178 edge3.localBPorts.emplace("0/1");171 edge3.localBPorts.emplace("0/1");
179 edge3.position = AddrPosition::DEVICE;172 edge3.position = AddrPosition::DEVICE;
180- expectTopoInfo.edges[1].emplace_back(edge3);173+ expectTopoInfo.edges.emplace_back(edge3);
181 174 
182 EdgeInfo edge4;175 EdgeInfo edge4;
183- edge4.netLayer = 2;
184 edge4.linkType = LinkType::PEER2NET;176 edge4.linkType = LinkType::PEER2NET;
185 edge4.protocols.emplace(LinkProtocol::ROCE);177 edge4.protocols.emplace(LinkProtocol::ROCE);
186 edge4.topoType = TopoType::CLOS;178 edge4.topoType = TopoType::CLOS;
@@ -188,7 +180,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
188 edge4.localA = 0;180 edge4.localA = 0;
189 edge4.localAPorts.emplace("0/0");181 edge4.localAPorts.emplace("0/0");
190 edge4.position = AddrPosition::DEVICE;182 edge4.position = AddrPosition::DEVICE;
191- expectTopoInfo.edges[2].emplace_back(edge4);183+ expectTopoInfo.edges.emplace_back(edge4);
192 184 
193 EXPECT_EQ(topoInfo.version, expectTopoInfo.version);185 EXPECT_EQ(topoInfo.version, expectTopoInfo.version);
194 EXPECT_EQ(topoInfo.peerCount, expectTopoInfo.peerCount);186 EXPECT_EQ(topoInfo.peerCount, expectTopoInfo.peerCount);
@@ -199,25 +191,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
199 EXPECT_EQ(topoInfo.edgeCount, expectTopoInfo.edgeCount);191 EXPECT_EQ(topoInfo.edgeCount, expectTopoInfo.edgeCount);
200 EXPECT_EQ(topoInfo.edges.size(), expectTopoInfo.edges.size());192 EXPECT_EQ(topoInfo.edges.size(), expectTopoInfo.edges.size());
201 193 
202- auto it_topo_edges = topoInfo.edges.begin();194+ EXPECT_EQ(topoInfo.edges, expectTopoInfo.edges);
203- auto it_expect_edges = expectTopoInfo.edges.begin();
204- for (; it_topo_edges != topoInfo.edges.end(); it_topo_edges++, it_expect_edges++) {
205- EXPECT_EQ(it_topo_edges->first, it_expect_edges->first);
206- EXPECT_EQ((it_topo_edges->second).size(), (it_expect_edges->second).size());
207- for (u32 i = 0; i < (it_topo_edges->second).size(); i++) {
208- EXPECT_EQ((it_topo_edges->second)[i].netLayer, (it_expect_edges->second)[i].netLayer);
209- EXPECT_EQ((it_topo_edges->second)[i].protocols, (it_expect_edges->second)[i].protocols);
210- EXPECT_EQ((it_topo_edges->second)[i].linkType, (it_expect_edges->second)[i].linkType);
211- EXPECT_EQ((it_topo_edges->second)[i].topoType, (it_expect_edges->second)[i].topoType);
212- EXPECT_EQ((it_topo_edges->second)[i].topoInstId, (it_expect_edges->second)[i].topoInstId);
213- EXPECT_EQ((it_topo_edges->second)[i].localA, (it_expect_edges->second)[i].localA);
214- EXPECT_EQ((it_topo_edges->second)[i].localAPorts, (it_expect_edges->second)[i].localAPorts);
215- EXPECT_EQ((it_topo_edges->second)[i].localB, (it_expect_edges->second)[i].localB);
216- EXPECT_EQ((it_topo_edges->second)[i].localBPorts, (it_expect_edges->second)[i].localBPorts);
217- EXPECT_EQ((it_topo_edges->second)[i].position, (it_expect_edges->second)[i].position);
218- }
219- }
220- 
221 EXPECT_EQ(topoInfo.Describe(), expectTopoInfo.Describe());195 EXPECT_EQ(topoInfo.Describe(), expectTopoInfo.Describe());
222}196}
223 197 
@@ -436,7 +410,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_EdgesSizeUnequalToEdgeCount_Expect_Ex
436}410}
437 411 
438// 重复的边 PEER2PEER,localA和localB对调412// 重复的边 PEER2PEER,localA和localB对调
439-TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Exception)413+TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Merged)
440{414{
441 DevType devType = DevType::DEV_TYPE_910A;415 DevType devType = DevType::DEV_TYPE_910A;
442 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));416 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));
@@ -465,7 +439,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Exception)
465 "position": "DEVICE"439 "position": "DEVICE"
466 },440 },
467 {441 {
468- "net_layer": 0,442+ "net_layer": 1,
469 "link_type": "PEER2PEER",443 "link_type": "PEER2PEER",
470 "protocols": ["UB_CTP"],444 "protocols": ["UB_CTP"],
471 "topo_type": "1DMESH",445 "topo_type": "1DMESH",
@@ -481,7 +455,11 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Exception)
481 455 
482 JsonParser topoParser;456 JsonParser topoParser;
483 TopoInfo topoInfo;457 TopoInfo topoInfo;
484- EXPECT_THROW(topoParser.ParseString(topoString, topoInfo), InvalidParamsException);458+ EXPECT_NO_THROW(topoParser.ParseString(topoString, topoInfo));
459+ EXPECT_EQ(topoInfo.edgeCount, 1);
460+ ASSERT_EQ(topoInfo.edges.size(), 1);
461+ EXPECT_EQ(topoInfo.edges[0].localA, 0);
462+ EXPECT_EQ(topoInfo.edges[0].localB, 1);
485}463}
486 464 
487// Endpoint的localId无效465// Endpoint的localId无效
@@ -660,11 +638,7 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
660 expectTopoInfo.peers.emplace_back(peer2);638 expectTopoInfo.peers.emplace_back(peer2);
661 639 
662 expectTopoInfo.edgeCount = 5;640 expectTopoInfo.edgeCount = 5;
663- expectTopoInfo.edges[0] = std::vector<EdgeInfo>();
664- expectTopoInfo.edges[1] = std::vector<EdgeInfo>();
665- expectTopoInfo.edges[2] = std::vector<EdgeInfo>();
666 EdgeInfo edge0;641 EdgeInfo edge0;
667- edge0.netLayer = 0;
668 edge0.linkType = LinkType::PEER2PEER;642 edge0.linkType = LinkType::PEER2PEER;
669 edge0.protocols.emplace(LinkProtocol::UB_CTP);643 edge0.protocols.emplace(LinkProtocol::UB_CTP);
670 edge0.topoType = TopoType::MESH_1D;644 edge0.topoType = TopoType::MESH_1D;
@@ -674,10 +648,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
674 edge0.localB = 1;648 edge0.localB = 1;
675 edge0.localBPorts.emplace("0/1");649 edge0.localBPorts.emplace("0/1");
676 edge0.position = AddrPosition::DEVICE;650 edge0.position = AddrPosition::DEVICE;
677- expectTopoInfo.edges[0].emplace_back(edge0);651+ expectTopoInfo.edges.emplace_back(edge0);
678 652 
679 EdgeInfo edge1;653 EdgeInfo edge1;
680- edge1.netLayer = 0;
681 edge1.linkType = LinkType::PEER2PEER;654 edge1.linkType = LinkType::PEER2PEER;
682 edge1.protocols.emplace(LinkProtocol::UB_MEM);655 edge1.protocols.emplace(LinkProtocol::UB_MEM);
683 edge1.topoType = TopoType::MESH_1D;656 edge1.topoType = TopoType::MESH_1D;
@@ -687,10 +660,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
687 edge1.localB = 2;660 edge1.localB = 2;
688 edge1.localBPorts.emplace("0/1");661 edge1.localBPorts.emplace("0/1");
689 edge1.position = AddrPosition::DEVICE;662 edge1.position = AddrPosition::DEVICE;
690- expectTopoInfo.edges[0].emplace_back(edge1);663+ expectTopoInfo.edges.emplace_back(edge1);
691 664 
692 EdgeInfo edge2;665 EdgeInfo edge2;
693- edge2.netLayer = 0;
694 edge2.linkType = LinkType::PEER2NET;666 edge2.linkType = LinkType::PEER2NET;
695 edge2.protocols.emplace(LinkProtocol::UB_CTP);667 edge2.protocols.emplace(LinkProtocol::UB_CTP);
696 edge2.topoType = TopoType::MESH_1D;668 edge2.topoType = TopoType::MESH_1D;
@@ -698,10 +670,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
698 edge2.localA = 0;670 edge2.localA = 0;
699 edge2.localAPorts.emplace("0/0");671 edge2.localAPorts.emplace("0/0");
700 edge2.position = AddrPosition::HOST;672 edge2.position = AddrPosition::HOST;
701- expectTopoInfo.edges[0].emplace_back(edge2);673+ expectTopoInfo.edges.emplace_back(edge2);
702 674 
703 EdgeInfo edge3;675 EdgeInfo edge3;
704- edge3.netLayer = 1;
705 edge3.linkType = LinkType::PEER2PEER;676 edge3.linkType = LinkType::PEER2PEER;
706 edge3.protocols.emplace(LinkProtocol::UB_TP);677 edge3.protocols.emplace(LinkProtocol::UB_TP);
707 edge3.topoType = TopoType::MESH_1D;678 edge3.topoType = TopoType::MESH_1D;
@@ -711,10 +682,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
711 edge3.localB = 2;682 edge3.localB = 2;
712 edge3.localBPorts.emplace("0/1");683 edge3.localBPorts.emplace("0/1");
713 edge3.position = AddrPosition::DEVICE;684 edge3.position = AddrPosition::DEVICE;
714- expectTopoInfo.edges[1].emplace_back(edge3);685+ expectTopoInfo.edges.emplace_back(edge3);
715 686 
716 EdgeInfo edge4;687 EdgeInfo edge4;
717- edge4.netLayer = 2;
718 edge4.linkType = LinkType::PEER2NET;688 edge4.linkType = LinkType::PEER2NET;
719 edge4.protocols.emplace(LinkProtocol::ROCE);689 edge4.protocols.emplace(LinkProtocol::ROCE);
720 edge4.topoType = TopoType::CLOS;690 edge4.topoType = TopoType::CLOS;
@@ -722,7 +692,7 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
722 edge4.localA = 0;692 edge4.localA = 0;
723 edge4.localAPorts.emplace("0/0");693 edge4.localAPorts.emplace("0/0");
724 edge4.position = AddrPosition::DEVICE;694 edge4.position = AddrPosition::DEVICE;
725- expectTopoInfo.edges[2].emplace_back(edge4);695+ expectTopoInfo.edges.emplace_back(edge4);
726 696 
727 BinaryStream binStream;697 BinaryStream binStream;
728 expectTopoInfo.GetBinStream(binStream);698 expectTopoInfo.GetBinStream(binStream);
@@ -737,25 +707,7 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
737 EXPECT_EQ(expectTopoInfo.edgeCount, reBuildTopo.edgeCount);707 EXPECT_EQ(expectTopoInfo.edgeCount, reBuildTopo.edgeCount);
738 EXPECT_EQ(expectTopoInfo.edges.size(), reBuildTopo.edges.size());708 EXPECT_EQ(expectTopoInfo.edges.size(), reBuildTopo.edges.size());
739 709 
740- auto it_topo_edges = expectTopoInfo.edges.begin();710+ EXPECT_EQ(expectTopoInfo.edges, reBuildTopo.edges);
741- auto it_expect_edges = reBuildTopo.edges.begin();
742- for (; it_topo_edges != expectTopoInfo.edges.end(); it_topo_edges++, it_expect_edges++) {
743- EXPECT_EQ(it_topo_edges->first, it_expect_edges->first);
744- EXPECT_EQ((it_topo_edges->second).size(), (it_expect_edges->second).size());
745- for (u32 i = 0; i < (it_topo_edges->second).size(); i++) {
746- EXPECT_EQ((it_topo_edges->second)[i].netLayer, (it_expect_edges->second)[i].netLayer);
747- EXPECT_EQ((it_topo_edges->second)[i].protocols, (it_expect_edges->second)[i].protocols);
748- EXPECT_EQ((it_topo_edges->second)[i].linkType, (it_expect_edges->second)[i].linkType);
749- EXPECT_EQ((it_topo_edges->second)[i].topoType, (it_expect_edges->second)[i].topoType);
750- EXPECT_EQ((it_topo_edges->second)[i].topoInstId, (it_expect_edges->second)[i].topoInstId);
751- EXPECT_EQ((it_topo_edges->second)[i].localA, (it_expect_edges->second)[i].localA);
752- EXPECT_EQ((it_topo_edges->second)[i].localAPorts, (it_expect_edges->second)[i].localAPorts);
753- EXPECT_EQ((it_topo_edges->second)[i].localB, (it_expect_edges->second)[i].localB);
754- EXPECT_EQ((it_topo_edges->second)[i].localBPorts, (it_expect_edges->second)[i].localBPorts);
755- EXPECT_EQ((it_topo_edges->second)[i].position, (it_expect_edges->second)[i].position);
756- }
757- }
758- 
759 EXPECT_EQ(expectTopoInfo.Describe(), reBuildTopo.Describe());711 EXPECT_EQ(expectTopoInfo.Describe(), reBuildTopo.Describe());
760}712}
761 713 
@@ -41,21 +41,25 @@ const std::string RankTable2pClos = R"(
41 {41 {
42 "addr_type": "IPV4",42 "addr_type": "IPV4",
43 "addr": "192.168.100.11",43 "addr": "192.168.100.11",
44+ "plane_id": "planeA",
44 "ports": [ "0/1" ]45 "ports": [ "0/1" ]
45 },46 },
46 {47 {
47 "addr_type": "IPV4",48 "addr_type": "IPV4",
48 "addr": "192.168.100.12",49 "addr": "192.168.100.12",
50+ "plane_id": "planeB",
49 "ports": [ "0/2" ]51 "ports": [ "0/2" ]
50 },52 },
51 {53 {
52 "addr_type": "IPV4",54 "addr_type": "IPV4",
53 "addr": "192.168.100.13",55 "addr": "192.168.100.13",
56+ "plane_id": "planeC",
54 "ports": [ "0/3" ]57 "ports": [ "0/3" ]
55 },58 },
56 {59 {
57 "addr_type": "IPV4",60 "addr_type": "IPV4",
58 "addr": "192.168.100.14",61 "addr": "192.168.100.14",
62+ "plane_id": "planeD",
59 "ports": [ "0/4" ]63 "ports": [ "0/4" ]
60 }64 }
61 ],65 ],
@@ -88,21 +92,25 @@ const std::string RankTable2pClos = R"(
88 {92 {
89 "addr_type": "IPV4",93 "addr_type": "IPV4",
90 "addr": "192.168.100.21",94 "addr": "192.168.100.21",
95+ "plane_id": "planeA",
91 "ports": [ "1/1" ]96 "ports": [ "1/1" ]
92 },97 },
93 {98 {
94 "addr_type": "IPV4",99 "addr_type": "IPV4",
95 "addr": "192.168.100.22",100 "addr": "192.168.100.22",
101+ "plane_id": "planeB",
96 "ports": [ "1/2" ]102 "ports": [ "1/2" ]
97 },103 },
98 {104 {
99 "addr_type": "IPV4",105 "addr_type": "IPV4",
100 "addr": "192.168.100.23",106 "addr": "192.168.100.23",
107+ "plane_id": "planeC",
101 "ports": [ "1/3" ]108 "ports": [ "1/3" ]
102 },109 },
103 {110 {
104 "addr_type": "IPV4",111 "addr_type": "IPV4",
105 "addr": "192.168.100.24",112 "addr": "192.168.100.24",
113+ "plane_id": "planeD",
106 "ports": [ "1/4" ]114 "ports": [ "1/4" ]
107 }115 }
108 ],116 ],
@@ -142,11 +150,13 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
142 {150 {
143 "addr_type": "IPV4",151 "addr_type": "IPV4",
144 "addr": "192.168.164.101",152 "addr": "192.168.164.101",
153+ "plane_id": "planeA",
145 "ports": [ "0/1" ]154 "ports": [ "0/1" ]
146 },155 },
147 {156 {
148 "addr_type": "IPV4",157 "addr_type": "IPV4",
149 "addr": "192.168.164.102",158 "addr": "192.168.164.102",
159+ "plane_id": "planeB",
150 "ports": [ "0/2" ]160 "ports": [ "0/2" ]
151 },161 },
152 {162 {
@@ -187,11 +197,13 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
187 {197 {
188 "addr_type": "IPV4",198 "addr_type": "IPV4",
189 "addr": "192.168.164.111",199 "addr": "192.168.164.111",
200+ "plane_id": "planeC",
190 "ports": [ "1/1" ]201 "ports": [ "1/1" ]
191 },202 },
192 {203 {
193 "addr_type": "IPV4",204 "addr_type": "IPV4",
194 "addr": "192.168.164.112",205 "addr": "192.168.164.112",
206+ "plane_id": "planeD",
195 "ports": [ "1/2" ]207 "ports": [ "1/2" ]
196 },208 },
197 {209 {
@@ -243,41 +255,49 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
243 {255 {
244 "addr_type": "IPV4",256 "addr_type": "IPV4",
245 "addr": "192.168.164.100",257 "addr": "192.168.164.100",
258+ "plane_id": "planeA",
246 "ports": [ "0/0" ]259 "ports": [ "0/0" ]
247 },260 },
248 {261 {
249 "addr_type": "IPV4",262 "addr_type": "IPV4",
250 "addr": "192.168.164.101",263 "addr": "192.168.164.101",
264+ "plane_id": "planeA",
251 "ports": [ "0/1" ]265 "ports": [ "0/1" ]
252 },266 },
253 {267 {
254 "addr_type": "IPV4",268 "addr_type": "IPV4",
255 "addr": "192.168.164.102",269 "addr": "192.168.164.102",
270+ "plane_id": "planeA",
256 "ports": [ "0/2" ]271 "ports": [ "0/2" ]
257 },272 },
258 {273 {
259 "addr_type": "IPV4",274 "addr_type": "IPV4",
260 "addr": "192.168.164.103",275 "addr": "192.168.164.103",
276+ "plane_id": "planeA",
261 "ports": [ "0/3" ]277 "ports": [ "0/3" ]
262 },278 },
263 {279 {
264 "addr_type": "IPV4",280 "addr_type": "IPV4",
265 "addr": "192.168.164.104",281 "addr": "192.168.164.104",
282+ "plane_id": "planeB",
266 "ports": [ "0/4" ]283 "ports": [ "0/4" ]
267 },284 },
268 {285 {
269 "addr_type": "IPV4",286 "addr_type": "IPV4",
270 "addr": "192.168.164.105",287 "addr": "192.168.164.105",
288+ "plane_id": "planeB",
271 "ports": [ "0/5" ]289 "ports": [ "0/5" ]
272 },290 },
273 {291 {
274 "addr_type": "IPV4",292 "addr_type": "IPV4",
275 "addr": "192.168.164.106",293 "addr": "192.168.164.106",
294+ "plane_id": "planeB",
276 "ports": [ "0/6" ]295 "ports": [ "0/6" ]
277 },296 },
278 {297 {
279 "addr_type": "IPV4",298 "addr_type": "IPV4",
280 "addr": "192.168.164.107",299 "addr": "192.168.164.107",
300+ "plane_id": "planeB",
281 "ports": [ "0/7" ]301 "ports": [ "0/7" ]
282 },302 },
283 {303 {
@@ -288,41 +308,49 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
288 {308 {
289 "addr_type": "IPV4",309 "addr_type": "IPV4",
290 "addr": "192.168.164.110",310 "addr": "192.168.164.110",
311+ "plane_id": "planeC",
291 "ports": [ "1/0" ]312 "ports": [ "1/0" ]
292 },313 },
293 {314 {
294 "addr_type": "IPV4",315 "addr_type": "IPV4",
295 "addr": "192.168.164.111",316 "addr": "192.168.164.111",
317+ "plane_id": "planeC",
296 "ports": [ "1/1" ]318 "ports": [ "1/1" ]
297 },319 },
298 {320 {
299 "addr_type": "IPV4",321 "addr_type": "IPV4",
300 "addr": "192.168.164.112",322 "addr": "192.168.164.112",
323+ "plane_id": "planeC",
301 "ports": [ "1/2" ]324 "ports": [ "1/2" ]
302 },325 },
303 {326 {
304 "addr_type": "IPV4",327 "addr_type": "IPV4",
305 "addr": "192.168.164.113",328 "addr": "192.168.164.113",
329+ "plane_id": "planeC",
306 "ports": [ "1/3" ]330 "ports": [ "1/3" ]
307 },331 },
308 {332 {
309 "addr_type": "IPV4",333 "addr_type": "IPV4",
310 "addr": "192.168.164.114",334 "addr": "192.168.164.114",
335+ "plane_id": "planeD",
311 "ports": [ "1/4" ]336 "ports": [ "1/4" ]
312 },337 },
313 {338 {
314 "addr_type": "IPV4",339 "addr_type": "IPV4",
315 "addr": "192.168.164.115",340 "addr": "192.168.164.115",
341+ "plane_id": "planeD",
316 "ports": [ "1/5" ]342 "ports": [ "1/5" ]
317 },343 },
318 {344 {
319 "addr_type": "IPV4",345 "addr_type": "IPV4",
320 "addr": "192.168.164.116",346 "addr": "192.168.164.116",
347+ "plane_id": "planeD",
321 "ports": [ "1/6" ]348 "ports": [ "1/6" ]
322 },349 },
323 {350 {
324 "addr_type": "IPV4",351 "addr_type": "IPV4",
325 "addr": "192.168.164.117",352 "addr": "192.168.164.117",
353+ "plane_id": "planeD",
326 "ports": [ "1/7" ]354 "ports": [ "1/7" ]
327 },355 },
328 {356 {
@@ -353,11 +381,13 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
353 {381 {
354 "addr_type": "IPV4",382 "addr_type": "IPV4",
355 "addr": "192.168.164.101",383 "addr": "192.168.164.101",
384+ "plane_id": "planeA",
356 "ports": [ "0/1" ]385 "ports": [ "0/1" ]
357 },386 },
358 {387 {
359 "addr_type": "IPV4",388 "addr_type": "IPV4",
360 "addr": "192.168.164.102",389 "addr": "192.168.164.102",
390+ "plane_id": "planeB",
361 "ports": [ "0/2" ]391 "ports": [ "0/2" ]
362 },392 },
363 {393 {
@@ -398,11 +428,13 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
398 {428 {
399 "addr_type": "IPV4",429 "addr_type": "IPV4",
400 "addr": "192.168.164.111",430 "addr": "192.168.164.111",
431+ "plane_id": "planeC",
401 "ports": [ "1/1" ]432 "ports": [ "1/1" ]
402 },433 },
403 {434 {
404 "addr_type": "IPV4",435 "addr_type": "IPV4",
405 "addr": "192.168.164.112",436 "addr": "192.168.164.112",
437+ "plane_id": "planeD",
406 "ports": [ "1/2" ]438 "ports": [ "1/2" ]
407 },439 },
408 {440 {
@@ -458,11 +490,13 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
458 {490 {
459 "addr_type": "IPV4",491 "addr_type": "IPV4",
460 "addr": "192.168.164.101",492 "addr": "192.168.164.101",
493+ "plane_id": "planeA",
461 "ports": [ "0/1" ]494 "ports": [ "0/1" ]
462 },495 },
463 {496 {
464 "addr_type": "IPV4",497 "addr_type": "IPV4",
465 "addr": "192.168.164.102",498 "addr": "192.168.164.102",
499+ "plane_id": "planeB",
466 "ports": [ "0/2" ]500 "ports": [ "0/2" ]
467 },501 },
468 {502 {
@@ -503,11 +537,13 @@ const std::string RANK_TABLE_4P_REPLACE_RANK1 = R"(
503 {537 {
504 "addr_type": "IPV4",538 "addr_type": "IPV4",
505 "addr": "192.168.164.111",539 "addr": "192.168.164.111",
540+ "plane_id": "planeC",
506 "ports": [ "1/1" ]541 "ports": [ "1/1" ]
507 },542 },
508 {543 {
509 "addr_type": "IPV4",544 "addr_type": "IPV4",
510 "addr": "192.168.164.112",545 "addr": "192.168.164.112",
546+ "plane_id": "planeD",
511 "ports": [ "1/2" ]547 "ports": [ "1/2" ]
512 },548 },
513 {549 {
@@ -34,6 +34,7 @@ protected:
34 34 
35 virtual void SetUp()35 virtual void SetUp()
36 {36 {
37+ PhyTopo::GetInstance()->Clear();
37 hccpSocketHandle = new int(0);38 hccpSocketHandle = new int(0);
38 MOCKER_CPP(&SocketHandleManager::Create)39 MOCKER_CPP(&SocketHandleManager::Create)
39 .stubs()40 .stubs()
@@ -51,6 +52,7 @@ protected:
51 52 
52 virtual void TearDown()53 virtual void TearDown()
53 {54 {
55+ PhyTopo::GetInstance()->Clear();
54 GlobalMockObject::verify();56 GlobalMockObject::verify();
55 delete hccpSocketHandle;57 delete hccpSocketHandle;
56 std::cout << "A Test case in SocketManagerTest TearDown" << std::endl;58 std::cout << "A Test case in SocketManagerTest TearDown" << std::endl;
@@ -178,6 +180,55 @@ TEST_F(SocketManagerTest, Ut_ServerInitAll_Skip_Init_When_Env_Config)
178 EXPECT_NO_THROW(SocketManager::ServerInitAll(rankInfo));180 EXPECT_NO_THROW(SocketManager::ServerInitAll(rankInfo));
179}181}
180 182 
183+TEST_F(SocketManagerTest, Ut_ServerInitAll_When_AllRankPortsUnmatched_Expect_NoSocketOrPortChange)
184+{
185+ EnvHostNicConfig envConfig;
186+ EnvHostNicConfig& fakeEnvConfig = envConfig;
187+ fakeEnvConfig.hcclDeviceSocketPortRange = CfgField<std::vector<SocketPortRange>>{
188+ "HCCL_NPU_SOCKET_PORT_RANGE", {{16666, 18888}}, [](const std::string& s) -> std::vector<SocketPortRange> {
189+ return CastSocketPortRange(s, "HCCL_NPU_SOCKET_PORT_RANGE");
190+ }};
191+ fakeEnvConfig.hcclDeviceSocketPortRange.isParsed = true;
192+ MOCKER_CPP(&EnvConfig::GetHostNicConfig).stubs().will(returnValue(fakeEnvConfig));
193+ 
194+ string topoFilePath{HCOMM_CODE_ROOT_DIR "/test/legacy/ut/framework/communicator/topo2pclos.json"};
195+ MOCKER_CPP(&CommunicatorImpl::GetTopoFilePath).stubs().will(returnValue(topoFilePath));
196+ MOCKER(HrtGetDevice).stubs().will(returnValue(0));
197+ 
198+ RankGraphBuilder rankGraphBuilder;
199+ unique_ptr<RankGraph> graph = rankGraphBuilder.Build(RankTable2pClos, topoFilePath, 0);
200+ ASSERT_NE(nullptr, graph);
201+ NewRankInfo rankInfo = rankGraphBuilder.GetRankTableInfo()->ranks[0];
202+ auto phyTopoGraph = PhyTopo::GetInstance()->GetTopoGraph();
203+ ASSERT_NE(nullptr, phyTopoGraph);
204+ ASSERT_FALSE(phyTopoGraph->GetEdges(rankInfo.localId).empty());
205+ rankInfo.devicePort = 31000;
206+ std::vector<u32> expectedSocketPorts;
207+ u32 socketPort = 32000;
208+ for (auto& rankLevelInfo : rankInfo.rankLevelInfos) {
209+ for (auto& rankAddr : rankLevelInfo.rankAddrs) {
210+ rankAddr.ports = {"ut/unmatched/port"};
211+ rankAddr.socketPort_ = socketPort++;
212+ expectedSocketPorts.push_back(rankAddr.socketPort_);
213+ }
214+ }
215+ auto& serverSocketMap = SocketManager::GetServerSocketMap();
216+ const auto serverSocketCount = serverSocketMap.size();
217+ 
218+ EXPECT_NO_THROW(SocketManager::ServerInitAll(rankInfo));
219+ 
220+ EXPECT_EQ(serverSocketCount, serverSocketMap.size());
221+ EXPECT_EQ(31000, rankInfo.devicePort);
222+ size_t addrIndex = 0;
223+ for (const auto& rankLevelInfo : rankInfo.rankLevelInfos) {
224+ for (const auto& rankAddr : rankLevelInfo.rankAddrs) {
225+ ASSERT_LT(addrIndex, expectedSocketPorts.size());
226+ EXPECT_EQ(expectedSocketPorts[addrIndex++], rankAddr.socketPort_);
227+ }
228+ }
229+ EXPECT_EQ(expectedSocketPorts.size(), addrIndex);
230+}
231+ 
181TEST_F(SocketManagerTest, test_BatchCreateSockets_with_SocketConfig)232TEST_F(SocketManagerTest, test_BatchCreateSockets_with_SocketConfig)
182{233{
183 SocketManager socketMgr(localRank, devicePhyId, devicePhyId, "tmp");234 SocketManager socketMgr(localRank, devicePhyId, devicePhyId, "tmp");
@@ -292,6 +292,7 @@ const std::string RankTable4p = R"(
292}292}
293)";293)";
294 294 
295+// Physical topology does not define net_layer; network layers come from the rank table.
295const std::string Topo1Ser8Dev = R"(296const std::string Topo1Ser8Dev = R"(
296 {297 {
297 "version": "2.0",298 "version": "2.0",
@@ -313,7 +314,6 @@ const std::string Topo1Ser8Dev = R"(
313 "edge_count": 14,314 "edge_count": 14,
314 "edge_list": [315 "edge_list": [
315 {316 {
316- "net_layer": 0,
317 "link_type": "PEER2PEER",317 "link_type": "PEER2PEER",
318 "protocols": [318 "protocols": [
319 "UB_CTP"319 "UB_CTP"
@@ -329,7 +329,6 @@ const std::string Topo1Ser8Dev = R"(
329 "position": "DEVICE"329 "position": "DEVICE"
330 },330 },
331 {331 {
332- "net_layer": 0,
333 "link_type": "PEER2PEER",332 "link_type": "PEER2PEER",
334 "protocols": [333 "protocols": [
335 "UB_CTP"334 "UB_CTP"
@@ -345,7 +344,6 @@ const std::string Topo1Ser8Dev = R"(
345 "position": "DEVICE"344 "position": "DEVICE"
346 },345 },
347 {346 {
348- "net_layer": 0,
349 "link_type": "PEER2PEER",347 "link_type": "PEER2PEER",
350 "protocols": [348 "protocols": [
351 "UB_CTP"349 "UB_CTP"
@@ -361,7 +359,6 @@ const std::string Topo1Ser8Dev = R"(
361 "position": "DEVICE"359 "position": "DEVICE"
362 },360 },
363 {361 {
364- "net_layer": 0,
365 "link_type": "PEER2PEER",362 "link_type": "PEER2PEER",
366 "protocols": [363 "protocols": [
367 "UB_CTP"364 "UB_CTP"
@@ -377,7 +374,6 @@ const std::string Topo1Ser8Dev = R"(
377 "position": "DEVICE"374 "position": "DEVICE"
378 },375 },
379 {376 {
380- "net_layer": 0,
381 "link_type": "PEER2PEER",377 "link_type": "PEER2PEER",
382 "protocols": [378 "protocols": [
383 "UB_CTP"379 "UB_CTP"
@@ -393,7 +389,6 @@ const std::string Topo1Ser8Dev = R"(
393 "position": "DEVICE"389 "position": "DEVICE"
394 },390 },
395 {391 {
396- "net_layer": 0,
397 "link_type": "PEER2PEER",392 "link_type": "PEER2PEER",
398 "protocols": [393 "protocols": [
399 "UB_CTP"394 "UB_CTP"
@@ -409,7 +404,6 @@ const std::string Topo1Ser8Dev = R"(
409 "position": "DEVICE"404 "position": "DEVICE"
410 },405 },
411 {406 {
412- "net_layer": 1,
413 "link_type": "PEER2NET",407 "link_type": "PEER2NET",
414 "protocols": [408 "protocols": [
415 "UB_CTP"409 "UB_CTP"
@@ -422,7 +416,6 @@ const std::string Topo1Ser8Dev = R"(
422 "position": "DEVICE"416 "position": "DEVICE"
423 },417 },
424 {418 {
425- "net_layer": 1,
426 "link_type": "PEER2NET",419 "link_type": "PEER2NET",
427 "protocols": [420 "protocols": [
428 "UB_CTP"421 "UB_CTP"
@@ -435,7 +428,6 @@ const std::string Topo1Ser8Dev = R"(
435 "position": "DEVICE"428 "position": "DEVICE"
436 },429 },
437 {430 {
438- "net_layer": 1,
439 "link_type": "PEER2NET",431 "link_type": "PEER2NET",
440 "protocols": [432 "protocols": [
441 "UB_CTP"433 "UB_CTP"
@@ -448,7 +440,6 @@ const std::string Topo1Ser8Dev = R"(
448 "position": "DEVICE"440 "position": "DEVICE"
449 },441 },
450 {442 {
451- "net_layer": 1,
452 "link_type": "PEER2NET",443 "link_type": "PEER2NET",
453 "protocols": [444 "protocols": [
454 "UB_CTP"445 "UB_CTP"
@@ -461,7 +452,6 @@ const std::string Topo1Ser8Dev = R"(
461 "position": "DEVICE"452 "position": "DEVICE"
462 },453 },
463 {454 {
464- "net_layer": 2,
465 "link_type": "PEER2NET",455 "link_type": "PEER2NET",
466 "protocols": [456 "protocols": [
467 "UB_CTP"457 "UB_CTP"
@@ -474,7 +464,6 @@ const std::string Topo1Ser8Dev = R"(
474 "position": "HOST"464 "position": "HOST"
475 },465 },
476 {466 {
477- "net_layer": 2,
478 "link_type": "PEER2NET",467 "link_type": "PEER2NET",
479 "protocols": [468 "protocols": [
480 "UB_CTP"469 "UB_CTP"
@@ -487,7 +476,6 @@ const std::string Topo1Ser8Dev = R"(
487 "position": "HOST"476 "position": "HOST"
488 },477 },
489 {478 {
490- "net_layer": 2,
491 "link_type": "PEER2NET",479 "link_type": "PEER2NET",
492 "protocols": [480 "protocols": [
493 "UB_CTP"481 "UB_CTP"
@@ -500,7 +488,6 @@ const std::string Topo1Ser8Dev = R"(
500 "position": "HOST"488 "position": "HOST"
501 },489 },
502 {490 {
503- "net_layer": 2,
504 "link_type": "PEER2NET",491 "link_type": "PEER2NET",
505 "protocols": [492 "protocols": [
506 "UB_CTP"493 "UB_CTP"
@@ -10,6 +10,8 @@
10 10 
11#include <cstring>11#include <cstring>
12 12 
13+#include <hccl/hccl_types.h>
14+ 
13#include "hccp.h"15#include "hccp.h"
14#include "hccp_async.h"16#include "hccp_async.h"
15#include "hccp_ctx.h"17#include "hccp_ctx.h"
@@ -415,6 +417,22 @@ int RaGetDevEidInfoList(struct RaInfo info, struct HccpDevEidInfo info_list[], u
415 417 
416int RaGetDevBaseAttr(void* ctx_handle, struct DevBaseAttr* attr) { return 0; }418int RaGetDevBaseAttr(void* ctx_handle, struct DevBaseAttr* attr) { return 0; }
417 419 
420+// legacy UT ??? base_comm ???????? HCCP ????????
421+namespace hcomm {
422+ 
423+HcclResult HccpRaGetDevBaseAttr(void* ctxHandle, struct DevBaseAttr* attr)
424+{
425+ if (RaGetDevBaseAttr(ctxHandle, attr) != 0) {
426+ return HCCL_E_NETWORK;
427+ }
428+ if (attr != nullptr) {
429+ attr->ub.priorityInfo[0].tpType.bs.ctp = 1;
430+ }
431+ return HCCL_SUCCESS;
432+}
433+ 
434+} // namespace hcomm
435+ 
418int RaCtxUpdateCi(void* qp_handle, uint16_t ci) { return 0; }436int RaCtxUpdateCi(void* qp_handle, uint16_t ci) { return 0; }
419 437 
420int RaGetAsyncReqResult(void* req_handle, int* req_result) { return 0; }438int RaGetAsyncReqResult(void* req_handle, int* req_result) { return 0; }
@@ -85,8 +85,8 @@ namespace test {
85 std::initializer_list<std::string> localBPorts = {}, LinkProtocol protocol = LinkProtocol::UB_CTP,85 std::initializer_list<std::string> localBPorts = {}, LinkProtocol protocol = LinkProtocol::UB_CTP,
86 AddrPosition position = AddrPosition::DEVICE, u32 topoInstId = 0, TopoType topoType = TopoType::CLOS)86 AddrPosition position = AddrPosition::DEVICE, u32 topoInstId = 0, TopoType topoType = TopoType::CLOS)
87 {87 {
88+ (void)netLayer;
88 EdgeInfo edge;89 EdgeInfo edge;
89- edge.netLayer = netLayer;
90 edge.linkType = linkType;90 edge.linkType = linkType;
91 edge.topoType = topoType;91 edge.topoType = topoType;
92 edge.topoInstId = topoInstId;92 edge.topoInstId = topoInstId;
@@ -108,9 +108,7 @@ namespace test {
108 topo.peers.emplace_back(MakePeer(localId));108 topo.peers.emplace_back(MakePeer(localId));
109 }109 }
110 topo.edgeCount = edges.size();110 topo.edgeCount = edges.size();
111- for (const auto& edge : edges) {111+ topo.edges = edges;
112- topo.edges[edge.netLayer].push_back(edge);
113- }
114 return topo;112 return topo;
115 }113 }
116 114 
@@ -215,34 +215,26 @@ protected:
215 void TearDown() override {}215 void TearDown() override {}
216};216};
217 217 
218-TEST_F(PhyTopoTest, Ut_AddTopoGraph_When_TopoNotNullAndNetLayerNotExist_Expect_ReturnTopo)218+TEST_F(PhyTopoTest, Ut_AddTopoGraph_When_TopoNotNull_Expect_ReturnTopo)
219{219{
220 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();220 std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
221- u32 netLayer = 1;221+ phyTopo.AddTopoGraph(topo);
222- phyTopo.AddTopoGraph(netLayer, topo);222+ EXPECT_EQ(phyTopo.GetTopoGraph(), topo);
223- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer), topo);
224}223}
225 224 
226-TEST_F(PhyTopoTest, Ut_GetTopoGraph_When_NetLayerExist_Expect_ReturnTopo)225+TEST_F(PhyTopoTest, Ut_GetTopoGraph_When_TopoNotAdded_Expect_ReturnNullptr)
227{226{
228- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo1227+ EXPECT_EQ(phyTopo.GetTopoGraph(), nullptr);
229- = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
230- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo2
231- = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
232- u32 netLayer1 = 1;
233- u32 netLayer2 = 2;
234- phyTopo.AddTopoGraph(netLayer1, topo1);
235- phyTopo.AddTopoGraph(netLayer2, topo2);
236- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer1), topo1);
237- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer2), topo2);
238}228}
239 229 
240-TEST_F(PhyTopoTest, Ut_GetTopoGraph_When_NetLayerNoExist_Expect_ReturnNullptr)230+TEST_F(PhyTopoTest, Ut_Clear_When_TopoAdded_Expect_ResetTopoAndInitFlag)
241{231{
242- std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo1232+ std::shared_ptr<Graph<PhyTopo::Node, PhyTopo::Link>> topo = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
243- = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();233+ phyTopo.AddTopoGraph(topo);
244- u32 netLayer1 = 1;234+ phyTopo.InitFinish();
245- u32 netLayer2 = 2;235+ 
246- phyTopo.AddTopoGraph(netLayer1, topo1);236+ phyTopo.Clear();
247- EXPECT_EQ(phyTopo.GetTopoGraph(netLayer2), nullptr);237+ 
238+ EXPECT_EQ(phyTopo.GetTopoGraph(), nullptr);
239+ EXPECT_FALSE(phyTopo.IsInitFinished());
248}240}
@@ -91,13 +91,9 @@ std::unique_ptr<PhyTopo> PhyTopoBuilderBuildStub(const std::string& topoPath)
91 std::unique_ptr<PhyTopo> phyTopo = std::make_unique<PhyTopo>();91 std::unique_ptr<PhyTopo> phyTopo = std::make_unique<PhyTopo>();
92 PhyTopoBuilder phyTopoBuilder;92 PhyTopoBuilder phyTopoBuilder;
93 auto topoInfo = phyTopoBuilder.LoadTopoInfo(topoPath);93 auto topoInfo = phyTopoBuilder.LoadTopoInfo(topoPath);
94- // 根据topoInfo,按netLayer构造Graph94+ // topoInfo 中的全部物理边构造成一张 Graph。
95- for (const auto& iter : topoInfo->edges) {95+ auto graph = phyTopoBuilder.CreateGraph(topoInfo->edges);
96- auto netLayer = iter.first;96+ phyTopo->AddTopoGraph(graph);
97- auto graph = phyTopoBuilder.CreateGraph(iter.second);
98- phyTopo->AddTopoGraph(netLayer, graph);
99- HCCL_DEBUG("[PhyTopoBuilder::%s]Build netLayer[%u] topo graph success.", __func__, netLayer);
100- }
101 return phyTopo;97 return phyTopo;
102}98}
103 99 
@@ -117,10 +113,15 @@ protected:
117 113 
118 static void TearDownTestCase() { std::cout << "PhyTopoBuilderTest TearDown" << std::endl; }114 static void TearDownTestCase() { std::cout << "PhyTopoBuilderTest TearDown" << std::endl; }
119 115 
120- virtual void SetUp() { std::cout << "A Test case in PhyTopoBuilderTest SetUP" << std::endl; }116+ virtual void SetUp()
117+ {
118+ PhyTopo::GetInstance()->Clear();
119+ std::cout << "A Test case in PhyTopoBuilderTest SetUP" << std::endl;
120+ }
121 121 
122 virtual void TearDown()122 virtual void TearDown()
123 {123 {
124+ PhyTopo::GetInstance()->Clear();
124 GlobalMockObject::verify();125 GlobalMockObject::verify();
125 std::cout << "A Test case in PhyTopoBuilderTest TearDown" << std::endl;126 std::cout << "A Test case in PhyTopoBuilderTest TearDown" << std::endl;
126 }127 }
@@ -156,7 +157,7 @@ TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_ValidTopoPath_Expect_ReturnEdg
156 std::string topoPath = "./topo_stub";157 std::string topoPath = "./topo_stub";
157 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoStub));158 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoStub));
158 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);159 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);
159- auto graph = phyTopo->GetTopoGraph(0);160+ auto graph = phyTopo->GetTopoGraph();
160 size_t totalEdgeNum = 0;161 size_t totalEdgeNum = 0;
161 162 
162 // 遍历所有源节点163 // 遍历所有源节点
@@ -169,24 +170,41 @@ TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_ValidTopoPath_Expect_ReturnEdg
169 }170 }
170 }171 }
171 172 
172- EXPECT_EQ(totalEdgeNum, 6);173+ EXPECT_EQ(totalEdgeNum, 8);
173}174}
174 175 
175-TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_EdgeRepeat_Expect_ReturnEdgeNum)176+TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_EdgeRepeat_Expect_KeepInputEdges)
176{177{
177 std::string topoPath = "./test_topo_stub";178 std::string topoPath = "./test_topo_stub";
178 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoWithRepeatEdge));179 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoWithRepeatEdge));
179- std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);180+ std::unique_ptr<PhyTopo> phyTopo;
180- auto graph = phyTopo->GetTopoGraph(0);181+ EXPECT_NO_THROW(phyTopo = PhyTopoBuilderBuildStub(topoPath));
182+ ASSERT_NE(phyTopo, nullptr);
183+ auto graph = phyTopo->GetTopoGraph();
181 ASSERT_NE(graph, nullptr);184 ASSERT_NE(graph, nullptr);
185+ // TopoInfo 解析阶段负责去重;建图阶段按输入边构建双向物理边。
186+ EXPECT_EQ(graph->GetEdges(PhyTopo::Peer::GetId(0), PhyTopo::Peer::GetId(1)).size(), 2);
187+ EXPECT_EQ(graph->GetEdges(PhyTopo::Peer::GetId(1), PhyTopo::Peer::GetId(0)).size(), 2);
188+}
182 189 
183- size_t totalEdgeNum = 0;190+TEST_F(PhyTopoBuilderTest, Ut_BuildPhyTopo_When_NoEdges_Expect_KeepIsolatedPeers)
184- for (const auto& srcEntry : graph->edges) {191+{
185- for (const auto& dstEntry : srcEntry.second) {192+ TopoInfo topoInfo;
186- totalEdgeNum += dstEntry.second.size();193+ topoInfo.version = "2.0";
187- }194+ topoInfo.peerCount = 3;
195+ for (u32 localId = 0; localId < topoInfo.peerCount; ++localId) {
196+ PeerInfo peer;
197+ peer.localId = localId;
198+ topoInfo.peers.emplace_back(peer);
188 }199 }
189- EXPECT_EQ(totalEdgeNum, 4);200+ 
201+ PhyTopoBuilder phyTopoBuilder;
202+ phyTopoBuilder.BuildPhyTopo(topoInfo);
203+ 
204+ auto graph = PhyTopo::GetInstance()->GetTopoGraph();
205+ ASSERT_NE(graph, nullptr);
206+ EXPECT_EQ(graph->nodes.size(), 3);
207+ EXPECT_TRUE(graph->edges.empty());
190}208}
191 209 
192TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_DiffProtocols_Expect_ReturnEdgeNum)210TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_DiffProtocols_Expect_ReturnEdgeNum)
@@ -194,7 +212,7 @@ TEST_F(PhyTopoBuilderTest, Ut_PhyTopoBuilder_When_DiffProtocols_Expect_ReturnEdg
194 std::string topoPath = "./topo_stub";212 std::string topoPath = "./topo_stub";
195 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoWithDiffProtocols));213 MOCKER_CPP(&PhyTopoBuilder::LoadTopoInfo).stubs().will(invoke(LoadTopoInfoWithDiffProtocols));
196 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);214 std::unique_ptr<PhyTopo> phyTopo = PhyTopoBuilderBuildStub(topoPath);
197- auto graph = phyTopo->GetTopoGraph(0);215+ auto graph = phyTopo->GetTopoGraph();
198 size_t totalEdgeNum = 0;216 size_t totalEdgeNum = 0;
199 217 
200 // 遍历所有源节点218 // 遍历所有源节点
@@ -526,6 +526,79 @@ TEST_F(RankGraphTest, ut_GetEndpointDesc_When_Normal_Expect_SUCCESS)
526 EXPECT_EQ(ret, HCCL_SUCCESS);526 EXPECT_EQ(ret, HCCL_SUCCESS);
527}527}
528 528 
529+TEST_F(RankGraphTest, ut_GetEndpointInfo_When_SameEndpointAcrossLayers_Expect_LayerSpecificBwCoeff)
530+{
531+ constexpr u32 topoInstId = 0;
532+ constexpr u32 layer1 = 1;
533+ constexpr u32 layer2 = 2;
534+ RankGraph rankGraph(myRank);
535+ auto peer = createPeer(myRank);
536+ rankGraph.AddPeer(peer);
537+ 
538+ IpAddress endpointAddr("192.168.1.1");
539+ CommAddr commAddr{};
540+ commAddr.type = COMM_ADDR_TYPE_IP_V4;
541+ commAddr.addr = endpointAddr.GetBinaryAddress().addr;
542+ std::set<LinkProtocol> protocols = {LinkProtocol::UB_CTP};
543+ auto layer1Iface = std::make_shared<NetInstance::ConnInterface>(
544+ endpointAddr, std::set<std::string>{"1/0"}, AddrPosition::DEVICE, LinkType::PEER2NET, protocols, TopoType::CLOS,
545+ topoInstId);
546+ auto layer2Iface = std::make_shared<NetInstance::ConnInterface>(
547+ endpointAddr, std::set<std::string>{"2/0", "2/1"}, AddrPosition::DEVICE, LinkType::PEER2NET, protocols,
548+ TopoType::CLOS, topoInstId);
549+ peer->AddConnInterface(layer1, layer1Iface);
550+ peer->AddConnInterface(layer2, layer2Iface);
551+ peer->SetEndpointToIface(layer1, topoInstId, commAddr, COMM_PROTOCOL_UBC_CTP, layer1Iface);
552+ peer->SetEndpointToIface(layer2, topoInstId, commAddr, COMM_PROTOCOL_UBC_CTP, layer2Iface);
553+ 
554+ EndpointDesc layer1Desc;
555+ EndpointDesc layer2Desc;
556+ uint32_t descNum = 1;
557+ ASSERT_EQ(rankGraph.GetEndpointDesc(layer1, topoInstId, &descNum, &layer1Desc), HCCL_SUCCESS);
558+ ASSERT_EQ(descNum, 1);
559+ u32 descNetLayer = UINT32_MAX;
560+ u32 descTopoInstId = UINT32_MAX;
561+ ASSERT_TRUE(GetEndpointTopoInfo(layer1Desc, descNetLayer, descTopoInstId));
562+ EXPECT_EQ(descNetLayer, layer1);
563+ EXPECT_EQ(descTopoInstId, topoInstId);
564+ descNum = 1;
565+ ASSERT_EQ(rankGraph.GetEndpointDesc(layer2, topoInstId, &descNum, &layer2Desc), HCCL_SUCCESS);
566+ ASSERT_EQ(descNum, 1);
567+ ASSERT_TRUE(GetEndpointTopoInfo(layer2Desc, descNetLayer, descTopoInstId));
568+ EXPECT_EQ(descNetLayer, layer2);
569+ EXPECT_EQ(descTopoInstId, topoInstId);
570+ 
571+ EndpointDesc copiedLayer2Desc;
572+ ASSERT_EQ(EndpointDescInit(&copiedLayer2Desc, 1), HCCL_SUCCESS);
573+ copiedLayer2Desc.protocol = layer2Desc.protocol;
574+ copiedLayer2Desc.commAddr = layer2Desc.commAddr;
575+ copiedLayer2Desc.loc = layer2Desc.loc;
576+ ASSERT_TRUE(GetEndpointTopoInfo(copiedLayer2Desc, descNetLayer, descTopoInstId));
577+ EXPECT_EQ(descNetLayer, layer2);
578+ EXPECT_EQ(descTopoInstId, topoInstId);
579+ 
580+ EndpointAttrBwCoeff layer1BwCoeff = 0;
581+ EndpointAttrBwCoeff layer2BwCoeff = 0;
582+ EXPECT_EQ(
583+ rankGraph.GetEndpointInfo(myRank, &layer1Desc, ENDPOINT_ATTR_BW_COEFF, sizeof(layer1BwCoeff), &layer1BwCoeff),
584+ HCCL_SUCCESS);
585+ EXPECT_EQ(
586+ rankGraph.GetEndpointInfo(
587+ myRank, &copiedLayer2Desc, ENDPOINT_ATTR_BW_COEFF, sizeof(layer2BwCoeff), &layer2BwCoeff),
588+ HCCL_SUCCESS);
589+ EXPECT_EQ(layer1BwCoeff, 1);
590+ EXPECT_EQ(layer2BwCoeff, 2);
591+ 
592+ EndpointDesc legacyDesc;
593+ ASSERT_EQ(EndpointDescInit(&legacyDesc, 1), HCCL_SUCCESS);
594+ legacyDesc.commAddr = layer1Desc.commAddr;
595+ legacyDesc.protocol = layer1Desc.protocol;
596+ legacyDesc.loc.locType = layer1Desc.loc.locType;
597+ EXPECT_EQ(
598+ rankGraph.GetEndpointInfo(myRank, &legacyDesc, ENDPOINT_ATTR_BW_COEFF, sizeof(layer1BwCoeff), &layer1BwCoeff),
599+ HCCL_E_PARA);
600+}
601+ 
529TEST_F(RankGraphTest, ut_AddGroupLinks_When_1pNormal_Expect_SUCCESS)602TEST_F(RankGraphTest, ut_AddGroupLinks_When_1pNormal_Expect_SUCCESS)
530{603{
531 auto rankGraph = create4pRankGraph(myRank);604 auto rankGraph = create4pRankGraph(myRank);
@@ -51,6 +51,52 @@ protected:
51 }51 }
52};52};
53 53 
54+TEST_F(RankGraph64Plus1Test, Ut_GetPeer2PlaneEdges_When_MultiPortNoiseNotInLayer0_Expect_Ignored)
55+{
56+ auto phyTopoGraph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
57+ auto phyPeer = std::make_shared<PhyTopo::Peer>(64);
58+ auto phyFabric = std::make_shared<PhyTopo::Fabric>();
59+ const NodeId peerNodeId = PhyTopo::Peer::GetId(64);
60+ const NodeId fabricNodeId = PhyTopo::Fabric::GetId();
61+ phyTopoGraph->AddNode(peerNodeId, phyPeer);
62+ phyTopoGraph->AddNode(fabricNodeId, phyFabric);
63+ 
64+ auto rankPeer = std::make_shared<NetInstance::Peer>(0, 64, 64, 0);
65+ const std::vector<std::set<std::string>> physicalPlanePortGroups = {
66+ {"0/0", "0/1", "0/2", "0/3"},
67+ {"0/4", "0/5", "0/6", "0/7"},
68+ {"1/0", "1/1", "1/2", "1/3"},
69+ {"1/4", "1/5", "1/6", "1/7"},
70+ };
71+ std::map<std::string, std::vector<IpAddress>> layer0PortAddrMap;
72+ layer0PortAddrMap["1/0"] = {IpAddress("192.168.0.1")};
73+ rankPeer->SetPortPortAddrMapLayer0(layer0PortAddrMap);
74+ 
75+ PhyTopo::LinkAttributes linkAttrs;
76+ linkAttrs.linktype = LinkType::PEER2NET;
77+ linkAttrs.protocols = {LinkProtocol::UB_CTP};
78+ for (u32 planeId = 0; planeId < static_cast<u32>(physicalPlanePortGroups.size()); ++planeId) {
79+ auto edge = std::make_shared<PhyTopo::Link>(phyPeer, phyFabric, linkAttrs, TopoType::CLOS, planeId);
80+ edge->SetSourceIface(std::make_shared<PhyTopo::ConnInterface>(
81+ physicalPlanePortGroups[planeId], AddrPosition::DEVICE, LinkType::PEER2NET, linkAttrs.protocols));
82+ phyTopoGraph->AddEdge(peerNodeId, fabricNodeId, edge);
83+ }
84+ 
85+ auto noiseEdge = std::make_shared<PhyTopo::Link>(phyPeer, phyFabric, linkAttrs, TopoType::CLOS, 2);
86+ noiseEdge->SetSourceIface(std::make_shared<PhyTopo::ConnInterface>(
87+ std::set<std::string>{"9/0", "9/1", "9/2", "9/3"}, AddrPosition::DEVICE, LinkType::PEER2NET,
88+ linkAttrs.protocols));
89+ phyTopoGraph->AddEdge(peerNodeId, fabricNodeId, noiseEdge);
90+ 
91+ UpdaterFor64Plus1 updater;
92+ std::shared_ptr<PhyTopo::Link> matchedEdge;
93+ EXPECT_NO_THROW(
94+ matchedEdge
95+ = updater.GetPeer2PlaneEdges(2, rankPeer, phyTopoGraph, BACKUP_TO_PLANE_ADDR_NUM, linkAttrs.protocols));
96+ ASSERT_NE(matchedEdge, nullptr);
97+ EXPECT_EQ(matchedEdge->GetTopoInstId(), 2);
98+}
99+ 
54TEST_F(RankGraph64Plus1Test, test_4p_without_backup)100TEST_F(RankGraph64Plus1Test, test_4p_without_backup)
55{101{
56 // ranktable不使用备份, topo文件也无备份信息102 // ranktable不使用备份, topo文件也无备份信息
@@ -116,14 +162,24 @@ TEST_F(RankGraph64Plus1Test, test_RankGraph_Build_without_Backup)
116 EXPECT_EQ(rankGraph->peers_[i]->GetNodeId(), i);162 EXPECT_EQ(rankGraph->peers_[i]->GetNodeId(), i);
117 EXPECT_EQ(rankGraph->peers_[i]->GetLevels().size(), 2);163 EXPECT_EQ(rankGraph->peers_[i]->GetLevels().size(), 2);
118 }164 }
165+ // topo 中 net_layer=99 的 0/9 噪声端口不能污染 rankTable 定义的 layer 0 接口
166+ for (const auto& rankPeer : rankGraph->peers_) {
167+ const auto layer0Ifaces = rankPeer.second->GetIfacesByLayer(0);
168+ EXPECT_FALSE(layer0Ifaces.empty());
169+ for (const auto& iface : layer0Ifaces) {
170+ ASSERT_NE(nullptr, iface);
171+ EXPECT_EQ(0, iface->GetPorts().count("0/9"));
172+ }
173+ }
119 // check fabGroups174 // check fabGroups
120 // check level0 az0-rack0175 // check level0 az0-rack0
121 NetInstance* netInstL0 = rankGraph->GetNetInstanceByNetInstId(0, "az0-rack0");176 NetInstance* netInstL0 = rankGraph->GetNetInstanceByNetInstId(0, "az0-rack0");
122 EXPECT_NE(netInstL0, nullptr);177 EXPECT_NE(netInstL0, nullptr);
123 EXPECT_EQ(netInstL0->rankIds, expectRanks);178 EXPECT_EQ(netInstL0->rankIds, expectRanks);
124 EXPECT_EQ(netInstL0->peers.size(), 4);179 EXPECT_EQ(netInstL0->peers.size(), 4);
125- EXPECT_EQ(netInstL0->fabrics.size(), 4);180+ ASSERT_EQ(netInstL0->fabrics.size(), 1);
126- EXPECT_EQ(netInstL0->vGraph.nodes.size(), 8);181+ EXPECT_EQ(netInstL0->vGraph.nodes.size(), 5);
182+ EXPECT_EQ(netInstL0->fabrics[0]->GetPlaneId(), "0");
127 183 
128 for (u32 i = 1; i < expectRanks.size() - 1; i++) {184 for (u32 i = 1; i < expectRanks.size() - 1; i++) {
129 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);185 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);
@@ -168,8 +224,8 @@ TEST_F(RankGraph64Plus1Test, test_RankGraph_Build_with_Backup)
168 EXPECT_NE(netInstL0, nullptr);224 EXPECT_NE(netInstL0, nullptr);
169 EXPECT_EQ(netInstL0->rankIds, expectRanks);225 EXPECT_EQ(netInstL0->rankIds, expectRanks);
170 EXPECT_EQ(netInstL0->peers.size(), 4);226 EXPECT_EQ(netInstL0->peers.size(), 4);
171- EXPECT_EQ(netInstL0->fabrics.size(), 4); // netLayer0支持peer2net的边rankGraph会有4个fabric227+ EXPECT_EQ(netInstL0->fabrics.size(), 1); // rankTable未配置plane_id,所有地址归入默认plane 0
172- EXPECT_EQ(netInstL0->vGraph.nodes.size(), 8);228+ EXPECT_EQ(netInstL0->vGraph.nodes.size(), 5);
173 for (u32 i = 1; i < expectRanks.size() - 1; i++) {229 for (u32 i = 1; i < expectRanks.size() - 1; i++) {
174 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);230 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);
175 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->target_->GetNodeId(), i);231 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->target_->GetNodeId(), i);
@@ -214,8 +270,8 @@ TEST_F(RankGraph64Plus1Test, test_checkpoint_normal_to_backup)
214 EXPECT_NE(netInstL0, nullptr);270 EXPECT_NE(netInstL0, nullptr);
215 EXPECT_EQ(netInstL0->rankIds, expectRanks);271 EXPECT_EQ(netInstL0->rankIds, expectRanks);
216 EXPECT_EQ(netInstL0->peers.size(), 4);272 EXPECT_EQ(netInstL0->peers.size(), 4);
217- EXPECT_EQ(netInstL0->fabrics.size(), 4);273+ EXPECT_EQ(netInstL0->fabrics.size(), 1);
218- EXPECT_EQ(netInstL0->vGraph.nodes.size(), 8);274+ EXPECT_EQ(netInstL0->vGraph.nodes.size(), 5);
219 for (u32 i = 1; i < expectRanks.size() - 1; i++) {275 for (u32 i = 1; i < expectRanks.size() - 1; i++) {
220 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);276 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);
221 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->target_->GetNodeId(), i);277 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->target_->GetNodeId(), i);
@@ -259,8 +315,8 @@ TEST_F(RankGraph64Plus1Test, test_checkpoint_normal_switch_pod_without_backup)
259 EXPECT_NE(netInstL0, nullptr);315 EXPECT_NE(netInstL0, nullptr);
260 EXPECT_EQ(netInstL0->rankIds, expectRanks);316 EXPECT_EQ(netInstL0->rankIds, expectRanks);
261 EXPECT_EQ(netInstL0->peers.size(), 4);317 EXPECT_EQ(netInstL0->peers.size(), 4);
262- EXPECT_EQ(netInstL0->fabrics.size(), 4);318+ EXPECT_EQ(netInstL0->fabrics.size(), 1);
263- EXPECT_EQ(netInstL0->vGraph.nodes.size(), 8);319+ EXPECT_EQ(netInstL0->vGraph.nodes.size(), 5);
264 for (u32 i = 1; i < expectRanks.size() - 1; i++) {320 for (u32 i = 1; i < expectRanks.size() - 1; i++) {
265 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);321 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->source_->GetNodeId(), 0);
266 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->target_->GetNodeId(), i);322 EXPECT_EQ(netInstL0->vGraph.edges[0][i][0]->target_->GetNodeId(), i);
@@ -9,15 +9,32 @@
9 */9 */
10 10 
11#include "gtest/gtest.h"11#include "gtest/gtest.h"
12+ 
13+#include <initializer_list>
14+#include <iostream>
15+#include <set>
16+#include <string>
17+#include <unistd.h>
18+#include <utility>
19+#include <vector>
20+ 
12#include <mockcpp/mokc.h>21#include <mockcpp/mokc.h>
13#include <mockcpp/mockcpp.hpp>22#include <mockcpp/mockcpp.hpp>
14-#include <iostream>23+ 
15-#include <unistd.h>24+#include <hccl/hccl_types.h>
25+ 
26+#include "hccp_ctx.h"
27+#include "rdma_handle_manager.h"
28+ 
29+namespace hcomm {
30+HcclResult HccpRaGetDevBaseAttr(void* ctxHandle, struct DevBaseAttr* attr);
31+}
16 32 
17#define private public33#define private public
18#define protected public34#define protected public
19 35 
20#include "detour_service.h"36#include "detour_service.h"
37+#include "orion_adapter_hccp.h"
21#include "phy_topo.h"38#include "phy_topo.h"
22#include "phy_topo_builder.h"39#include "phy_topo_builder.h"
23#include "rank_graph_test_data_builder.h"40#include "rank_graph_test_data_builder.h"
@@ -29,6 +46,130 @@
29 46 
30using namespace Hccl;47using namespace Hccl;
31 48 
49+namespace {
50+AddressInfo MakeEidAddress(const std::string& eid, std::initializer_list<std::string> ports, const std::string& planeId)
51+{
52+ AddressInfo address;
53+ address.addr = IpAddress(IpAddress::StrToEID(eid));
54+ address.addrType = AddrType::EID;
55+ address.ports = std::set<std::string>(ports.begin(), ports.end());
56+ address.planeId = planeId;
57+ return address;
58+}
59+ 
60+std::vector<AddressInfo> MakeOverlappedUbAddresses(u32 rankId, LinkProtocol protocol)
61+{
62+ const std::string eid0 = rankId == 0U ? "00000000000000000000000000000001" : "00000000000000000000000000000011";
63+ const std::string eid1 = rankId == 0U ? "00000000000000000000000000000002" : "00000000000000000000000000000012";
64+ if (protocol == LinkProtocol::UB_CTP) {
65+ return {
66+ MakeEidAddress(eid0, {"0/0", "0/1", "0/2", "0/3", "0/4", "0/5"}, "planeA"),
67+ MakeEidAddress(eid1, {"0/6", "0/7"}, "planeB"),
68+ };
69+ }
70+ return {
71+ MakeEidAddress(eid0, {"0/0", "0/1"}, "planeA"),
72+ MakeEidAddress(eid1, {"0/6", "0/7"}, "planeB"),
73+ };
74+}
75+ 
76+RankTableInfo MakeOverlappedUbRankTable(u32 netLayer, LinkProtocol protocol)
77+{
78+ return test::MakeRankTable({
79+ test::MakeRankInfo(
80+ 0, 0, 0,
81+ {
82+ test::MakeRankLevel(
83+ 0, "inner", NetType::TOPO_FILE_DESC,
84+ {
85+ test::MakeAddress("192.168.0.1", {"1/0"}),
86+ }),
87+ test::MakeRankLevel(netLayer, "all", NetType::CLOS, MakeOverlappedUbAddresses(0, protocol)),
88+ }),
89+ test::MakeRankInfo(
90+ 1, 1, 1,
91+ {
92+ test::MakeRankLevel(
93+ 0, "inner", NetType::TOPO_FILE_DESC,
94+ {
95+ test::MakeAddress("192.168.0.2", {"1/1"}),
96+ }),
97+ test::MakeRankLevel(netLayer, "all", NetType::CLOS, MakeOverlappedUbAddresses(1, protocol)),
98+ }),
99+ });
100+}
101+ 
102+RankTableInfo MakeOverlappedUbRankTableForLayer1And2()
103+{
104+ RankTableInfo rankTable = MakeOverlappedUbRankTable(1, LinkProtocol::UB_CTP);
105+ for (auto& rankInfo : rankTable.ranks) {
106+ rankInfo.rankLevelInfos.emplace_back(test::MakeRankLevel(
107+ 2, "all-layer2", NetType::CLOS, MakeOverlappedUbAddresses(rankInfo.rankId, LinkProtocol::UB_CTP)));
108+ }
109+ return rankTable;
110+}
111+ 
112+TopoInfo MakeOverlappedUbTopo(bool addLocalTpEdge = true, bool addDuplicateCtpEdge = false)
113+{
114+ std::vector<EdgeInfo> edges = {
115+ test::MakeEdge(0, LinkType::PEER2PEER, 0, {"1/0"}, 1, {"1/1"}),
116+ };
117+ for (u32 localId = 0U; localId < 2U; ++localId) {
118+ EdgeInfo ctpEdge
119+ = test::MakeEdge(0, LinkType::PEER2NET, localId, {"0/0", "0/1", "0/2", "0/3", "0/4", "0/5", "0/6", "0/7"});
120+ ctpEdge.protocols = {LinkProtocol::UB_CTP, LinkProtocol::UB_MEM};
121+ if (addDuplicateCtpEdge) {
122+ EdgeInfo duplicateCtpEdge = ctpEdge;
123+ duplicateCtpEdge.topoInstId = 8;
124+ edges.emplace_back(std::move(duplicateCtpEdge));
125+ }
126+ edges.emplace_back(std::move(ctpEdge));
127+ if (addLocalTpEdge || localId != 0U) {
128+ edges.emplace_back(test::MakeEdge(
129+ 0, LinkType::PEER2NET, localId, {"0/0", "0/1", "0/6", "0/7"}, 0, {}, LinkProtocol::UB_TP));
130+ }
131+ }
132+ return test::MakeTopoInfo({0, 1}, edges);
133+}
134+ 
135+void MockDevBaseAttr(DevBaseAttr* devBaseAttr, u32 callCount = 2U)
136+{
137+ MOCKER_CPP(&RdmaHandleManager::GetByIp).stubs().will(returnValue(static_cast<RdmaHandle>(devBaseAttr)));
138+ MOCKER(hcomm::HccpRaGetDevBaseAttr)
139+ .expects(exactly(callCount))
140+ .with(mockcpp::any(), outBoundP(devBaseAttr, sizeof(*devBaseAttr)))
141+ .will(returnValue(HCCL_SUCCESS));
142+}
143+ 
144+void CheckOverlappedUbPaths(
145+ const RankGraph& rankGraph, u32 netLayer, const std::set<LinkProtocol>& expectedProtocols,
146+ const std::multiset<size_t>& expectedPortCounts)
147+{
148+ const std::vector<NetInstance::Path> paths = rankGraph.GetPaths(netLayer, 0, 1);
149+ ASSERT_EQ(2, paths.size());
150+ std::multiset<size_t> portCounts;
151+ for (const auto& path : paths) {
152+ ASSERT_EQ(2, path.links.size());
153+ EXPECT_EQ(expectedProtocols, path.links[0].GetLinkProtocols());
154+ EXPECT_EQ(expectedProtocols, path.links[1].GetLinkProtocols());
155+ ASSERT_NE(nullptr, path.links[0].GetSourceIface());
156+ portCounts.emplace(path.links[0].GetSourceIface()->GetPorts().size());
157+ }
158+ EXPECT_EQ(expectedPortCounts, portCounts);
159+}
160+ 
161+void CheckSingleTopoInst(const RankGraph& rankGraph, u32 netLayer)
162+{
163+ const NetInstance* netInst = rankGraph.GetNetInstanceByRankId(netLayer, 0);
164+ ASSERT_NE(nullptr, netInst);
165+ std::vector<u32> topoInstIds;
166+ u32 topoInstNum = 0U;
167+ netInst->GetTopoInstsByLayer(topoInstIds, topoInstNum);
168+ EXPECT_EQ(1U, topoInstNum);
169+ EXPECT_EQ((std::vector<u32>{0U}), topoInstIds);
170+}
171+} // namespace
172+ 
32class RankGraphBuilderTest : public testing::Test {173class RankGraphBuilderTest : public testing::Test {
33protected:174protected:
34 static void SetUpTestCase() { std::cout << "RankGraphBuilderTest SetUP" << std::endl; }175 static void SetUpTestCase() { std::cout << "RankGraphBuilderTest SetUP" << std::endl; }
@@ -105,7 +246,7 @@ TEST_F(RankGraphBuilderTest, Ut_Build_When_OnePTopoFileWithoutEdge_Expect_Succes
105 PhyTopo::GetInstance()->Clear();246 PhyTopo::GetInstance()->Clear();
106 auto graph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();247 auto graph = std::make_shared<Graph<PhyTopo::Node, PhyTopo::Link>>();
107 graph->AddNode(PhyTopo::Peer::GetId(0), std::make_shared<PhyTopo::Peer>(0));248 graph->AddNode(PhyTopo::Peer::GetId(0), std::make_shared<PhyTopo::Peer>(0));
108- PhyTopo::GetInstance()->AddTopoGraph(0, graph);249+ PhyTopo::GetInstance()->AddTopoGraph(graph);
109 PhyTopo::GetInstance()->InitFinish();250 PhyTopo::GetInstance()->InitFinish();
110 RankGraphBuilder rankGraphBuilder;251 RankGraphBuilder rankGraphBuilder;
111 std::unique_ptr<RankGraph> rankGraph252 std::unique_ptr<RankGraph> rankGraph
@@ -118,14 +259,17 @@ TEST_F(RankGraphBuilderTest, Ut_Build_When_OnePTopoFileWithoutEdge_Expect_Succes
118 EXPECT_EQ(peer->GetLocalId(), 0);259 EXPECT_EQ(peer->GetLocalId(), 0);
119}260}
120 261 
121-TEST_F(RankGraphBuilderTest, Ut_BuildFromRankTable_When_NetLayerInconsistent_Expect_InvalidParamsException)262+TEST_F(RankGraphBuilderTest, Ut_BuildFromRankTable_When_NetLayerMissingInTopo_Expect_Success)
122{263{
123 // 校验BuildFromRankTable的Add(RankId, Peer)264 // 校验BuildFromRankTable的Add(RankId, Peer)
124 // when265 // when
125 MOCKER_CPP(&PhyTopoBuilder::Build).stubs().with(mockcpp::any()).will(ignoreReturnValue());266 MOCKER_CPP(&PhyTopoBuilder::Build).stubs().with(mockcpp::any()).will(ignoreReturnValue());
267+ // 本用例只验证 RankTable 建图,不依赖物理拓扑构建。
268+ MOCKER_CPP(&RankGraphBuilder::AddTopoDescFabricInfo).stubs().will(ignoreReturnValue());
126 MOCKER_CPP(&RankGraph::InitInnerRanks).stubs().will(ignoreReturnValue());269 MOCKER_CPP(&RankGraph::InitInnerRanks).stubs().will(ignoreReturnValue());
127 MOCKER_CPP(&DetourService::InsertDetourLinks).stubs().with(mockcpp::any()).will(ignoreReturnValue());270 MOCKER_CPP(&DetourService::InsertDetourLinks).stubs().with(mockcpp::any()).will(ignoreReturnValue());
128 MOCKER_CPP(&RankGraphBuilder::BuildPeer2PeerLinks).stubs().will(ignoreReturnValue());271 MOCKER_CPP(&RankGraphBuilder::BuildPeer2PeerLinks).stubs().will(ignoreReturnValue());
272+ MOCKER_CPP(&RankGraphBuilder::UpdateTopoInstForMyRankOnly).stubs().will(ignoreReturnValue());
129 MOCKER_CPP(&RankGraphBuilder::AddFabricInfo).stubs().will(ignoreReturnValue());273 MOCKER_CPP(&RankGraphBuilder::AddFabricInfo).stubs().will(ignoreReturnValue());
130 // then274 // then
131 RankGraphBuilder rankGraphBuilder;275 RankGraphBuilder rankGraphBuilder;
@@ -135,20 +279,26 @@ TEST_F(RankGraphBuilderTest, Ut_BuildFromRankTable_When_NetLayerInconsistent_Exp
135 {279 {
136 test::MakeAddress("192.168.200.1", {"0/1"}),280 test::MakeAddress("192.168.200.1", {"0/1"}),
137 }));281 }));
138- EXPECT_THROW(rankGraphBuilder.Build(rankTable, "topo.json", 0), InvalidParamsException);282+ std::unique_ptr<RankGraph> rankGraph;
283+ EXPECT_NO_THROW(rankGraph = rankGraphBuilder.Build(rankTable, "topo.json", 0));
284+ EXPECT_NE(rankGraph, nullptr);
139}285}
140 286 
141-TEST_F(RankGraphBuilderTest, ut_Build_When_4pRankTable_Expect_Success)287+TEST_F(RankGraphBuilderTest, Ut_Build_When_TopoWithoutNetLayer_Expect_UseRankTableLayers)
142{288{
143 PhyTopo::GetInstance()->Clear();289 PhyTopo::GetInstance()->Clear();
144 RankGraphBuilder rankGraphBuilder;290 RankGraphBuilder rankGraphBuilder;
145 std::unique_ptr<RankGraph> rankGraph291 std::unique_ptr<RankGraph> rankGraph
146 = rankGraphBuilder.RecoverBuild(test::MakeRankTable4pForBuilder(), test::MakeFourPeerBuilderTopo(), 0);292 = rankGraphBuilder.RecoverBuild(test::MakeRankTable4pForBuilder(), test::MakeFourPeerBuilderTopo(), 0);
147- EXPECT_NE(nullptr, rankGraph);293+ ASSERT_NE(nullptr, rankGraph);
294+ const std::set<u32> expectedLevels = {0, 1, 2};
295+ EXPECT_EQ(3, rankGraph->GetLevelNum());
296+ EXPECT_EQ(expectedLevels, rankGraph->GetLevels(0));
148 std::vector<std::string> netIds = {"az0-rack0", "az0", "all"};297 std::vector<std::string> netIds = {"az0-rack0", "az0", "all"};
149- for (s32 rankId = 0; rankId < 3; rankId++) {298+ for (s32 rankId = 0; rankId < 4; rankId++) {
150 for (u32 netLayer = 0; netLayer < 3; netLayer++) {299 for (u32 netLayer = 0; netLayer < 3; netLayer++) {
151 const NetInstance* fabGroup = rankGraph->GetNetInstanceByRankId(netLayer, rankId);300 const NetInstance* fabGroup = rankGraph->GetNetInstanceByRankId(netLayer, rankId);
301+ ASSERT_NE(nullptr, fabGroup);
152 EXPECT_EQ(netIds[netLayer], fabGroup->GetNetInstId());302 EXPECT_EQ(netIds[netLayer], fabGroup->GetNetInstId());
153 303 
154 EXPECT_EQ(true, fabGroup->HasNode(NetInstance::Peer(rankId, 0, 0, 0).GetLocalId()));304 EXPECT_EQ(true, fabGroup->HasNode(NetInstance::Peer(rankId, 0, 0, 0).GetLocalId()));
@@ -162,6 +312,11 @@ TEST_F(RankGraphBuilderTest, ut_Build_When_4pRankTable_Expect_Success)
162 }312 }
163 }313 }
164 314 
315+ const NetInstance* layer0 = rankGraph->GetNetInstanceByNetInstId(0, "az0-rack0");
316+ ASSERT_NE(nullptr, layer0);
317+ EXPECT_TRUE(layer0->fabrics.empty());
318+ EXPECT_EQ(4, layer0->vGraph.nodes.size());
319+ 
165 std::vector<NetInstance::Path> pathsLayer0 = rankGraph->GetPaths(0, 0, 1);320 std::vector<NetInstance::Path> pathsLayer0 = rankGraph->GetPaths(0, 0, 1);
166 EXPECT_EQ(1, pathsLayer0.size());321 EXPECT_EQ(1, pathsLayer0.size());
167 // GetPaths检查边0 - 1的level1的边 peer0->net0、net0->peer1、peer0->net1、net1->peer1322 // GetPaths检查边0 - 1的level1的边 peer0->net0、net0->peer1、peer0->net1、net1->peer1
@@ -186,8 +341,177 @@ TEST_F(RankGraphBuilderTest, ut_Build_When_4pRankTable_Expect_Success)
186 EXPECT_EQ(htonl(0xC0A8650B), pathsLayer1[0].links[1].GetTargetIface()->GetAddr().GetBinaryAddress().addr.s_addr);341 EXPECT_EQ(htonl(0xC0A8650B), pathsLayer1[0].links[1].GetTargetIface()->GetAddr().GetBinaryAddress().addr.s_addr);
187 342 
188 std::vector<NetInstance::Path> pathsLayer2 = rankGraph->GetPaths(2, 2, 3);343 std::vector<NetInstance::Path> pathsLayer2 = rankGraph->GetPaths(2, 2, 3);
189- EXPECT_EQ(1, pathsLayer1.size());344+ EXPECT_EQ(1, pathsLayer2.size());
190- EXPECT_EQ(2, pathsLayer1[0].links.size());345+ EXPECT_EQ(2, pathsLayer2[0].links.size());
346+}
347+ 
348+TEST_F(RankGraphBuilderTest, Ut_RecoverBuild_When_EidSupportsCtpAndRtp_Expect_AllUbProtocols)
349+{
350+ DevBaseAttr devBaseAttr{};
351+ devBaseAttr.ub.priorityInfo[0].tpType.bs.ctp = 1;
352+ devBaseAttr.ub.priorityInfo[Hccl::kRaUbGetTpInfoParamDefaultQos].tpType.bs.rtp = 1;
353+ MockDevBaseAttr(&devBaseAttr);
354+ 
355+ RankGraphBuilder rankGraphBuilder;
356+ std::unique_ptr<RankGraph> rankGraph
357+ = rankGraphBuilder.RecoverBuild(MakeOverlappedUbRankTable(1, LinkProtocol::UB_CTP), MakeOverlappedUbTopo(), 0);
358+ 
359+ ASSERT_NE(nullptr, rankGraph);
360+ const std::set<u32> expectedLevels = {0, 1};
361+ EXPECT_EQ(expectedLevels, rankGraph->GetLevels(0));
362+ CheckOverlappedUbPaths(*rankGraph, 1, {LinkProtocol::UB_CTP, LinkProtocol::UB_TP, LinkProtocol::UB_MEM}, {2, 6});
363+}
364+ 
365+TEST_F(RankGraphBuilderTest, Ut_RecoverBuild_When_Layer1And2HaveDuplicatePhyLinks_Expect_KeepOneTopoInst)
366+{
367+ DevBaseAttr devBaseAttr{};
368+ devBaseAttr.ub.priorityInfo[0].tpType.bs.ctp = 1;
369+ devBaseAttr.ub.priorityInfo[Hccl::kRaUbGetTpInfoParamDefaultQos].tpType.bs.rtp = 1;
370+ MockDevBaseAttr(&devBaseAttr, 4U);
371+ 
372+ RankGraphBuilder rankGraphBuilder;
373+ std::unique_ptr<RankGraph> rankGraph
374+ = rankGraphBuilder.RecoverBuild(MakeOverlappedUbRankTableForLayer1And2(), MakeOverlappedUbTopo(true, true), 0);
375+ 
376+ ASSERT_NE(nullptr, rankGraph);
377+ for (u32 netLayer : {1U, 2U}) {
378+ CheckSingleTopoInst(*rankGraph, netLayer);
379+ CheckOverlappedUbPaths(
380+ *rankGraph, netLayer, {LinkProtocol::UB_CTP, LinkProtocol::UB_TP, LinkProtocol::UB_MEM}, {2, 6});
381+ }
382+}
383+ 
384+TEST_F(RankGraphBuilderTest, Ut_RecoverBuild_When_PortsOverlapAndEidsUseTp_Expect_TpLinks)
385+{
386+ DevBaseAttr devBaseAttr{};
387+ devBaseAttr.ub.priorityInfo[Hccl::kRaUbGetTpInfoParamDefaultQos].tpType.bs.rtp = 1;
388+ MockDevBaseAttr(&devBaseAttr);
389+ 
390+ RankGraphBuilder rankGraphBuilder;
391+ std::unique_ptr<RankGraph> rankGraph
392+ = rankGraphBuilder.RecoverBuild(MakeOverlappedUbRankTable(2, LinkProtocol::UB_TP), MakeOverlappedUbTopo(), 0);
393+ 
394+ ASSERT_NE(nullptr, rankGraph);
395+ CheckOverlappedUbPaths(*rankGraph, 2, {LinkProtocol::UB_TP}, {2, 2});
396+}
397+ 
398+TEST_F(RankGraphBuilderTest, Ut_RecoverBuild_When_OnlyRemotePortsOverlapAndEidsUseCtp_Expect_IgnoreTpLinks)
399+{
400+ DevBaseAttr devBaseAttr{};
401+ devBaseAttr.ub.priorityInfo[Hccl::kRaUbGetTpInfoParamDefaultQos].tpType.bs.ctp = 1;
402+ MockDevBaseAttr(&devBaseAttr);
403+ 
404+ RankGraphBuilder rankGraphBuilder;
405+ std::unique_ptr<RankGraph> rankGraph = rankGraphBuilder.RecoverBuild(
406+ MakeOverlappedUbRankTable(1, LinkProtocol::UB_CTP), MakeOverlappedUbTopo(false), 0);
407+ 
408+ ASSERT_NE(nullptr, rankGraph);
409+ CheckOverlappedUbPaths(*rankGraph, 1, {LinkProtocol::UB_CTP, LinkProtocol::UB_MEM}, {2, 6});
410+}
411+ 
412+TEST_F(RankGraphBuilderTest, Ut_RecoverBuild_When_SameTopoInstHasDifferentPlanes_Expect_CreateFabricByPlaneId)
413+{
414+ PhyTopo::GetInstance()->Clear();
415+ const std::string rankTableString = R"({
416+ "version": "2.0",
417+ "rank_count": 1,
418+ "rank_list": [
419+ {
420+ "rank_id": 0,
421+ "device_id": 0,
422+ "local_id": 0,
423+ "level_list": [
424+ {
425+ "net_layer": 0,
426+ "net_instance_id": "rank-group-0",
427+ "net_type": "TOPO_FILE_DESC",
428+ "rank_addr_list": [
429+ {
430+ "addr_type": "IPV4",
431+ "addr": "192.168.0.1",
432+ "ports": ["0/1"],
433+ "plane_id": "planeA"
434+ },
435+ {
436+ "addr_type": "IPV4",
437+ "addr": "192.168.0.2",
438+ "ports": ["0/2"],
439+ "plane_id": "planeB"
440+ }
441+ ]
442+ }
443+ ]
444+ }
445+ ]
446+ })";
447+ const std::string topoString = R"({
448+ "version": "2.0",
449+ "peer_count": 1,
450+ "peer_list": [{"local_id": 0}],
451+ "edge_count": 2,
452+ "edge_list": [
453+ {
454+ "link_type": "PEER2NET",
455+ "protocols": ["UB_CTP"],
456+ "topo_type": "CLOS",
457+ "topo_instance_id": 7,
458+ "local_a": 0,
459+ "local_a_ports": ["0/1"],
460+ "position": "DEVICE"
461+ },
462+ {
463+ "link_type": "PEER2NET",
464+ "protocols": ["UB_CTP"],
465+ "topo_type": "CLOS",
466+ "topo_instance_id": 7,
467+ "local_a": 0,
468+ "local_a_ports": ["0/2"],
469+ "position": "DEVICE"
470+ }
471+ ]
472+ })";
473+ 
474+ JsonParser parser;
475+ RankTableInfo rankTableInfo;
476+ TopoInfo topoInfo;
477+ parser.ParseString(rankTableString, rankTableInfo);
478+ parser.ParseString(topoString, topoInfo);
479+ 
480+ RankGraphBuilder rankGraphBuilder;
481+ std::unique_ptr<RankGraph> rankGraph = rankGraphBuilder.RecoverBuild(rankTableInfo, topoInfo, 0);
482+ ASSERT_NE(nullptr, rankGraph);
483+ NetInstance* layer0 = rankGraph->GetNetInstanceByNetInstId(0, "rank-group-0");
484+ ASSERT_NE(nullptr, layer0);
485+ ASSERT_EQ(2, layer0->GetFabrics().size());
486+ std::set<PlaneId> planeIds;
487+ for (const auto& fabric : layer0->GetFabrics()) {
488+ ASSERT_NE(nullptr, fabric);
489+ planeIds.insert(fabric->GetPlaneId());
490+ }
491+ EXPECT_EQ((std::set<PlaneId>{"planeA", "planeB"}), planeIds);
492+}
493+ 
494+TEST_F(RankGraphBuilderTest, Ut_ConstructConnI_When_PortMapEmpty_Expect_OnlyPcieCreatesD2hIface)
495+{
496+ const std::map<std::string, std::vector<IpAddress>> emptyPortAddrMap;
497+ auto pcieIface = std::make_shared<PhyTopo::ConnInterface>(
498+ std::set<std::string>{"0/0"}, AddrPosition::DEVICE, LinkType::PEER2PEER,
499+ std::set<LinkProtocol>{LinkProtocol::PCIE});
500+ MOCKER(HrtRaSocketGetVnicIpInfos).stubs();
501+ 
502+ auto pcieNetIfaces = ConstructConnIFromPhyTopoConnIAndPortMap(pcieIface, emptyPortAddrMap, TopoType::CLOS, 0, 0);
503+ 
504+ ASSERT_EQ(1, pcieNetIfaces.size());
505+ EXPECT_EQ(std::set<std::string>{"d2h"}, pcieNetIfaces[0]->GetPorts());
506+ EXPECT_EQ(std::set<LinkProtocol>{LinkProtocol::PCIE}, pcieNetIfaces[0]->GetLinkProtocols());
507+ 
508+ auto unmatchedIface = std::make_shared<PhyTopo::ConnInterface>(
509+ std::set<std::string>{"0/9"}, AddrPosition::DEVICE, LinkType::PEER2PEER,
510+ std::set<LinkProtocol>{LinkProtocol::UB_CTP});
511+ auto unmatchedNetIfaces
512+ = ConstructConnIFromPhyTopoConnIAndPortMap(unmatchedIface, emptyPortAddrMap, TopoType::CLOS, 0, 0);
513+ 
514+ EXPECT_TRUE(unmatchedNetIfaces.empty());
191}515}
192 516 
193TEST_F(RankGraphBuilderTest, Ut_RankGraphBuilderRecoverBuild_When_Invalid_Expect_InvalidParamsException)517TEST_F(RankGraphBuilderTest, Ut_RankGraphBuilderRecoverBuild_When_Invalid_Expect_InvalidParamsException)
@@ -40,7 +40,6 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_Normal_Expect_Success)
40 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));40 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));
41 41 
42 std::string edgeString = R"({42 std::string edgeString = R"({
43- "net_layer": 0,
44 "link_type": "PEER2PEER",43 "link_type": "PEER2PEER",
45 "protocols": ["UB_CTP"], 44 "protocols": ["UB_CTP"],
46 "topo_type": "1DMESH",45 "topo_type": "1DMESH",
@@ -57,7 +56,6 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_Normal_Expect_Success)
57 topoParser.ParseString(edgeString, edgeInfo);56 topoParser.ParseString(edgeString, edgeInfo);
58 57 
59 EdgeInfo edge0;58 EdgeInfo edge0;
60- edge0.netLayer = 0;
61 edge0.protocols.emplace(LinkProtocol::UB_CTP);59 edge0.protocols.emplace(LinkProtocol::UB_CTP);
62 edge0.linkType = LinkType::PEER2PEER;60 edge0.linkType = LinkType::PEER2PEER;
63 edge0.topoType = TopoType::MESH_1D;61 edge0.topoType = TopoType::MESH_1D;
@@ -101,7 +99,6 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_OptionalFieldsMissing_Expect_Success)
101 topoParser.ParseString(edgeString, edgeInfo);99 topoParser.ParseString(edgeString, edgeInfo);
102 100 
103 EdgeInfo edge0;101 EdgeInfo edge0;
104- edge0.netLayer = 0;
105 edge0.protocols.emplace(LinkProtocol::UB_CTP);102 edge0.protocols.emplace(LinkProtocol::UB_CTP);
106 edge0.linkType = LinkType::PEER2PEER;103 edge0.linkType = LinkType::PEER2PEER;
107 edge0.topoType = TopoType::CLOS;104 edge0.topoType = TopoType::CLOS;
@@ -139,7 +136,6 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_PEER2NET_ExistB_Expect_Warning)
139 topoParser.ParseString(edgeString, edgeInfo);136 topoParser.ParseString(edgeString, edgeInfo);
140 137 
141 EdgeInfo edge0;138 EdgeInfo edge0;
142- edge0.netLayer = 0;
143 edge0.protocols.emplace(LinkProtocol::UB_CTP);139 edge0.protocols.emplace(LinkProtocol::UB_CTP);
144 edge0.linkType = LinkType::PEER2NET;140 edge0.linkType = LinkType::PEER2NET;
145 edge0.topoType = TopoType::MESH_1D;141 edge0.topoType = TopoType::MESH_1D;
@@ -173,7 +169,6 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_NormalPeer2Net_Expect_Success)
173 topoParser.ParseString(edgeString, edgeInfo);169 topoParser.ParseString(edgeString, edgeInfo);
174 170 
175 EdgeInfo edge0;171 EdgeInfo edge0;
176- edge0.netLayer = 0;
177 edge0.protocols.emplace(LinkProtocol::UB_CTP);172 edge0.protocols.emplace(LinkProtocol::UB_CTP);
178 edge0.linkType = LinkType::PEER2NET;173 edge0.linkType = LinkType::PEER2NET;
179 edge0.topoType = TopoType::MESH_1D;174 edge0.topoType = TopoType::MESH_1D;
@@ -202,14 +197,13 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_NeededFieldMissing_Expect_Exception)
202 EXPECT_THROW(edgeParser.ParseString(edgeString, edgeInfo), InvalidParamsException);197 EXPECT_THROW(edgeParser.ParseString(edgeString, edgeInfo), InvalidParamsException);
203}198}
204 199 
205-// net_layer = 8200+// 旧 topo.json 中不同或越界的 net_layer 都应被忽略,解析结果与不带该字段时一致
206-TEST_F(EdgeParserTest, Ut_Deserialize_When_InvalidNetLayer_Expect_Exception)201+TEST_F(EdgeParserTest, Ut_Deserialize_When_LegacyNetLayerDifferentOrOutOfRange_Expect_SameEdge)
207{202{
208 DevType devType = DevType::DEV_TYPE_910A;203 DevType devType = DevType::DEV_TYPE_910A;
209 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));204 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));
210 205 
211- std::string edgeString = R"({206+ std::string edgeStringWithoutNetLayer = R"({
212- "net_layer": 8,
213 "link_type": "PEER2PEER",207 "link_type": "PEER2PEER",
214 "protocols": ["UB_CTP"],208 "protocols": ["UB_CTP"],
215 "topo_type": "1DMESH",209 "topo_type": "1DMESH",
@@ -221,9 +215,21 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_InvalidNetLayer_Expect_Exception)
221 "position": "DEVICE"215 "position": "DEVICE"
222 })";216 })";
223 217 
218+ nlohmann::json edgeJsonWithoutNetLayer = nlohmann::json::parse(edgeStringWithoutNetLayer);
219+ nlohmann::json edgeJsonWithDifferentNetLayer = edgeJsonWithoutNetLayer;
220+ nlohmann::json edgeJsonWithOutOfRangeNetLayer = edgeJsonWithoutNetLayer;
221+ edgeJsonWithDifferentNetLayer["net_layer"] = 1;
222+ edgeJsonWithOutOfRangeNetLayer["net_layer"] = 8;
223+ 
224 JsonParser edgeParser;224 JsonParser edgeParser;
225- EdgeInfo edgeInfo;225+ EdgeInfo edgeWithoutNetLayer;
226- EXPECT_THROW(edgeParser.ParseString(edgeString, edgeInfo), InvalidParamsException);226+ EdgeInfo edgeWithDifferentNetLayer;
227+ EdgeInfo edgeWithOutOfRangeNetLayer;
228+ EXPECT_NO_THROW(edgeParser.ParseString(edgeStringWithoutNetLayer, edgeWithoutNetLayer));
229+ EXPECT_NO_THROW(edgeParser.ParseString(edgeJsonWithDifferentNetLayer.dump(), edgeWithDifferentNetLayer));
230+ EXPECT_NO_THROW(edgeParser.ParseString(edgeJsonWithOutOfRangeNetLayer.dump(), edgeWithOutOfRangeNetLayer));
231+ EXPECT_TRUE(edgeWithoutNetLayer == edgeWithDifferentNetLayer);
232+ EXPECT_TRUE(edgeWithoutNetLayer == edgeWithOutOfRangeNetLayer);
227}233}
228 234 
229// 无效的LinkProtocol235// 无效的LinkProtocol
@@ -447,7 +453,6 @@ TEST_F(EdgeParserTest, Ut_Deserialize_When_InvalidPosition_Expect_Exception)
447TEST_F(EdgeParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success)453TEST_F(EdgeParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success)
448{454{
449 EdgeInfo edge0;455 EdgeInfo edge0;
450- edge0.netLayer = 0;
451 edge0.protocols.emplace(LinkProtocol::UB_CTP);456 edge0.protocols.emplace(LinkProtocol::UB_CTP);
452 edge0.linkType = LinkType::PEER2PEER;457 edge0.linkType = LinkType::PEER2PEER;
453 edge0.topoType = TopoType::MESH_1D;458 edge0.topoType = TopoType::MESH_1D;
@@ -464,4 +469,12 @@ TEST_F(EdgeParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
464 469 
465 EdgeInfo edgeInfoRebuild(binStream);470 EdgeInfo edgeInfoRebuild(binStream);
466 EXPECT_EQ(edgeInfoRebuild.Describe(), edge0.Describe());471 EXPECT_EQ(edgeInfoRebuild.Describe(), edge0.Describe());
472+ 
473+ BinaryStream layoutStream;
474+ edge0.GetBinStream(layoutStream);
475+ u32 binaryLayer = 0;
476+ u32 linkType = 0;
477+ layoutStream >> binaryLayer >> linkType;
478+ EXPECT_EQ(binaryLayer, 0);
479+ EXPECT_EQ(linkType, static_cast<u32>(edge0.linkType));
467}480}
@@ -49,6 +49,28 @@ std::string BuildLargeTopoString()
49}49}
50} // namespace50} // namespace
51 51 
52+namespace {
53+void WriteLegacyEdge(BinaryStream& binaryStream, u32 binaryLayer, const EdgeInfo& edge)
54+{
55+ binaryStream << binaryLayer << static_cast<u32>(edge.linkType) << static_cast<u32>(edge.topoType)
56+ << edge.topoInstId;
57+ binaryStream << edge.protocols.size();
58+ for (const auto& protocol : edge.protocols) {
59+ binaryStream << static_cast<u32>(protocol);
60+ }
61+ binaryStream << edge.localA << edge.localB;
62+ binaryStream << edge.localAPorts.size();
63+ for (const auto& port : edge.localAPorts) {
64+ binaryStream << port;
65+ }
66+ binaryStream << edge.localBPorts.size();
67+ for (const auto& port : edge.localBPorts) {
68+ binaryStream << port;
69+ }
70+ binaryStream << static_cast<u32>(edge.position);
71+}
72+} // namespace
73+ 
52class TopoParserTest : public testing::Test {74class TopoParserTest : public testing::Test {
53protected:75protected:
54 static void SetUpTestCase() { std::cout << "TopoParserTest SetUP" << std::endl; }76 static void SetUpTestCase() { std::cout << "TopoParserTest SetUP" << std::endl; }
@@ -157,11 +179,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
157 expectTopoInfo.peers.emplace_back(peer2);179 expectTopoInfo.peers.emplace_back(peer2);
158 180 
159 expectTopoInfo.edgeCount = 5;181 expectTopoInfo.edgeCount = 5;
160- expectTopoInfo.edges[0] = std::vector<EdgeInfo>();
161- expectTopoInfo.edges[1] = std::vector<EdgeInfo>();
162- expectTopoInfo.edges[2] = std::vector<EdgeInfo>();
163 EdgeInfo edge0;182 EdgeInfo edge0;
164- edge0.netLayer = 0;
165 edge0.linkType = LinkType::PEER2PEER;183 edge0.linkType = LinkType::PEER2PEER;
166 edge0.protocols.emplace(LinkProtocol::UB_CTP);184 edge0.protocols.emplace(LinkProtocol::UB_CTP);
167 edge0.topoType = TopoType::MESH_1D;185 edge0.topoType = TopoType::MESH_1D;
@@ -171,10 +189,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
171 edge0.localB = 1;189 edge0.localB = 1;
172 edge0.localBPorts.emplace("0/1");190 edge0.localBPorts.emplace("0/1");
173 edge0.position = AddrPosition::DEVICE;191 edge0.position = AddrPosition::DEVICE;
174- expectTopoInfo.edges[0].emplace_back(edge0);192+ expectTopoInfo.edges.emplace_back(edge0);
175 193 
176 EdgeInfo edge1;194 EdgeInfo edge1;
177- edge1.netLayer = 0;
178 edge1.linkType = LinkType::PEER2PEER;195 edge1.linkType = LinkType::PEER2PEER;
179 edge1.protocols.emplace(LinkProtocol::UB_MEM);196 edge1.protocols.emplace(LinkProtocol::UB_MEM);
180 edge1.topoType = TopoType::MESH_1D;197 edge1.topoType = TopoType::MESH_1D;
@@ -184,10 +201,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
184 edge1.localB = 2;201 edge1.localB = 2;
185 edge1.localBPorts.emplace("0/1");202 edge1.localBPorts.emplace("0/1");
186 edge1.position = AddrPosition::DEVICE;203 edge1.position = AddrPosition::DEVICE;
187- expectTopoInfo.edges[0].emplace_back(edge1);204+ expectTopoInfo.edges.emplace_back(edge1);
188 205 
189 EdgeInfo edge2;206 EdgeInfo edge2;
190- edge2.netLayer = 0;
191 edge2.linkType = LinkType::PEER2NET;207 edge2.linkType = LinkType::PEER2NET;
192 edge2.protocols.emplace(LinkProtocol::UB_CTP);208 edge2.protocols.emplace(LinkProtocol::UB_CTP);
193 edge2.topoType = TopoType::MESH_1D;209 edge2.topoType = TopoType::MESH_1D;
@@ -195,10 +211,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
195 edge2.localA = 0;211 edge2.localA = 0;
196 edge2.localAPorts.emplace("0/0");212 edge2.localAPorts.emplace("0/0");
197 edge2.position = AddrPosition::HOST;213 edge2.position = AddrPosition::HOST;
198- expectTopoInfo.edges[0].emplace_back(edge2);214+ expectTopoInfo.edges.emplace_back(edge2);
199 215 
200 EdgeInfo edge3;216 EdgeInfo edge3;
201- edge3.netLayer = 1;
202 edge3.linkType = LinkType::PEER2PEER;217 edge3.linkType = LinkType::PEER2PEER;
203 edge3.protocols.emplace(LinkProtocol::UB_TP);218 edge3.protocols.emplace(LinkProtocol::UB_TP);
204 edge3.topoType = TopoType::MESH_1D;219 edge3.topoType = TopoType::MESH_1D;
@@ -208,10 +223,9 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
208 edge3.localB = 2;223 edge3.localB = 2;
209 edge3.localBPorts.emplace("0/1");224 edge3.localBPorts.emplace("0/1");
210 edge3.position = AddrPosition::DEVICE;225 edge3.position = AddrPosition::DEVICE;
211- expectTopoInfo.edges[1].emplace_back(edge3);226+ expectTopoInfo.edges.emplace_back(edge3);
212 227 
213 EdgeInfo edge4;228 EdgeInfo edge4;
214- edge4.netLayer = 2;
215 edge4.linkType = LinkType::PEER2NET;229 edge4.linkType = LinkType::PEER2NET;
216 edge4.protocols.emplace(LinkProtocol::ROCE);230 edge4.protocols.emplace(LinkProtocol::ROCE);
217 edge4.topoType = TopoType::CLOS;231 edge4.topoType = TopoType::CLOS;
@@ -219,7 +233,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
219 edge4.localA = 0;233 edge4.localA = 0;
220 edge4.localAPorts.emplace("0/0");234 edge4.localAPorts.emplace("0/0");
221 edge4.position = AddrPosition::DEVICE;235 edge4.position = AddrPosition::DEVICE;
222- expectTopoInfo.edges[2].emplace_back(edge4);236+ expectTopoInfo.edges.emplace_back(edge4);
223 237 
224 EXPECT_EQ(topoInfo.version, expectTopoInfo.version);238 EXPECT_EQ(topoInfo.version, expectTopoInfo.version);
225 EXPECT_EQ(topoInfo.peerCount, expectTopoInfo.peerCount);239 EXPECT_EQ(topoInfo.peerCount, expectTopoInfo.peerCount);
@@ -230,24 +244,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_Normal_Expect_Success)
230 EXPECT_EQ(topoInfo.edgeCount, expectTopoInfo.edgeCount);244 EXPECT_EQ(topoInfo.edgeCount, expectTopoInfo.edgeCount);
231 EXPECT_EQ(topoInfo.edges.size(), expectTopoInfo.edges.size());245 EXPECT_EQ(topoInfo.edges.size(), expectTopoInfo.edges.size());
232 246 
233- auto it_topo_edges = topoInfo.edges.begin();247+ EXPECT_EQ(topoInfo.edges, expectTopoInfo.edges);
234- auto it_expect_edges = expectTopoInfo.edges.begin();
235- for (; it_topo_edges != topoInfo.edges.end(); it_topo_edges++, it_expect_edges++) {
236- EXPECT_EQ(it_topo_edges->first, it_expect_edges->first);
237- EXPECT_EQ((it_topo_edges->second).size(), (it_expect_edges->second).size());
238- for (u32 i = 0; i < (it_topo_edges->second).size(); i++) {
239- EXPECT_EQ((it_topo_edges->second)[i].netLayer, (it_expect_edges->second)[i].netLayer);
240- EXPECT_EQ((it_topo_edges->second)[i].protocols, (it_expect_edges->second)[i].protocols);
241- EXPECT_EQ((it_topo_edges->second)[i].linkType, (it_expect_edges->second)[i].linkType);
242- EXPECT_EQ((it_topo_edges->second)[i].topoType, (it_expect_edges->second)[i].topoType);
243- EXPECT_EQ((it_topo_edges->second)[i].topoInstId, (it_expect_edges->second)[i].topoInstId);
244- EXPECT_EQ((it_topo_edges->second)[i].localA, (it_expect_edges->second)[i].localA);
245- EXPECT_EQ((it_topo_edges->second)[i].localAPorts, (it_expect_edges->second)[i].localAPorts);
246- EXPECT_EQ((it_topo_edges->second)[i].localB, (it_expect_edges->second)[i].localB);
247- EXPECT_EQ((it_topo_edges->second)[i].localBPorts, (it_expect_edges->second)[i].localBPorts);
248- EXPECT_EQ((it_topo_edges->second)[i].position, (it_expect_edges->second)[i].position);
249- }
250- }
251 248 
252 EXPECT_EQ(topoInfo.Describe(), expectTopoInfo.Describe());249 EXPECT_EQ(topoInfo.Describe(), expectTopoInfo.Describe());
253}250}
@@ -473,7 +470,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_EdgesSizeUnequalToEdgeCount_Expect_Ex
473}470}
474 471 
475// 重复的边 PEER2PEER,localA和localB对调472// 重复的边 PEER2PEER,localA和localB对调
476-TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Exception)473+TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Merged)
477{474{
478 DevType devType = DevType::DEV_TYPE_910A;475 DevType devType = DevType::DEV_TYPE_910A;
479 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));476 MOCKER(HrtGetDeviceType).stubs().will(returnValue(devType));
@@ -502,7 +499,7 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Exception)
502 "position": "DEVICE"499 "position": "DEVICE"
503 },500 },
504 {501 {
505- "net_layer": 0,502+ "net_layer": 7,
506 "link_type": "PEER2PEER",503 "link_type": "PEER2PEER",
507 "protocols": ["UB_CTP"],504 "protocols": ["UB_CTP"],
508 "topo_type": "1DMESH",505 "topo_type": "1DMESH",
@@ -518,7 +515,11 @@ TEST_F(TopoParserTest, Ut_Deserialize_When_DuplicateEdge_Expect_Exception)
518 515 
519 JsonParser topoParser;516 JsonParser topoParser;
520 TopoInfo topoInfo;517 TopoInfo topoInfo;
521- EXPECT_THROW(topoParser.ParseString(topoString, topoInfo), InvalidParamsException);518+ EXPECT_NO_THROW(topoParser.ParseString(topoString, topoInfo));
519+ EXPECT_EQ(topoInfo.edgeCount, 1);
520+ ASSERT_EQ(topoInfo.edges.size(), 1);
521+ EXPECT_EQ(topoInfo.edges[0].localA, 0);
522+ EXPECT_EQ(topoInfo.edges[0].localB, 1);
522}523}
523 524 
524// Endpoint的localId无效525// Endpoint的localId无效
@@ -697,11 +698,7 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
697 expectTopoInfo.peers.emplace_back(peer2);698 expectTopoInfo.peers.emplace_back(peer2);
698 699 
699 expectTopoInfo.edgeCount = 5;700 expectTopoInfo.edgeCount = 5;
700- expectTopoInfo.edges[0] = std::vector<EdgeInfo>();
701- expectTopoInfo.edges[1] = std::vector<EdgeInfo>();
702- expectTopoInfo.edges[2] = std::vector<EdgeInfo>();
703 EdgeInfo edge0;701 EdgeInfo edge0;
704- edge0.netLayer = 0;
705 edge0.linkType = LinkType::PEER2PEER;702 edge0.linkType = LinkType::PEER2PEER;
706 edge0.protocols.emplace(LinkProtocol::UB_CTP);703 edge0.protocols.emplace(LinkProtocol::UB_CTP);
707 edge0.topoType = TopoType::MESH_1D;704 edge0.topoType = TopoType::MESH_1D;
@@ -711,10 +708,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
711 edge0.localB = 1;708 edge0.localB = 1;
712 edge0.localBPorts.emplace("0/1");709 edge0.localBPorts.emplace("0/1");
713 edge0.position = AddrPosition::DEVICE;710 edge0.position = AddrPosition::DEVICE;
714- expectTopoInfo.edges[0].emplace_back(edge0);711+ expectTopoInfo.edges.emplace_back(edge0);
715 712 
716 EdgeInfo edge1;713 EdgeInfo edge1;
717- edge1.netLayer = 0;
718 edge1.linkType = LinkType::PEER2PEER;714 edge1.linkType = LinkType::PEER2PEER;
719 edge1.protocols.emplace(LinkProtocol::UB_MEM);715 edge1.protocols.emplace(LinkProtocol::UB_MEM);
720 edge1.topoType = TopoType::MESH_1D;716 edge1.topoType = TopoType::MESH_1D;
@@ -724,10 +720,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
724 edge1.localB = 2;720 edge1.localB = 2;
725 edge1.localBPorts.emplace("0/1");721 edge1.localBPorts.emplace("0/1");
726 edge1.position = AddrPosition::DEVICE;722 edge1.position = AddrPosition::DEVICE;
727- expectTopoInfo.edges[0].emplace_back(edge1);723+ expectTopoInfo.edges.emplace_back(edge1);
728 724 
729 EdgeInfo edge2;725 EdgeInfo edge2;
730- edge2.netLayer = 0;
731 edge2.linkType = LinkType::PEER2NET;726 edge2.linkType = LinkType::PEER2NET;
732 edge2.protocols.emplace(LinkProtocol::UB_CTP);727 edge2.protocols.emplace(LinkProtocol::UB_CTP);
733 edge2.topoType = TopoType::MESH_1D;728 edge2.topoType = TopoType::MESH_1D;
@@ -735,10 +730,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
735 edge2.localA = 0;730 edge2.localA = 0;
736 edge2.localAPorts.emplace("0/0");731 edge2.localAPorts.emplace("0/0");
737 edge2.position = AddrPosition::HOST;732 edge2.position = AddrPosition::HOST;
738- expectTopoInfo.edges[0].emplace_back(edge2);733+ expectTopoInfo.edges.emplace_back(edge2);
739 734 
740 EdgeInfo edge3;735 EdgeInfo edge3;
741- edge3.netLayer = 1;
742 edge3.linkType = LinkType::PEER2PEER;736 edge3.linkType = LinkType::PEER2PEER;
743 edge3.protocols.emplace(LinkProtocol::UB_TP);737 edge3.protocols.emplace(LinkProtocol::UB_TP);
744 edge3.topoType = TopoType::MESH_1D;738 edge3.topoType = TopoType::MESH_1D;
@@ -748,10 +742,9 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
748 edge3.localB = 2;742 edge3.localB = 2;
749 edge3.localBPorts.emplace("0/1");743 edge3.localBPorts.emplace("0/1");
750 edge3.position = AddrPosition::DEVICE;744 edge3.position = AddrPosition::DEVICE;
751- expectTopoInfo.edges[1].emplace_back(edge3);745+ expectTopoInfo.edges.emplace_back(edge3);
752 746 
753 EdgeInfo edge4;747 EdgeInfo edge4;
754- edge4.netLayer = 2;
755 edge4.linkType = LinkType::PEER2NET;748 edge4.linkType = LinkType::PEER2NET;
756 edge4.protocols.emplace(LinkProtocol::ROCE);749 edge4.protocols.emplace(LinkProtocol::ROCE);
757 edge4.topoType = TopoType::CLOS;750 edge4.topoType = TopoType::CLOS;
@@ -759,12 +752,35 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
759 edge4.localA = 0;752 edge4.localA = 0;
760 edge4.localAPorts.emplace("0/0");753 edge4.localAPorts.emplace("0/0");
761 edge4.position = AddrPosition::DEVICE;754 edge4.position = AddrPosition::DEVICE;
762- expectTopoInfo.edges[2].emplace_back(edge4);755+ expectTopoInfo.edges.emplace_back(edge4);
763 756 
764 BinaryStream binStream;757 BinaryStream binStream;
765 expectTopoInfo.GetBinStream(binStream);758 expectTopoInfo.GetBinStream(binStream);
766 TopoInfo reBuildTopo(binStream);759 TopoInfo reBuildTopo(binStream);
767 760 
761+ BinaryStream layoutStream;
762+ expectTopoInfo.GetBinStream(layoutStream);
763+ std::string binaryVersion;
764+ u32 binaryPeerCount = 0;
765+ u32 binaryEdgeCount = 0;
766+ size_t binaryPeerSize = 0;
767+ layoutStream >> binaryVersion >> binaryPeerCount >> binaryEdgeCount >> binaryPeerSize;
768+ EXPECT_EQ(binaryVersion, expectTopoInfo.version);
769+ EXPECT_EQ(binaryPeerCount, expectTopoInfo.peerCount);
770+ EXPECT_EQ(binaryEdgeCount, expectTopoInfo.edgeCount);
771+ EXPECT_EQ(binaryPeerSize, expectTopoInfo.peers.size());
772+ for (size_t i = 0; i < binaryPeerSize; i++) {
773+ PeerInfo binaryPeer(layoutStream);
774+ EXPECT_EQ(binaryPeer.localId, expectTopoInfo.peers[i].localId);
775+ }
776+ size_t edgeGroupCount = 0;
777+ u32 binaryLayer = 0;
778+ size_t groupEdgeCount = 0;
779+ layoutStream >> edgeGroupCount >> binaryLayer >> groupEdgeCount;
780+ EXPECT_EQ(edgeGroupCount, 1);
781+ EXPECT_EQ(binaryLayer, 0);
782+ EXPECT_EQ(groupEdgeCount, expectTopoInfo.edges.size());
783+ 
768 EXPECT_EQ(expectTopoInfo.version, reBuildTopo.version);784 EXPECT_EQ(expectTopoInfo.version, reBuildTopo.version);
769 EXPECT_EQ(expectTopoInfo.peerCount, reBuildTopo.peerCount);785 EXPECT_EQ(expectTopoInfo.peerCount, reBuildTopo.peerCount);
770 EXPECT_EQ(expectTopoInfo.peers.size(), reBuildTopo.peers.size());786 EXPECT_EQ(expectTopoInfo.peers.size(), reBuildTopo.peers.size());
@@ -774,28 +790,110 @@ TEST_F(TopoParserTest, Ut_BinaryStream_When_GetBinStreamToReBuild_Expect_Success
774 EXPECT_EQ(expectTopoInfo.edgeCount, reBuildTopo.edgeCount);790 EXPECT_EQ(expectTopoInfo.edgeCount, reBuildTopo.edgeCount);
775 EXPECT_EQ(expectTopoInfo.edges.size(), reBuildTopo.edges.size());791 EXPECT_EQ(expectTopoInfo.edges.size(), reBuildTopo.edges.size());
776 792 
777- auto it_topo_edges = expectTopoInfo.edges.begin();793+ EXPECT_EQ(expectTopoInfo.edges, reBuildTopo.edges);
778- auto it_expect_edges = reBuildTopo.edges.begin();
779- for (; it_topo_edges != expectTopoInfo.edges.end(); it_topo_edges++, it_expect_edges++) {
780- EXPECT_EQ(it_topo_edges->first, it_expect_edges->first);
781- EXPECT_EQ((it_topo_edges->second).size(), (it_expect_edges->second).size());
782- for (u32 i = 0; i < (it_topo_edges->second).size(); i++) {
783- EXPECT_EQ((it_topo_edges->second)[i].netLayer, (it_expect_edges->second)[i].netLayer);
784- EXPECT_EQ((it_topo_edges->second)[i].protocols, (it_expect_edges->second)[i].protocols);
785- EXPECT_EQ((it_topo_edges->second)[i].linkType, (it_expect_edges->second)[i].linkType);
786- EXPECT_EQ((it_topo_edges->second)[i].topoType, (it_expect_edges->second)[i].topoType);
787- EXPECT_EQ((it_topo_edges->second)[i].topoInstId, (it_expect_edges->second)[i].topoInstId);
788- EXPECT_EQ((it_topo_edges->second)[i].localA, (it_expect_edges->second)[i].localA);
789- EXPECT_EQ((it_topo_edges->second)[i].localAPorts, (it_expect_edges->second)[i].localAPorts);
790- EXPECT_EQ((it_topo_edges->second)[i].localB, (it_expect_edges->second)[i].localB);
791- EXPECT_EQ((it_topo_edges->second)[i].localBPorts, (it_expect_edges->second)[i].localBPorts);
792- EXPECT_EQ((it_topo_edges->second)[i].position, (it_expect_edges->second)[i].position);
793- }
794- }
795 794 
796 EXPECT_EQ(expectTopoInfo.Describe(), reBuildTopo.Describe());795 EXPECT_EQ(expectTopoInfo.Describe(), reBuildTopo.Describe());
797}796}
798 797 
798+TEST_F(TopoParserTest, Ut_BinaryStream_When_ReadLegacyGroups_Expect_FlattenedEdges)
799+{
800+ TopoInfo expectTopoInfo;
801+ expectTopoInfo.version = "2.0";
802+ expectTopoInfo.peerCount = 2;
803+ expectTopoInfo.edgeCount = 2;
804+ 
805+ PeerInfo peer0;
806+ peer0.localId = 0;
807+ PeerInfo peer1;
808+ peer1.localId = 1;
809+ expectTopoInfo.peers = {peer0, peer1};
810+ 
811+ EdgeInfo edge0;
812+ edge0.linkType = LinkType::PEER2PEER;
813+ edge0.protocols.emplace(LinkProtocol::UB_CTP);
814+ edge0.topoType = TopoType::MESH_1D;
815+ edge0.localA = 0;
816+ edge0.localAPorts.emplace("0/0");
817+ edge0.localB = 1;
818+ edge0.localBPorts.emplace("0/1");
819+ edge0.position = AddrPosition::DEVICE;
820+ 
821+ EdgeInfo edge1;
822+ edge1.linkType = LinkType::PEER2NET;
823+ edge1.protocols.emplace(LinkProtocol::ROCE);
824+ edge1.topoType = TopoType::CLOS;
825+ edge1.topoInstId = 1;
826+ edge1.localA = 1;
827+ edge1.localAPorts.emplace("1/0");
828+ edge1.position = AddrPosition::HOST;
829+ expectTopoInfo.edges = {edge0, edge1};
830+ 
831+ BinaryStream legacyStream;
832+ legacyStream << expectTopoInfo.version << expectTopoInfo.peerCount << expectTopoInfo.edgeCount;
833+ legacyStream << expectTopoInfo.peers.size();
834+ for (const auto& peer : expectTopoInfo.peers) {
835+ peer.GetBinStream(legacyStream);
836+ }
837+ const size_t edgeGroupCount = 2;
838+ const size_t groupEdgeCount = 1;
839+ legacyStream << edgeGroupCount;
840+ legacyStream << static_cast<u32>(1) << groupEdgeCount;
841+ WriteLegacyEdge(legacyStream, 1, edge0);
842+ legacyStream << static_cast<u32>(7) << groupEdgeCount;
843+ WriteLegacyEdge(legacyStream, 7, edge1);
844+ 
845+ TopoInfo reBuildTopo(legacyStream);
846+ EXPECT_EQ(reBuildTopo.version, expectTopoInfo.version);
847+ EXPECT_EQ(reBuildTopo.peerCount, expectTopoInfo.peerCount);
848+ EXPECT_EQ(reBuildTopo.edgeCount, expectTopoInfo.edgeCount);
849+ EXPECT_EQ(reBuildTopo.peers.size(), expectTopoInfo.peers.size());
850+ EXPECT_EQ(reBuildTopo.edges, expectTopoInfo.edges);
851+}
852+ 
853+TEST_F(TopoParserTest, Ut_BinaryStream_When_LegacyGroupsContainSameEdge_Expect_Merged)
854+{
855+ TopoInfo topoInfo;
856+ topoInfo.version = "2.0";
857+ topoInfo.peerCount = 2;
858+ topoInfo.edgeCount = 2;
859+ 
860+ PeerInfo peer0;
861+ peer0.localId = 0;
862+ PeerInfo peer1;
863+ peer1.localId = 1;
864+ topoInfo.peers = {peer0, peer1};
865+ 
866+ EdgeInfo edge;
867+ edge.linkType = LinkType::PEER2PEER;
868+ edge.protocols.emplace(LinkProtocol::UB_CTP);
869+ edge.topoType = TopoType::MESH_1D;
870+ edge.localA = 0;
871+ edge.localAPorts.emplace("0/0");
872+ edge.localB = 1;
873+ edge.localBPorts.emplace("0/1");
874+ edge.position = AddrPosition::DEVICE;
875+ 
876+ BinaryStream legacyStream;
877+ legacyStream << topoInfo.version << topoInfo.peerCount << topoInfo.edgeCount;
878+ legacyStream << topoInfo.peers.size();
879+ for (const auto& peer : topoInfo.peers) {
880+ peer.GetBinStream(legacyStream);
881+ }
882+ 
883+ const size_t edgeGroupCount = 2;
884+ const size_t groupEdgeCount = 1;
885+ legacyStream << edgeGroupCount;
886+ legacyStream << static_cast<u32>(0) << groupEdgeCount;
887+ WriteLegacyEdge(legacyStream, 0, edge);
888+ legacyStream << static_cast<u32>(7) << groupEdgeCount;
889+ WriteLegacyEdge(legacyStream, 7, edge);
890+ 
891+ TopoInfo rebuiltTopo(legacyStream);
892+ EXPECT_EQ(rebuiltTopo.edgeCount, 1);
893+ ASSERT_EQ(rebuiltTopo.edges.size(), 1);
894+ EXPECT_EQ(rebuiltTopo.edges[0], edge);
895+}
896+ 
799TEST_F(TopoParserTest, Ut_DeserializeBinaryStream_When_Normal_Expect_Success)897TEST_F(TopoParserTest, Ut_DeserializeBinaryStream_When_Normal_Expect_Success)
800{898{
801 DevType devType = DevType::DEV_TYPE_910A;899 DevType devType = DevType::DEV_TYPE_910A;
@@ -810,9 +810,9 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_EmptyRankLevelInfos_Exp
810 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态810 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态
811}811}
812 812 
813-TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoTopoGraph_Expect_NoThrow)813+TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoMatchingPort_Expect_HostPortUnchanged)
814{814{
815- // Given: rankInfo with rankLevelInfos but netLayer doesn't match any built topo graph815+ // Given: the rank address port does not match the HOST+RDMA physical link port
816 NewRankInfo rankInfo;816 NewRankInfo rankInfo;
817 rankInfo.rankId = 0;817 rankInfo.rankId = 0;
818 rankInfo.deviceId = 0;818 rankInfo.deviceId = 0;
@@ -821,6 +821,7 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoTopoGraph_Expect_NoTh
821 AddressInfo addrInfo;821 AddressInfo addrInfo;
822 addrInfo.addr = IpAddress("192.168.1.1");822 addrInfo.addr = IpAddress("192.168.1.1");
823 addrInfo.socketPort_ = 0;823 addrInfo.socketPort_ = 0;
824+ addrInfo.ports.insert("0/0");
824 RankLevelInfo levelInfo;825 RankLevelInfo levelInfo;
825 levelInfo.netLayer = 0;826 levelInfo.netLayer = 0;
826 levelInfo.rankAddrs.push_back(addrInfo);827 levelInfo.rankAddrs.push_back(addrInfo);
@@ -830,16 +831,15 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoTopoGraph_Expect_NoTh
830 831 
831 MockTopoPathAndBuild(BuildEmptyTopo);832 MockTopoPathAndBuild(BuildEmptyTopo);
832 833 
833- // When: PhyTopo built but netLayer=0 has no graph → GetTopoGraph returns nullptr834+ // When & Then: the unified physical graph is scanned, but the unmatched port is ignored
834- // Then: skip nullptr graph, log debug, continue, return without error
835 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));835 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));
836 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);836 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);
837 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态837 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态
838}838}
839 839 
840-TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_MultipleRankLevelInfos_Expect_NoThrow)840+TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_MultipleUnmatchedPorts_Expect_HostPortUnchanged)
841{841{
842- // Given: multiple rankLevelInfos, none with a matching topo graph842+ // Given: multiple rankLevelInfos, none with a port matching the HOST+RDMA physical link
843 NewRankInfo rankInfo;843 NewRankInfo rankInfo;
844 rankInfo.rankId = 0;844 rankInfo.rankId = 0;
845 rankInfo.deviceId = 0;845 rankInfo.deviceId = 0;
@@ -849,6 +849,7 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_MultipleRankLevelInfos_
849 AddressInfo addrInfo;849 AddressInfo addrInfo;
850 addrInfo.addr = IpAddress(StringFormat("192.168.%u.1", i + 1));850 addrInfo.addr = IpAddress(StringFormat("192.168.%u.1", i + 1));
851 addrInfo.socketPort_ = 0;851 addrInfo.socketPort_ = 0;
852+ addrInfo.ports.insert(StringFormat("2/%u", i));
852 RankLevelInfo levelInfo;853 RankLevelInfo levelInfo;
853 levelInfo.netLayer = i;854 levelInfo.netLayer = i;
854 levelInfo.rankAddrs.push_back(addrInfo);855 levelInfo.rankAddrs.push_back(addrInfo);
@@ -859,7 +860,7 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_MultipleRankLevelInfos_
859 860 
860 MockTopoPathAndBuild(BuildEmptyTopo);861 MockTopoPathAndBuild(BuildEmptyTopo);
861 862 
862- // When & Then: iterate all level infos, all graphs nullptr, no throw863+ // When & Then: all unmatched ports are ignored
863 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));864 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));
864 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);865 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);
865 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态866 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态
@@ -867,22 +868,22 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_MultipleRankLevelInfos_
867 868 
868TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_RdmaLinkEmptyRankAddrs_Expect_Continue)869TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_RdmaLinkEmptyRankAddrs_Expect_Continue)
869{870{
870- // Given: host RDMA topology exists at netLayer=3, but rankAddrs is empty871+ // Given: the physical topology has a HOST+ROCE link, but rankAddrs is empty
871 NewRankInfo rankInfo;872 NewRankInfo rankInfo;
872 rankInfo.rankId = 0;873 rankInfo.rankId = 0;
873 rankInfo.deviceId = 0;874 rankInfo.deviceId = 0;
874 rankInfo.localId = 0;875 rankInfo.localId = 0;
875 876 
876 RankLevelInfo levelInfo;877 RankLevelInfo levelInfo;
877- levelInfo.netLayer = 3; // HOST+ROCE link at netLayer=3878+ levelInfo.netLayer = 3;
878- // rankAddrs left EMPTY — triggers rankLevelInfo.rankAddrs.empty() check879+ // rankAddrs is left empty, so no physical port can be matched
879 rankInfo.rankLevelInfos.push_back(levelInfo);880 rankInfo.rankLevelInfos.push_back(levelInfo);
880 881 
881 MOCKER(HrtGetDevice).stubs().will(returnValue(0));882 MOCKER(HrtGetDevice).stubs().will(returnValue(0));
882 883 
883 MockTopoPathAndBuild(BuildHostRdmaTopo);884 MockTopoPathAndBuild(BuildHostRdmaTopo);
884 885 
885- // When & Then: ROCE → RDMA but rankAddrs.empty() → skip, hostPort unchanged886+ // When & Then: the HOST+RDMA link is ignored and hostPort remains unchanged
886 PhyTopo::GetInstance()->Clear();887 PhyTopo::GetInstance()->Clear();
887 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));888 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));
888 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);889 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);
@@ -892,7 +893,7 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_RdmaLinkEmptyRankAddrs_
892// basePort configured, portRange empty → listenPort = basePort + devPhyId893// basePort configured, portRange empty → listenPort = basePort + devPhyId
893TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_BasePort_Expect_HostPortSet)894TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_BasePort_Expect_HostPortSet)
894{895{
895- // Given: HOST+ROCE link at netLayer=3, basePort configured896+ // Given: a matching HOST+ROCE physical port and a configured basePort
896 EnvHostNicConfig fakeConfig;897 EnvHostNicConfig fakeConfig;
897 fakeConfig.hcclHostSocketPortRange = CfgField<std::vector<SocketPortRange>>{898 fakeConfig.hcclHostSocketPortRange = CfgField<std::vector<SocketPortRange>>{
898 "HCCL_HOST_SOCKET_PORT_RANGE", {}, [](const std::string& s) -> std::vector<SocketPortRange> {899 "HCCL_HOST_SOCKET_PORT_RANGE", {}, [](const std::string& s) -> std::vector<SocketPortRange> {
@@ -911,8 +912,9 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_BasePort_Expect_HostPor
911 912 
912 AddressInfo addrInfo;913 AddressInfo addrInfo;
913 addrInfo.addr = IpAddress("192.168.1.1");914 addrInfo.addr = IpAddress("192.168.1.1");
915+ addrInfo.ports.insert("host0");
914 RankLevelInfo levelInfo;916 RankLevelInfo levelInfo;
915- levelInfo.netLayer = 3; // HOST+ROCE link at netLayer=3917+ levelInfo.netLayer = 3;
916 levelInfo.rankAddrs.push_back(addrInfo);918 levelInfo.rankAddrs.push_back(addrInfo);
917 rankInfo.rankLevelInfos.push_back(levelInfo);919 rankInfo.rankLevelInfos.push_back(levelInfo);
918 920 
@@ -932,10 +934,9 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_BasePort_Expect_HostPor
932 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态934 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态
933}935}
934 936 
935-TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoHostLink_Expect_HostPortUnchanged)937+TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_DevicePortOnly_Expect_HostPortUnchanged)
936{938{
937- // Given: graph exists at netLayer=1, but links are DEVICE position instead of HOST939+ // Given: the rank declares only a DEVICE physical port, not the HOST+RDMA port
938- // This tests the path where graph has edges but none match HOST position
939 NewRankInfo rankInfo;940 NewRankInfo rankInfo;
940 rankInfo.rankId = 0;941 rankInfo.rankId = 0;
941 rankInfo.deviceId = 0;942 rankInfo.deviceId = 0;
@@ -944,7 +945,8 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoHostLink_Expect_HostP
944 AddressInfo addrInfo;945 AddressInfo addrInfo;
945 addrInfo.addr = IpAddress("192.168.1.1");946 addrInfo.addr = IpAddress("192.168.1.1");
946 RankLevelInfo levelInfo;947 RankLevelInfo levelInfo;
947- levelInfo.netLayer = 1; // netLayer=1 has DEV links, not HOST948+ addrInfo.ports.insert("0/0");
949+ levelInfo.netLayer = 1;
948 levelInfo.rankAddrs.push_back(addrInfo);950 levelInfo.rankAddrs.push_back(addrInfo);
949 rankInfo.rankLevelInfos.push_back(levelInfo);951 rankInfo.rankLevelInfos.push_back(levelInfo);
950 952 
@@ -952,11 +954,11 @@ TEST_F(RankInfoDetectClientTest, Ut_HostListenPortDetect_NoHostLink_Expect_HostP
952 954 
953 MockTopoPathAndBuild(BuildHostRdmaTopo);955 MockTopoPathAndBuild(BuildHostRdmaTopo);
954 956 
955- // When: netLayer=1 graph exists but has no HOST position links957+ // When: the unified graph contains both DEVICE and HOST links
956 PhyTopo::GetInstance()->Clear();958 PhyTopo::GetInstance()->Clear();
957 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));959 EXPECT_NO_THROW(rankInfoDetectClient_->HostListenPortDetect(rankInfo));
958 960 
959- // Then: hostPort should remain at default since no HOST RDMA link found961+ // Then: hostPort remains unchanged because only the DEVICE port matches
960 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);962 EXPECT_EQ(rankInfo.hostPort, DEFAULT_VALUE_TCPPORT);
961 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态963 PhyTopo::GetInstance()->Clear(); // 清理上一次测试的拓扑状态
962}964}
@@ -267,6 +267,16 @@ TEST_F(HcclRankGraphTest, Ut_HcclRankGraphGetLinks_When_ValidParam_Expect_Return
267 EXPECT_EQ(ret, HCCL_SUCCESS);267 EXPECT_EQ(ret, HCCL_SUCCESS);
268 EXPECT_EQ(linkNum, 1);268 EXPECT_EQ(linkNum, 1);
269 EXPECT_EQ(links[0].linkAttr.hop, 1);269 EXPECT_EQ(links[0].linkAttr.hop, 1);
270+ u32 srcNetLayer = UINT32_MAX;
271+ u32 srcTopoInstId = UINT32_MAX;
272+ u32 dstNetLayer = UINT32_MAX;
273+ u32 dstTopoInstId = UINT32_MAX;
274+ EXPECT_TRUE(Hccl::GetEndpointTopoInfo(links[0].srcEndpointDesc, srcNetLayer, srcTopoInstId));
275+ EXPECT_EQ(srcNetLayer, netLayer);
276+ EXPECT_EQ(srcTopoInstId, 0);
277+ EXPECT_TRUE(Hccl::GetEndpointTopoInfo(links[0].dstEndpointDesc, dstNetLayer, dstTopoInstId));
278+ EXPECT_EQ(dstNetLayer, netLayer);
279+ EXPECT_EQ(dstTopoInstId, 0);
270}280}
271 281 
272TEST_F(HcclRankGraphTest, Ut_HcclRankGraphGetLinks_When_Param_Is_InVaild_Expect_Return_Error)282TEST_F(HcclRankGraphTest, Ut_HcclRankGraphGetLinks_When_Param_Is_InVaild_Expect_Return_Error)