Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "rank_table_info.h"
12 :
13 : #include <unordered_set>
14 : #include <unordered_map>
15 : #include <sstream>
16 : #include <string>
17 : #include "json_parser.h"
18 : #include "invalid_params_exception.h"
19 : #include "exception_util.h"
20 : #include "adapter_error_manager_pub.h"
21 :
22 : namespace Hccl {
23 :
24 24 : void RankTableInfo::Check()
25 : {
26 24 : if (version != "2.0") {
27 1 : HCCL_ERROR("[RankTableInfo::%s] failed with version [%s] is not \"2.0\".", __func__, version.c_str());
28 14 : RPT_INPUT_ERR(
29 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
30 : std::vector<std::string>({version, "version", "2.0"}));
31 1 : THROW<InvalidParamsException>(
32 3 : StringFormat("[RankTableInfo::%s] failed with version is not \"2.0\" in ranktable file.", __func__));
33 : }
34 :
35 23 : if (rankCount > MAX_RANKCOUNT) {
36 13 : RPT_INPUT_ERR(
37 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
38 : std::vector<std::string>(
39 : {std::to_string(rankCount), "rankCount", "lower than " + std::to_string(MAX_RANKCOUNT)}));
40 2 : THROW<InvalidParamsException>(StringFormat(
41 : "[RankTableInfo::%s] failed with rankCount [%u] exceeds maximum limit of [%u]", __func__, rankCount,
42 : MAX_RANKCOUNT));
43 : }
44 :
45 22 : if (rankCount == 0) {
46 14 : RPT_INPUT_ERR(
47 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
48 : std::vector<std::string>({std::to_string(rankCount), "rankCount", "should not be 0"}));
49 2 : THROW<InvalidParamsException>(StringFormat(
50 : "[RankTableInfo::%s] failed with rankCount [%u] exceeds minimum limit of [%u]", __func__, rankCount, 0));
51 : }
52 :
53 21 : if (rankCount != ranks.size()) {
54 14 : RPT_INPUT_ERR(
55 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
56 : std::vector<std::string>(
57 : {std::to_string(rankCount), "rankCount",
58 : "rankCount is equal to rankSize[" + std::to_string(ranks.size()) + "]"}));
59 2 : THROW<InvalidParamsException>(StringFormat(
60 : "[RankTableInfo::%s] failed with rankCount is not equal "
61 : "to rank_list size. version[%s], rankCount[%u], ranks.size[%u]",
62 : __func__, version.c_str(), rankCount, ranks.size()));
63 : }
64 :
65 20 : std::unordered_set<u32> rankIdSet;
66 20 : std::unordered_set<u32> localIdSet;
67 20 : u32 recordedReplaceLocalId{UNDEFIEND_LOCAL_ID};
68 66 : for (auto& rank : ranks) {
69 49 : if (static_cast<u32>(rank.rankId) >= rankCount) {
70 14 : RPT_INPUT_ERR(
71 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
72 : std::vector<std::string>(
73 : {std::to_string(rank.rankId), "rankId", "[0," + std::to_string(rankCount) + ")"}));
74 2 : THROW<InvalidParamsException>(StringFormat(
75 : "[Parse][ClusterInfo][RankTableInfo::%s] failed with rank_id is "
76 : "out of range. version[%s], rankCount[%u], rank_id[%d]",
77 : __func__, version.c_str(), rankCount, rank.rankId));
78 : }
79 48 : if (rankIdSet.count(rank.rankId) > 0) {
80 14 : RPT_INPUT_ERR(
81 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
82 : std::vector<std::string>({std::to_string(rank.rankId), "rankId", "rank_id is not repeat."}));
83 2 : THROW<InvalidParamsException>(StringFormat(
84 : "[Parse][ClusterInfo][RankTableInfo::%s] failed with rank_id is "
85 : "repeat. version[%s], rankCount[%u], rank_id[%d]",
86 : __func__, version.c_str(), rankCount, rank.rankId));
87 : }
88 47 : rankIdSet.insert(rank.rankId);
89 :
90 47 : if (rank.localId != BACKUP_LOCAL_ID && rank.localId != rank.replacedLocalId) {
91 14 : RPT_INPUT_ERR(
92 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
93 : std::vector<std::string>(
94 : {std::to_string(rank.replacedLocalId), "replacedLocalId",
95 : "replacedLocalId equal to locaId[" + std::to_string(rank.localId) + "]"}));
96 2 : THROW<InvalidParamsException>(StringFormat(
97 : "[Parse][ClusterInfo][RankTableInfo::Check] "
98 : "failed with replacedLocalId[%u] not equal to localId[%u].",
99 : rank.replacedLocalId, rank.localId));
100 46 : } else if (rank.localId == BACKUP_LOCAL_ID) {
101 1 : if (recordedReplaceLocalId == UNDEFIEND_LOCAL_ID) {
102 1 : recordedReplaceLocalId = rank.replacedLocalId;
103 : } else {
104 0 : RPT_INPUT_ERR(
105 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
106 : std::vector<std::string>({"NA", "NA", "multiple replaced rank is configured."}));
107 0 : THROW<InvalidParamsException>(StringFormat("[Parse][ClusterInfo][RankTableInfo::Check] "
108 : "multiple replaced rank is configured"));
109 : }
110 : } else {
111 45 : localIdSet.emplace(rank.localId);
112 : }
113 : }
114 :
115 62 : for (u32 rankRange = 0; rankRange < rankCount; rankRange++) {
116 45 : if (rankIdSet.find(rankRange) == rankIdSet.end()) {
117 0 : RPT_INPUT_ERR(
118 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
119 : std::vector<std::string>({std::to_string(rankRange), "rankId", "rank_id is continuous."}));
120 0 : THROW<InvalidParamsException>(StringFormat(
121 : "[Parse][ClusterInfo][RankTableInfo::%s] failed with rank_id is "
122 : "not continuous. version[%s], rankCount[%u], rankRange[%d]",
123 : __func__, version.c_str(), rankCount, rankRange));
124 : }
125 : }
126 :
127 17 : std::vector<std::unordered_map<std::string, u32>> verifyRankAddr;
128 62 : for (auto& rank : ranks) {
129 130 : for (auto& levelInfo : rank.rankLevelInfos) {
130 85 : InsertToRank(levelInfo.netInstId, levelInfo.rankAddrs.size(), verifyRankAddr, levelInfo.netLayer);
131 : }
132 : }
133 :
134 17 : if (localIdSet.find(recordedReplaceLocalId) != localIdSet.end()) {
135 0 : RPT_INPUT_ERR(
136 : true, "EI0014", std::vector<std::string>({"value", "variable", "expect"}),
137 : std::vector<std::string>(
138 : {std::to_string(recordedReplaceLocalId), "recordedReplacedLocalId",
139 : "failed with configuring same local_id with replaced one simutaneously."}));
140 0 : THROW<InvalidParamsException>(StringFormat(
141 : "[Parse][ClusterInfo][RankTableInfo::%s] failed with configuring "
142 : "same local_id[%u] with replaced one simutaneously",
143 : __func__, recordedReplaceLocalId));
144 : }
145 40 : }
146 :
147 27 : void RankTableInfo::Deserialize(const nlohmann::json& rankTableInfoJson, bool isCheck)
148 : {
149 27 : std::string msgVersion = "error occurs when parser object of propName \"version\"";
150 28 : TRY_CATCH_THROW(InvalidParamsException, msgVersion, version = GetJsonProperty(rankTableInfoJson, "version"););
151 26 : std::string msgStatus = "error occurs when parser object of propName \"status\"";
152 :
153 26 : std::string detourStr;
154 26 : std::string msgDetour = "error occurs when parser object of propName \"detour\"";
155 26 : TRY_CATCH_THROW(InvalidParamsException, msgDetour,
156 : detourStr = GetJsonProperty(rankTableInfoJson, "detour", false););
157 26 : if (detourStr == "true") {
158 20 : detour = true;
159 6 : } else if (detourStr == "false" || detourStr == "") {
160 5 : detour = false;
161 : } else {
162 2 : THROW<InvalidParamsException>(StringFormat("Invalid detour value [%s]", detourStr.c_str()));
163 : }
164 :
165 25 : std::string msgRankcount = "error occurs when parser object of propName \"rank_count\"";
166 26 : TRY_CATCH_THROW(InvalidParamsException, msgRankcount,
167 : rankCount = GetJsonPropertyUInt(rankTableInfoJson, "rank_count"););
168 :
169 24 : nlohmann::json rankJsons;
170 24 : std::string msgRanklist = "error occurs when parser object of propName \"rank_list\"";
171 24 : TRY_CATCH_THROW(InvalidParamsException, msgRanklist,
172 : GetJsonPropertyList(rankTableInfoJson, "rank_list", rankJsons););
173 77 : for (auto& rankJson : rankJsons) {
174 53 : NewRankInfo rankInfo;
175 53 : rankInfo.Deserialize(rankJson);
176 53 : ranks.emplace_back(rankInfo);
177 53 : }
178 :
179 : // check
180 24 : if (isCheck) {
181 23 : Check();
182 : }
183 70 : }
184 :
185 85 : void RankTableInfo::CheckAndInsert(
186 : const std::string& levelId, u32 rankAddrSize, std::unordered_map<std::string, u32>& idRankSizeMap) const
187 : {
188 85 : if (idRankSizeMap.find(levelId) != idRankSizeMap.end() && idRankSizeMap[levelId] != rankAddrSize) {
189 0 : THROW<InvalidParamsException>(StringFormat(
190 : "[RankTableInfo::%s] failed with the size of "
191 : "rank_addrs with the same id is different. leveId[%s],"
192 : "rankAddrSize[%u]",
193 : __func__, levelId.c_str(), rankAddrSize));
194 : }
195 85 : idRankSizeMap[levelId] = rankAddrSize;
196 85 : }
197 :
198 85 : void RankTableInfo::InsertToRank(
199 : const std::string& levelId, u32 rankAddrSize, std::vector<std::unordered_map<std::string, u32>>& rankLists,
200 : u32 levelNum) const
201 : {
202 85 : if (rankLists.size() <= levelNum) {
203 27 : rankLists.resize(levelNum + 1);
204 : }
205 85 : CheckAndInsert(levelId, rankAddrSize, rankLists[levelNum]);
206 85 : }
207 :
208 35 : std::string RankTableInfo::Describe() const
209 : {
210 : return StringFormat(
211 35 : "RankTableInfo[version=%s, rankCount=%u, ranks size=%d]", version.c_str(), rankCount, ranks.size());
212 : }
213 :
214 14 : void RankTableInfo::Dump() const
215 : {
216 28 : HCCL_DEBUG("RankTableInfo Dump:");
217 28 : HCCL_DEBUG("%s", Describe().c_str());
218 28 : HCCL_DEBUG("ranks:");
219 21 : for (const auto& rank : ranks) {
220 7 : HCCL_DEBUG("%s", rank.Describe().c_str());
221 14 : for (const auto& levelInfo : rank.rankLevelInfos) {
222 7 : HCCL_DEBUG("- %s", levelInfo.Describe().c_str());
223 : }
224 : }
225 14 : }
226 :
227 6 : RankTableInfo::RankTableInfo(BinaryStream& binaryStream)
228 : {
229 6 : binaryStream >> version >> rankCount;
230 6 : size_t ranksSize = 0;
231 6 : binaryStream >> ranksSize;
232 8 : HCCL_INFO("[%s] version[%s] rankCount[%u] ranks size[%u]", __func__, version.c_str(), rankCount, ranksSize);
233 13 : for (u32 i = 0; i < ranksSize; i++) {
234 7 : NewRankInfo rankInfo(binaryStream);
235 7 : ranks.emplace_back(rankInfo);
236 7 : }
237 6 : binaryStream >> detour;
238 6 : }
239 :
240 13 : void RankTableInfo::GetBinStream(bool isContainLocId, BinaryStream& binaryStream) const
241 : {
242 13 : if (ranks.size() == 0) {
243 0 : std::string msg = StringFormat("ranks size is zero.");
244 0 : THROW<InvalidParamsException>(msg);
245 0 : }
246 25 : HCCL_INFO("[%s] version[%s] rankCount[%u] ranks size[%u]", __func__, version.c_str(), rankCount, ranks.size());
247 :
248 13 : binaryStream << version << rankCount;
249 13 : binaryStream << ranks.size();
250 42 : for (auto& it : ranks) {
251 29 : it.GetBinStream(isContainLocId, binaryStream);
252 : }
253 13 : binaryStream << detour;
254 13 : }
255 :
256 1 : vector<char> RankTableInfo::GetUniqueId(bool isContainLocId) const
257 : {
258 1 : if (ranks.size() == 0) {
259 0 : std::string msg = StringFormat("ranks size is zero.");
260 0 : THROW<InvalidParamsException>(msg);
261 0 : }
262 1 : std::vector<char> result(0);
263 :
264 1 : BinaryStream binaryStream;
265 1 : binaryStream << version << rankCount;
266 :
267 1 : u32 ranksSize = ranks.size();
268 1 : binaryStream << ranksSize;
269 2 : for (auto& it : ranks) {
270 1 : it.GetBinStream(isContainLocId, binaryStream);
271 : }
272 :
273 1 : binaryStream.Dump(result);
274 1 : return result;
275 1 : }
276 :
277 1 : void RankTableInfo::UpdateRankTable(const RankTableInfo& localRankInfo)
278 : {
279 : // version
280 1 : if (detour) {
281 0 : CHK_PRT_THROW(
282 : localRankInfo.detour != true, HCCL_ERROR("[%s] detour cfg is not same with other ranks.", __func__),
283 : InvalidParamsException, "updateRankTableInfo error");
284 : }
285 1 : detour = localRankInfo.detour;
286 1 : if (rankCount == 0) {
287 1 : version = localRankInfo.version;
288 : } else {
289 0 : CHK_PRT_THROW(
290 : version != localRankInfo.version,
291 : HCCL_ERROR(
292 : "[%s] version[%s] error, local version[%s] .", __func__, version.c_str(),
293 : localRankInfo.version.c_str()),
294 : InvalidParamsException, "updateRankTableInfo error");
295 : }
296 :
297 : // ranks size
298 1 : CHK_PRT_THROW(
299 : localRankInfo.ranks.size() == 0, HCCL_ERROR("[%s] ranks size is zero.", __func__), InvalidParamsException,
300 : "updateRankTableInfo error");
301 :
302 1 : ranks.insert(ranks.end(), localRankInfo.ranks.begin(), localRankInfo.ranks.end());
303 1 : rankCount++;
304 :
305 1 : HCCL_INFO("[%s] success, current rankTableInfo[%s]", __func__, Describe().c_str());
306 1 : }
307 :
308 5 : std::unordered_map<u32, std::unordered_map<IpAddress, u32>> RankTableInfo::GetRankDeviceListenPortMap()
309 : {
310 5 : std::unordered_map<u32, std::unordered_map<IpAddress, u32>> ranklListenPortMap;
311 25 : for (auto& rankinfo : ranks) {
312 20 : std::unordered_map<IpAddress, u32> listenPortMap;
313 80 : for (auto& rankLevelInfo : rankinfo.rankLevelInfos) {
314 160 : for (auto& rankAddr : rankLevelInfo.rankAddrs) {
315 100 : listenPortMap.insert(std::make_pair(rankAddr.addr, rankAddr.socketPort_));
316 : }
317 : }
318 20 : listenPortMap.insert(std::make_pair(DEVICE_PORT_KEY_IPADDRESS, rankinfo.devicePort));
319 20 : ranklListenPortMap.insert(std::make_pair(rankinfo.rankId, listenPortMap));
320 20 : }
321 5 : return ranklListenPortMap;
322 0 : }
323 :
324 : } // namespace Hccl
|