Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 : #ifndef CLUSTER_MONITOR_H
11 : #define CLUSTER_MONITOR_H
12 : #include <atomic>
13 : #include <thread>
14 : #include <map>
15 : #include <deque>
16 : #include <mutex>
17 : #include "hcclCommDfx.h"
18 : #include "ring_buffer.h"
19 : #include "coll_comm.h"
20 : #include "reference_map.h"
21 : #include "log.h"
22 : #include "hccl/hccl_types.h"
23 : #include "hccl_common.h"
24 : #include "hccl_comm_socket_c_adpt.h"
25 : #include "hccl_communicator.h"
26 : #include "../../common/loggers/comm_addr_logger.h"
27 :
28 : namespace hcomm {
29 : using ClusterUIDType = struct HcclClusterMonitorUID {
30 : char id[2048] = {0}; // netInstanceId + localId 最大不超过2048字节
31 1055 : bool operator==(const HcclClusterMonitorUID& that) const { return std::string(this->id) == std::string(that.id); }
32 30 : bool operator!=(const HcclClusterMonitorUID& that) const { return std::string(this->id) != std::string(that.id); }
33 310 : bool operator<(const HcclClusterMonitorUID& that) const { return std::string(this->id) < std::string(that.id); }
34 : };
35 : } // namespace hcomm
36 :
37 : namespace std {
38 : template <>
39 : class hash<hcomm::HcclClusterMonitorUID> {
40 : public:
41 723 : size_t operator()(const hcomm::HcclClusterMonitorUID& uid) const { return hash<string>()(string(uid.id)); }
42 : };
43 : } // namespace std
44 :
45 : namespace hcomm {
46 : enum class ClusterMonitorStatus {
47 : CLUSTER_MONITOR_OK,
48 : CLUSTER_MONITOR_LOST,
49 : CLUSTER_MONITOR_NOTIFY,
50 : CLUSTER_MONITOR_CQE_ERR,
51 : CLUSTER_MONITOR_OPRETRY_NOT_SUPPORT,
52 : CLUSTER_MONITOR_STUCK,
53 : CLUSTER_MONITOR_INCONSISTENT
54 : };
55 :
56 : struct ErrorCqeInfo {
57 : u32 cqeLocalId = 0;
58 : u32 cqeRemoteLocalId = 0;
59 : uint16_t cqeStatus = 0;
60 : std::string cqeLocalEid = "";
61 : std::string cqeRemoteEid = "";
62 : std::string cqeRemoteInsId = "";
63 : std::string cqeLocalInsId = "";
64 : };
65 : const std::map<ClusterMonitorStatus, std::string> CLUSTER_MONITOR_STATUS_STR_MAP{
66 : {ClusterMonitorStatus::CLUSTER_MONITOR_OK, "OK"},
67 : {ClusterMonitorStatus::CLUSTER_MONITOR_LOST, "LOST"},
68 : {ClusterMonitorStatus::CLUSTER_MONITOR_NOTIFY, "NOTIFY"},
69 : {ClusterMonitorStatus::CLUSTER_MONITOR_CQE_ERR, "CQE ERROR"}};
70 :
71 1 : inline std::string GetClusterMonitorStatusStr(ClusterMonitorStatus status)
72 : {
73 1 : auto iter = CLUSTER_MONITOR_STATUS_STR_MAP.find(status);
74 1 : if (iter == CLUSTER_MONITOR_STATUS_STR_MAP.end()) {
75 0 : return "Unknown";
76 : } else {
77 1 : return iter->second;
78 : }
79 : }
80 :
81 : struct ClusterMonitorFrame {
82 : ClusterUIDType src{}; // 心跳建链的本端
83 : ClusterUIDType dst{}; // 心跳建链的远端
84 : ClusterUIDType crimer{}; // 异常的节点
85 : ClusterUIDType informer{}; // 把异常传输给自己的节点
86 : ClusterMonitorStatus status = ClusterMonitorStatus::CLUSTER_MONITOR_OK;
87 : HcclUs TOARelative{}; // time of arrival (Relative)
88 : HcclSystemTime TOASystem{}; // time of arrival (System)
89 : char reserved[256] = {0}; // 预留256个字段,后续扩展可存储其他信息
90 2 : ClusterMonitorFrame() {}
91 6 : ClusterMonitorFrame(
92 : ClusterUIDType& crimer, ClusterUIDType& informer, ClusterMonitorStatus status, HcclUs TOARelativeIn,
93 : HcclSystemTime TOASystemIn)
94 6 : : crimer(crimer),
95 6 : informer(informer),
96 6 : status(status),
97 6 : TOARelative(TOARelativeIn),
98 6 : TOASystem(TOASystemIn)
99 6 : {}
100 12 : ClusterMonitorFrame(
101 : ClusterUIDType& src, ClusterUIDType& dst, ClusterUIDType& crimer, ClusterUIDType& informer,
102 : ClusterMonitorStatus status)
103 12 : : src(src),
104 12 : dst(dst),
105 12 : crimer(crimer),
106 12 : informer(informer),
107 12 : status(status)
108 12 : {}
109 : };
110 :
111 : struct ClusterMonitorSocketCtx { // 原ConnInfo
112 : SocketDesc socketDesc; // 与对端连接的描述符
113 : SocketHandle socketHandler; // 引用头文件定义
114 : std::queue<ClusterMonitorFrame> sendBuffer; // 用来发送的帧队列
115 : u32 restSize = 0; // 剩余待发送的帧长度
116 : hccl::RingBuffer recvBuffer; // 用来接收的环形帧队列
117 : u32 lostNum = 0; // 丢失的心跳个数
118 : bool newConn = false; // 是否是新增的连接
119 5 : ClusterMonitorSocketCtx() {}
120 1 : ClusterMonitorSocketCtx(SocketDesc& socketDesc, bool newConn)
121 1 : : socketDesc(socketDesc),
122 1 : socketHandler(nullptr),
123 1 : newConn(newConn)
124 1 : {}
125 :
126 6 : void PrintSocketDesc(std::string tag) const
127 : {
128 6 : std::string localAddr = hcomm::logger::CommAddrLogger::ToString(socketDesc.localEndpoint.commAddr);
129 6 : std::string remoteAddr = hcomm::logger::CommAddrLogger::ToString(socketDesc.remoteEndpoint.commAddr);
130 6 : HCCL_DEBUG(
131 : "[%s] socketDesc: localEndpoint: {commAddr: %s, EndpointLocType: %d}, "
132 : "remoteEndpoint: {commAddr: %s, EndpointLocType: %d}, tag: %s, role: %d, listenPort: %u",
133 : tag.c_str(), localAddr.c_str(), socketDesc.localEndpoint.loc.locType, remoteAddr.c_str(),
134 : socketDesc.remoteEndpoint.loc.locType, socketDesc.tag, socketDesc.role, socketDesc.listenPort);
135 6 : }
136 : };
137 :
138 : struct UIDContext {
139 : ClusterUIDType uid;
140 : uint32_t netLayer{0};
141 : uint32_t rankId{0};
142 : uint32_t localId{0}; // 用来netLayer=0的时候排序使用
143 : std::string netInstId{}; // 用来netLayer>1的时候排序使用
144 : UIDContext() {}
145 21 : UIDContext(ClusterUIDType& uid, uint32_t netLayer, uint32_t rankId, uint32_t localId, std::string netInstId)
146 21 : : uid(uid),
147 21 : netLayer(netLayer),
148 21 : rankId(rankId),
149 21 : localId(localId),
150 21 : netInstId(netInstId)
151 21 : {}
152 : };
153 :
154 : struct ClusterUIDCxt {
155 : std::string netInstId;
156 : uint32_t localId;
157 : ClusterUIDCxt() {}
158 20 : ClusterUIDCxt(std::string& netInstId, uint32_t localId) : netInstId(netInstId), localId(localId) {}
159 : };
160 :
161 : class ClusterMonitor {
162 : public:
163 : HcclResult RegisterToClusterMonitor(HcclComm comm);
164 : HcclResult UnRegisterToClusterMonitor(const hccl::CollComm* collComm);
165 : ClusterUIDType FormatUID(ClusterUIDCxt cxt) const;
166 : std::string GetUID(const ClusterUIDType& uid) const;
167 : std::string FormatConnTag(HcommSocketRole role, std::pair<ClusterUIDType, ClusterUIDType> uidPair) const;
168 : HcclResult InsertClusterMonitorCtx(
169 : HcclComm comm, UIDContext remoteCtx, std::map<ClusterUIDType, ClusterMonitorSocketCtx>& needConnectRank);
170 : HcclResult GetSocketDescFromRankInfo(
171 : HcclComm comm, uint32_t remoteRank, uint32_t netLayer, const ClusterUIDType& remoteUID, SocketDesc& socketDesc);
172 : HcclResult GetSamePlaneRank(
173 : HcclComm comm, std::vector<UIDContext> singlePlaneCtx,
174 : std::map<ClusterUIDType, ClusterMonitorSocketCtx>& needConnectRank);
175 : HcclResult GetConnectRank(
176 : HcclComm comm, std::map<ClusterUIDType, ClusterMonitorSocketCtx>& needConnectRank,
177 : std::map<uint32_t, std::vector<UIDContext>> uidCtxs, std::vector<uint32_t>& netLayersVector);
178 : void CreateHBLinksAsync();
179 : void
180 : SetStatus(ClusterUIDType& crimer, ClusterUIDType& informer, ClusterMonitorStatus status, bool needBroadcast = true);
181 : void MonitorThread();
182 : HcclResult RunMonitorThread();
183 : HcclResult
184 : SendFrame(ClusterUIDType& dst, ClusterUIDType& crimer, ClusterUIDType& informer, ClusterMonitorStatus status);
185 : void DelErrorSocket();
186 : void ProcessExceptionEvent();
187 : HcclResult RecvFrame(ClusterUIDType rem);
188 : HcclResult ParseFrame(ClusterMonitorFrame& cmFrame, ClusterUIDType& src);
189 : HcclResult DeInit();
190 : void GetCqeErrInfoFromTaskException(
191 : u32 remoteLocalId, uint16_t status, std::string localEid, std::string remoteEid, std::string remoteInsId);
192 : std::vector<std::string> GetErrStatusVecFromCluserMonitor();
193 : std::vector<std::string>
194 : PrintEvents(std::map<ClusterMonitorStatus, std::queue<ClusterMonitorFrame>>& keyEvents) const;
195 : void MakeErrMsg(std::queue<ClusterMonitorFrame>& keyEvents, std::vector<std::string>& errStatusVec) const;
196 586 : ClusterMonitor() = default;
197 : ~ClusterMonitor();
198 :
199 : private:
200 : HcclResult GetRemEndpointDescs(
201 : HcclComm comm, std::map<uint32_t, std::vector<UIDContext>>& uidCtxs, std::vector<uint32_t>& netLayersVector);
202 : void GetRemEndpointDescsPerLayer(
203 : uint32_t netLayer, HcclComm comm, const Hccl::RankGraph* rankGraph, const hccl::CollComm* collComm,
204 : std::map<uint32_t, std::vector<UIDContext>>& uidCtxs, std::set<uint32_t>& rankIdsSet);
205 :
206 : HcclResult
207 : ProcessConnectRanks(const std::string& commId, std::map<ClusterUIDType, ClusterMonitorSocketCtx>& needConnectRank);
208 : void ClearClusterLinkContext(const std::string& commId, std::set<ClusterUIDType>& remInQueue);
209 : bool UnregisterCommIdFromMaps(const std::string& commId, const std::set<ClusterUIDType>& remInQueue);
210 : HcclResult CreateTransportHandle(ClusterMonitorSocketCtx& info) const;
211 : HcclResult OnConnectionEstablished(
212 : const std::string& commId, const ClusterUIDType& rem, ClusterMonitorSocketCtx& needConnectRank);
213 : HcclResult SendFrameFromBuffer(ClusterUIDType& dst, ClusterMonitorFrame& cmFrame);
214 :
215 : void CreateLinkWithRemotePonit(std::string commId, ClusterUIDType rem, ClusterMonitorSocketCtx needConnectRank);
216 :
217 : struct FrameStatus { // 专门用来给frame设置对应的状态
218 : ClusterMonitorStatus status = ClusterMonitorStatus::CLUSTER_MONITOR_OK;
219 : ClusterUIDType informer;
220 : bool needBroadcast = false;
221 7 : FrameStatus() {}
222 : };
223 :
224 : enum class MonitorLinkStatus {
225 : MONITOR_LINK_NOT_START,
226 : MONITOR_LINK_BUILDING,
227 : MONITOR_LINK_COMPLETED,
228 : };
229 :
230 : uint32_t myRankLocalId_;
231 : std::string myRankNetInstId_;
232 : ClusterUIDType myRankUID_;
233 : s32 deviceLogicId_{0};
234 :
235 : bool clusterMonitorThreadFlag_ = false;
236 : std::unique_ptr<std::thread> clusterMonitorThread_;
237 : // 防止重复初始化
238 : bool initialized_ = false;
239 : uint32_t lostThreshold_ = 0;
240 : std::atomic<bool> isDeInit_{false};
241 : std::atomic<bool> linkThreadRunning_{false};
242 :
243 : // 防止多线程同时初始化的线程锁
244 : std::mutex threadLock_;
245 : std::vector<ClusterUIDType> errorSocket_;
246 : std::queue<ClusterMonitorFrame> errStatusQueue_;
247 :
248 : // 通信域名称为key,ClusterUIDType表示1个节点,
249 : // bool表示0或1,是否连接上,用来指示是否有过这个通信域以及对应通信域里待连接的节点是否以及连接上,原groupMap_
250 : std::map<std::string, std::map<ClusterUIDType, bool>> commIdMap_;
251 :
252 : // 通信域名称为key, 一个通信域有多个待连接心跳的connInfo,存储到该结构体,待monitor线程轮询拿到, 原hbLinkConnInfo_
253 : std::map<std::string, std::queue<std::pair<ClusterUIDType, ClusterMonitorSocketCtx>>> clusterLinkContext_{};
254 : std::mutex clusertMonitorLinkMtx_; // 用来锁住clusterLinkContext_,原clusterLinkContext_
255 :
256 : // 存储UID与监控连接状态的map, NOT_START/BUILDING/COMPILETED,原rankId2LinkStatusMap_
257 : std::map<ClusterUIDType, MonitorLinkStatus> monitorLinkStatusMap_;
258 :
259 : // 存储UID与连接上下文的计数map,由于多个通信域都有可能使用同一个context去连接远端,需要计数处理,解注册时计数--,原rankId2SocketMap_
260 : hccl::ReferenceMap<ClusterUIDType, ClusterMonitorSocketCtx> uid2SocketRefMap_;
261 :
262 : // 用来做帧的统计计数,设置对应帧的状态,原rankId2StatusMap_
263 : hccl::ReferenceMap<ClusterUIDType, FrameStatus> uid2FrameStatusMap_;
264 :
265 : // uid与thread的维护关系,不同的remote起不同的异步建链线程,原linkThreadMap_
266 : std::map<ClusterUIDType, std::unique_ptr<std::thread>> linkThreadMap_{};
267 :
268 : // UnRegister 摘下、延后到 DeInit(join 之后) 再 SocketDestroy 的句柄
269 : std::vector<SocketHandle> pendingDestroySockets_;
270 :
271 : // 保存错误的节点
272 : std::queue<ClusterUIDType> errRankQueue_;
273 :
274 : ErrorCqeInfo cqeErrInfo_;
275 : };
276 : } // namespace hcomm
277 : #endif // CLUSTER_MONITOR_H
|