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 <cmath>
12 : #include "stream_utils.h"
13 : #include "coll_alg_utils.h"
14 :
15 : namespace hccl {
16 :
17 4 : bool IsAlgTypeLevel0Mesh(const AlgTypeLevel0 &originalAlgTypeLevel0)
18 : {
19 4 : return originalAlgTypeLevel0 == AlgTypeLevel0::ALG_LEVEL0_NP_MESH ||
20 0 : originalAlgTypeLevel0 == AlgTypeLevel0::ALG_LEVEL0_4P_MESH ||
21 4 : originalAlgTypeLevel0 == AlgTypeLevel0::ALG_LEVEL0_2P_MESH ||
22 4 : originalAlgTypeLevel0 == AlgTypeLevel0::ALG_LEVEL0_1P_MESH;
23 : }
24 :
25 2 : bool IsAlltoAllvcSatisfyBufferSize(const OpParam& param, u32 userRankSize, u64 cclbufferSize) {
26 6 : for (u32 i = 0; i < userRankSize; i++) {
27 4 : u64 maxSendLength = 0;
28 4 : u64 maxRecvLength = 0;
29 : // 计算每个rank需使用的中转内存大小是否满足cclbuffer大小
30 12 : for (u32 j = 0; j < userRankSize; j++) {
31 8 : u64 curSendCounts =
32 8 : *(static_cast<const u64 *>(param.All2AllDataDes.sendCountMatrix) + i * userRankSize + j);
33 8 : u64 curSendLength = curSendCounts * SIZE_TABLE[param.All2AllDataDes.sendType];
34 :
35 8 : u64 curRecvCounts =
36 8 : *(static_cast<const u64 *>(param.All2AllDataDes.sendCountMatrix) + i + userRankSize * j);
37 8 : u64 curRecvLength = curRecvCounts * SIZE_TABLE[param.All2AllDataDes.recvType];
38 :
39 8 : maxSendLength += curSendLength;
40 8 : maxRecvLength += curRecvLength;
41 : }
42 4 : if ((maxSendLength <= cclbufferSize) || (maxRecvLength <= cclbufferSize)) {
43 0 : return false;
44 : }
45 : }
46 2 : return true;
47 : }
48 :
49 39 : bool IsSupportUnifiedMarch(const OpParam& param, const TopoType& topoType, u32 serverNum, u32 superPodNum)
50 : {
51 39 : bool isGraphMode = (GetWorkflowMode() == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB);
52 39 : bool isDoubleRing = topoType == TopoType::TOPO_TYPE_NP_DOUBLE_RING;
53 39 : bool isSingleServer = (serverNum == 1) && (superPodNum == 1);
54 39 : return (param.aicpuUnfoldMode) && isDoubleRing && isGraphMode && isSingleServer;
55 : }
56 :
57 10 : bool IsSupportDirectFullmeshForAlltoallv(const OpParam& param, DevType deviceType, bool useSuperPodMode, u32 serverNum,
58 : bool isSingleMeshAggregation, u32 userRankSize, u64 cclbufferSize)
59 : {
60 10 : bool isOpbase = (GetWorkflowMode() == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE);
61 10 : bool baseInfo = (deviceType == DevType::DEV_TYPE_910_93 || (deviceType == DevType::DEV_TYPE_910B && isOpbase));
62 10 : bool isHCCS = false;
63 10 : bool isSatisfyBuffer = true;
64 10 : if (deviceType == DevType::DEV_TYPE_910_93) {
65 0 : isHCCS = (serverNum > 1) ?
66 0 : (!GetExternalInputInterHccsDisable() && useSuperPodMode) : true;
67 10 : } else if (deviceType == DevType::DEV_TYPE_910B) {
68 10 : if (param.opType == HcclCMDType::HCCL_CMD_ALLTOALLV) {
69 : // alltoallv算子单机和多机(小于8机64卡)acl graph场景都走directfullmesh算法,且不支持卡数不一致场景
70 8 : aclmdlRI rtModel = nullptr;
71 8 : bool isCapture = false;
72 8 : if (isOpbase) { // acl graph模式下获取capture信息,图模式需要规避
73 8 : HcclResult retCapture = GetStreamCaptureInfo(param.stream.ptr(), rtModel, isCapture);
74 8 : CHK_PRT_CONT(retCapture != HCCL_SUCCESS,
75 : HCCL_ERROR("Get capture status error. return[%d], capture model", retCapture));
76 : }
77 8 : isHCCS = (userRankSize <= MAX_ALLTOALLV_DIRECT_FULLMESH_RANKSIZE &&
78 16 : serverNum <= MAX_ALLTOALLV_DIRECT_FULLMESH_SERVER_NUM && isCapture) ||
79 : isSingleMeshAggregation;
80 : // A+X单机双module启用下, 未使能RDMA不能走directfullmesh算法
81 8 : bool isDifModule = serverNum == 1 && !isSingleMeshAggregation && userRankSize > HCCL_ALLTOALLV_P2P_SIZE;
82 8 : if (isDifModule && (GetExternalInputIntraRoceSwitch() == 0)) {
83 0 : isHCCS = false;
84 : }
85 : } else {
86 : // alltoall和alltoallvc在A2上仅支持单机
87 2 : isHCCS = (isSingleMeshAggregation) ? (true) : (false);
88 2 : if (isHCCS) {
89 : // A2场景下alltoall和alltoallvc需满足数据量大于cclbuffer大小条件
90 2 : isSatisfyBuffer = IsAlltoAllvcSatisfyBufferSize(param, userRankSize, cclbufferSize);
91 : }
92 : }
93 : }
94 10 : HCCL_DEBUG("[IsSupportDirectFullmeshForAlltoallv]baseInfo[%u], isOpbase[%u], isHCCS[%u], isSatisfyBuffer[%u]",
95 : baseInfo, isOpbase, isHCCS, isSatisfyBuffer);
96 10 : return baseInfo && isHCCS && isSatisfyBuffer;
97 : }
98 :
99 150 : bool SatisfyIntraSuperPod(DevType deviceType, u32 rankSize, bool useSuperPodMode, u32 superPodNum)
100 : {
101 150 : bool rankSizeSupport = (rankSize <= MAX_ALLTOALL_MESH_ALGO_RANK_INTRA_MESH);
102 150 : bool isDevice91093 = (deviceType == DevType::DEV_TYPE_910_93);
103 150 : bool isHCCS = !GetExternalInputInterHccsDisable() && useSuperPodMode;
104 149 : bool isSingleSuperPod = superPodNum == 1;
105 149 : bool isOpbase = (GetWorkflowMode() == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE);
106 148 : return (isDevice91093 && rankSizeSupport && isHCCS && isSingleSuperPod && isOpbase);
107 : }
108 :
109 149 : bool FullmeshPairwiseSatisfyHighPerfAlltoallMeshCondition(DevType deviceType, u32 rankSize, bool useSuperPodMode,
110 : std::vector<HcclAlgoType> algoConfig)
111 : {
112 149 : bool rankSizeSupport = (rankSize <= MAX_ALLTOALL_MESH_ALGO_RANK_INTRA_MESH);
113 149 : bool isDevice91093 = (deviceType == DevType::DEV_TYPE_910_93);
114 : bool twoLevelIntraUseMesh =
115 149 : (algoConfig[HCCL_ALGO_LEVEL_0] == HcclAlgoType::HCCL_ALGO_TYPE_FULLMESH &&
116 0 : algoConfig[HCCL_ALGO_LEVEL_1] == HcclAlgoType::HCCL_ALGO_TYPE_PAIRWISE);
117 149 : bool isHCCS = !GetExternalInputInterHccsDisable() && useSuperPodMode;
118 149 : HCCL_DEBUG("[FullmeshPairwiseSatisfyHighPerfAlltoallMeshCondition]isDevice91093 %u twoLevelIntraUseMesh %u isHCCS %u",
119 : isDevice91093, twoLevelIntraUseMesh, isHCCS);
120 150 : CHK_PRT_CONT(!(twoLevelIntraUseMesh && !isDevice91093),
121 : HCCL_WARNING("[FullmeshPairwiseSatisfyHighPerfAlltoallMeshCondition] AllToAll read only algorithm only "
122 : "support 910_93 device type, use default algorithm type"));
123 150 : CHK_PRT_CONT(!(twoLevelIntraUseMesh && !isHCCS),
124 : HCCL_WARNING("[FullmeshPairwiseSatisfyHighPerfAlltoallMeshCondition] AllToAll read only algorithm depends "
125 : "on HCCS, use default algorithm type"));
126 150 : return (isDevice91093 && twoLevelIntraUseMesh && rankSizeSupport && isHCCS);
127 : }
128 :
129 12 : bool IsConfigAHCAlgo(std::map<HcclCMDType, std::vector<HcclAlgoType>> algoConfigMap)
130 : {
131 : const std::set<HcclCMDType> hcclSupportAHCOpSet = {
132 : HcclCMDType::HCCL_CMD_ALLREDUCE, HcclCMDType::HCCL_CMD_REDUCE_SCATTER, HcclCMDType::HCCL_CMD_ALLGATHER
133 24 : };
134 :
135 48 : for (const auto& opType : hcclSupportAHCOpSet) {
136 36 : HcclAlgoType algoConfigLevel1 = algoConfigMap[opType][HCCL_ALGO_LEVEL_1];
137 36 : bool isConfigAHC =
138 36 : (algoConfigLevel1 == HcclAlgoType::HCCL_ALGO_TYPE_AHC ||
139 : algoConfigLevel1 == HcclAlgoType::HCCL_ALGO_TYPE_AHC_BROKE);
140 36 : if (isConfigAHC) {
141 0 : return true;
142 : }
143 : }
144 12 : return false;
145 12 : }
146 :
147 : template<typename keyType>
148 1995 : std::string GetAlgoString(const std::map<keyType, std::string>& levelMap, keyType key) {
149 1995 : auto iter = levelMap.find(key);
150 1995 : if (iter == levelMap.end()) {
151 4 : return "invalid algo type";
152 : } else {
153 1993 : return iter->second;
154 : }
155 : }
156 :
157 665 : std::string AlgTypeToStr(const AlgType algType)
158 : {
159 665 : AlgTypeLevel0 algTypeLevel0 = algType.algoLevel0;
160 665 : AlgTypeLevel1 algTypeLevel1 = algType.algoLevel1;
161 665 : AlgTypeLevel2 algTypeLevel2 = algType.algoLevel2;
162 665 : std::string algStrLevel0 = GetAlgoString(HCCL_ALGO_LEVEL0_NAME_MAP, algTypeLevel0);
163 665 : std::string algStrLevel1 = GetAlgoString(HCCL_ALGO_LEVEL1_NAME_MAP, algTypeLevel1);
164 665 : std::string algStrLevel2 = GetAlgoString(HCCL_ALGO_LEVEL2_NAME_MAP, algTypeLevel2);
165 665 : std::string algStr;
166 665 : algStr.append("level0:").append(algStrLevel0).append(",level1:").append(algStrLevel1).append(",level2:").append(algStrLevel2);
167 665 : return algStr;
168 665 : }
169 :
170 58880 : bool Is310P3Common(bool isHaveCpuRank, DevType deviceType)
171 : {
172 58880 : return !isHaveCpuRank && !Is310PDevice() && deviceType == DevType::DEV_TYPE_310P3;
173 : }
174 :
175 150 : u64 CalculatePiplineSliceNum(HcclCMDType opType, u64 dataSize, AlgType algType, DevType deviceType,
176 : u32 deviceNumPerAggregation, u32 moduleNum)
177 : {
178 150 : u64 piplineSliceNum = 0;
179 150 : bool isInterRing = false;
180 150 : if (algType.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_RING) {
181 36 : isInterRing = true;
182 : } else {
183 114 : isInterRing = false;
184 : }
185 :
186 : do {
187 150 : if (!GetExternalInputHcclEnablePipline()) {
188 150 : break;
189 : }
190 : /* 不支持pipline流水的场景 */
191 : // 支持的硬件场景
192 0 : if (deviceType != DevType::DEV_TYPE_910B || deviceNumPerAggregation < HCCL_DEVICE_NUM_TWO ||
193 : moduleNum < HCCL_DEVICE_NUM_TWO) {
194 : break;
195 : }
196 : // 支持的算子和算法场景
197 0 : if (opType != HcclCMDType::HCCL_CMD_ALLREDUCE ||
198 0 : (isInterRing && moduleNum > MAX_RING_PIPLINE_SERVER_NUM)) {
199 : break;
200 : }
201 0 : u64 sliceNumTemp = std::min(dataSize / deviceNumPerAggregation / MIN_PER_LINK_DATA_SIZE, MAX_PIPLINE_SLICE_NUM);
202 : // 图模式切分数量 <= 1时, 不做切分
203 0 : if (GetWorkflowMode() == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OPS_KERNEL_INFO_LIB &&
204 : sliceNumTemp <= MIN_PIPLINE_SLICE_NUM) {
205 0 : break;
206 : }
207 :
208 : /* 支持pipline流水, 但数据量不足以进行切分的场景 */
209 : // Server间使用Ring算法, 且单Server数据量<64KB时, 不做切分
210 0 : if ((isInterRing && dataSize / moduleNum < MIN_RING_DATA_SIZE)) {
211 0 : sliceNumTemp = 1;
212 : }
213 : // 支持pipline但数据量不满足切分条件时, 返回1, 用于单算子场景预申请流资源
214 0 : piplineSliceNum = (sliceNumTemp == 0) ? 1 : sliceNumTemp;
215 : } while (0);
216 150 : return piplineSliceNum;
217 : }
218 :
219 7 : bool HcclOpInplaceDefaultCase(const OpParam ¶m, u8 &isInplaceStatus)
220 : {
221 : // unknown op
222 7 : if (param.inputPtr != param.outputPtr) {
223 : // 可以走重执行
224 4 : HCCL_DEBUG("[CollAlgOperator][IsHcclOpInplace]param.inputPtr[%p] != param.outputPtr[%p]. They do not overlap.",
225 : param.inputPtr, param.outputPtr);
226 4 : isInplaceStatus = 0;
227 4 : return false;
228 : } else {
229 3 : HCCL_DEBUG("[CollAlgOperator][IsHcclOpInplace]param.inputPtr[%p] == param.outputPtr[%p]. They overlap.",
230 : param.inputPtr, param.outputPtr);
231 3 : isInplaceStatus = 1;
232 3 : return true;
233 : }
234 : }
235 :
236 91 : bool IsInputOutputOverlap(const OpParam ¶m, u64 inputDataSize, u64 outputDataSize, u8 &isInplaceStatus)
237 : {
238 91 : if (inputDataSize == 0 || outputDataSize == 0) {
239 : // 不存在overlap情况
240 3 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]The inputPtr[%p] dataSize[%llu], the outputPtr[%p] dataSize[%llu]."
241 : "They do not overlap.", param.inputPtr, inputDataSize, param.outputPtr, outputDataSize);
242 4 : isInplaceStatus = 0;
243 4 : return false;
244 : }
245 88 : u64 inputStart = reinterpret_cast<u64>(param.inputPtr);
246 88 : u64 inputEnd = reinterpret_cast<u64>(param.inputPtr) + inputDataSize - 1;
247 88 : u64 outputStart = reinterpret_cast<u64>(param.outputPtr);
248 88 : u64 outputEnd = reinterpret_cast<u64>(param.outputPtr) + outputDataSize - 1;
249 :
250 88 : if (inputStart <= outputEnd && outputStart <= inputEnd) {
251 12 : HCCL_DEBUG("[CollAlgOperator][OpRetry][AICPU]The inputPtr[%p] dataSize[%llu], the outputPtr[%p] dataSize[%llu]."
252 : "They overlap.", param.inputPtr, inputDataSize, param.outputPtr, outputDataSize);
253 12 : isInplaceStatus = 2; // The status 2 is overlap with dataSize.
254 12 : return true;
255 : } else {
256 76 : HCCL_DEBUG("[CollAlgOperator][OpRetry][AICPU]The inputPtr[%p] dataSize[%llu], the outputPtr[%p] dataSize[%llu]."
257 : "They do not overlap.", param.inputPtr, inputDataSize, param.outputPtr, outputDataSize);
258 87 : isInplaceStatus = 0;
259 87 : return false;
260 : }
261 : }
262 :
263 101 : bool IsInputOutPtrNotNullPtr(const OpParam ¶m, u8 &isInplaceStatus)
264 : {
265 101 : if (param.inputPtr == nullptr || param.outputPtr == nullptr) {
266 : // 不存在overlap情况
267 2 : HCCL_DEBUG("[CollAlgOperator][OpRetry][AICPU]param.tag[%s], the inputPtr[%p], the outputPtr[%p]."
268 : "They do not overlap.", param.tag.c_str(), param.inputPtr, param.outputPtr);
269 2 : isInplaceStatus = 0;
270 2 : return false;
271 : } else {
272 99 : return true;
273 : }
274 : }
275 :
276 100 : u32 InplaceDataUnitSize(const HcclCMDType &opType, const OpParam ¶m)
277 : {
278 100 : u32 unitSize = 0;
279 100 : if (opType != HcclCMDType::HCCL_CMD_ALLTOALLV && opType != HcclCMDType::HCCL_CMD_ALLTOALLVC &&
280 97 : opType != HcclCMDType::HCCL_CMD_ALLTOALL && opType != HcclCMDType::HCCL_CMD_ALLGATHER_V &&
281 93 : opType != HcclCMDType::HCCL_CMD_REDUCE_SCATTER_V) {
282 93 : if (param.DataDes.dataType >= HCCL_DATA_TYPE_RESERVED) {
283 0 : HCCL_WARNING("[InplaceDataUnitSize] out of range[%d, %d]",
284 : HCCL_DATA_TYPE_INT8, static_cast<int>(HCCL_DATA_TYPE_RESERVED) - 1);
285 0 : return 0;
286 : }
287 93 : unitSize = SIZE_TABLE[param.DataDes.dataType];
288 : }
289 100 : return unitSize;
290 : }
291 :
292 101 : bool IsHcclOpInplace(const HcclCMDType &opType, const OpParam ¶m, u32 userRank, u32 userRankSize,
293 : u8 &isInplaceStatus)
294 : {
295 101 : if (!IsInputOutPtrNotNullPtr(param, isInplaceStatus)) {
296 2 : return false;
297 : }
298 98 : u32 unitSize = InplaceDataUnitSize(opType, param);
299 98 : u64 inputDataSize = 0;
300 98 : u64 outputDataSize = 0;
301 98 : switch (opType) {
302 2 : case HcclCMDType::HCCL_CMD_SEND:
303 : case HcclCMDType::HCCL_CMD_RECEIVE:
304 2 : isInplaceStatus = 0;
305 2 : return false;
306 63 : case HcclCMDType::HCCL_CMD_ALLREDUCE:
307 63 : inputDataSize = param.DataDes.count * unitSize;
308 63 : outputDataSize = param.DataDes.count * unitSize;
309 63 : break;
310 3 : case HcclCMDType::HCCL_CMD_REDUCE:
311 3 : inputDataSize = param.DataDes.count * unitSize;
312 3 : if (userRank == param.root) {
313 2 : outputDataSize = param.DataDes.count * unitSize;
314 : }
315 3 : break;
316 2 : case HcclCMDType::HCCL_CMD_ALLGATHER:
317 2 : inputDataSize = param.DataDes.count * unitSize;
318 2 : outputDataSize = param.DataDes.count * unitSize * userRankSize;
319 2 : break;
320 16 : case HcclCMDType::HCCL_CMD_REDUCE_SCATTER:
321 16 : inputDataSize = param.DataDes.count * unitSize * userRankSize;
322 16 : outputDataSize = param.DataDes.count * unitSize;
323 16 : break;
324 2 : case HcclCMDType::HCCL_CMD_GATHER:
325 2 : inputDataSize = param.DataDes.count * unitSize;
326 2 : if (userRank == param.root) {
327 1 : outputDataSize = param.DataDes.count * unitSize * userRankSize;
328 : }
329 2 : break;
330 2 : case HcclCMDType::HCCL_CMD_SCATTER:
331 2 : if (userRank == param.root) {
332 1 : inputDataSize = param.DataDes.count * unitSize * userRankSize;
333 : }
334 2 : outputDataSize = param.DataDes.count * unitSize;
335 2 : break;
336 8 : case HcclCMDType::HCCL_CMD_ALLTOALLV:
337 : case HcclCMDType::HCCL_CMD_ALLTOALLVC:
338 : case HcclCMDType::HCCL_CMD_ALLTOALL:
339 : default:
340 8 : return HcclOpInplaceDefaultCase(param, isInplaceStatus);
341 : break;
342 : }
343 88 : return IsInputOutputOverlap(param, inputDataSize, outputDataSize, isInplaceStatus);
344 : }
345 :
346 9 : bool CheckUserInMemNotLargerThanCCLInMem(const HcclCMDType &opType, OpParam ¶m,
347 : u64 commInputSize, u32 userRankSize)
348 : {
349 9 : u32 unitSize = SIZE_TABLE[param.DataDes.dataType];
350 9 : u64 dataSize = 0;
351 9 : if (opType == HcclCMDType::HCCL_CMD_REDUCE_SCATTER) {
352 0 : dataSize = param.DataDes.count * unitSize * userRankSize;
353 9 : } else if (opType == HcclCMDType::HCCL_CMD_ALLREDUCE) {
354 9 : dataSize = param.DataDes.count * unitSize;
355 : }
356 :
357 9 : if (dataSize <= commInputSize) {
358 7 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU] UserInMem[%llu] <= CCLInMem[%llu]", dataSize, commInputSize);
359 : } else {
360 2 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU] UserInMem[%llu] > CCLInMem[%llu]", dataSize, commInputSize);
361 : }
362 9 : return dataSize <= commInputSize;
363 : }
364 :
365 7 : bool ExecutorOnlySupportDMAReduce(const std::string& algName)
366 : {
367 7 : return (algName == "AllReduceMeshSmallCountExecutor") || (algName == "ReduceScatterDeterExecutor");
368 : }
369 :
370 4 : bool ExecutorCanSupportDMAReduce(const std::string& algName)
371 : {
372 : const std::set<std::string> executorCanSupportDMAReduceSet = {
373 : "AllReduceRingFor91093Executor",
374 : "AllReduceFastDoubleRingFor91093Executor",
375 : "AlignedAllReduceDoubleRingFor91093Executor",
376 : "ReduceScatterRingFor91093Executor",
377 : "ReduceScatterFastDoubleRingFor91093Executor",
378 : "AlignedReduceScatterDoubleRingFor91093Executor",
379 : "ReduceScatterPipelineFor91093Executor"
380 4 : };
381 4 : if (executorCanSupportDMAReduceSet.find(algName) != executorCanSupportDMAReduceSet.end()) {
382 2 : return true;
383 : }
384 2 : return false;
385 4 : }
386 :
387 5 : bool ExecutorNoSupportDMAReduce(const std::string& algName)
388 : {
389 5 : return (algName == "AllReduceComm") || (algName == "ReduceScatterComm");
390 : }
391 :
392 7 : bool ExecutorSupportInPlace(const OpParam ¶m, const std::string& algName, bool retryEnable,
393 : InplaceSupportRetryStatus &inPlaceSupportRetryStatus)
394 : {
395 : (void) param;
396 : // case 2.2
397 7 : if (ExecutorOnlySupportDMAReduce(algName)) {
398 2 : if (retryEnable) {
399 1 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]ExecutorOnlySupportDMAReduce[%s] is not allowed"
400 : " for inplace case, the executor without DMAReduce will be applied.", algName.c_str());
401 1 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::RETRY_1_ALLOW_NO_DMA_REDUCE_CASE1;
402 1 : return true;
403 : }
404 1 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]ExecutorOnlySupportDMAReduce[%s] is not allowed"
405 : " for inplace case.", algName.c_str());
406 1 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::RETRY_0_NOT_ALLOW_NO_DMA_REDUCE_CASE1;
407 1 : return false;
408 5 : } else if (ExecutorNoSupportDMAReduce(algName)) {
409 1 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]ExecutorNoSupportDMAReduce[%s] is allowed"
410 : " for inplace case.", algName.c_str());
411 1 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::ALWAYS_NO_DMA_REDUCE;
412 1 : return true;
413 4 : } else if (ExecutorCanSupportDMAReduce(algName)) {
414 2 : if (retryEnable) {
415 : // 对应的executor会感应RetryEnable环境变量,走非DMA削减逻辑
416 1 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]ExecutorCanSupportDMAReduce[%s] is not allowed"
417 : " for inplace case, the executor without DMAReduce will be applied.", algName.c_str());
418 1 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::RETRY_1_ALLOW_NO_DMA_REDUCE_CASE2;
419 1 : return true;
420 : }
421 1 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]ExecutorCanSupportDMAReduce[%s] is not allowed"
422 : " for inplace case.", algName.c_str());
423 1 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::RETRY_0_NOT_ALLOW_NO_DMA_REDUCE_CASE2;
424 1 : return false;
425 : } else {
426 2 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]The unknown executor[%s] does not support "
427 : "for an inplace case yet.", algName.c_str());
428 2 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::UNKONWN_EXECUTOR;
429 2 : return false;
430 : }
431 : }
432 :
433 13 : bool FitRetryConditionforInPlaceOp(
434 : const HcclCMDType &opType, OpParam ¶m, const std::string& algName, u64 commInputSize, u32 userRankSize,
435 : bool retryEnable,
436 : InplaceSupportRetryStatus &inPlaceSupportRetryStatus)
437 : {
438 : // case 1 allgather or broadcast
439 13 : if (opType == HcclCMDType::HCCL_CMD_ALLGATHER ||
440 12 : opType == HcclCMDType::HCCL_CMD_BROADCAST) {
441 2 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::AG_BD_CASE;
442 2 : return true;
443 : }
444 : // case 2 reducescatter or allreduce
445 11 : if (opType == HcclCMDType::HCCL_CMD_REDUCE_SCATTER ||
446 11 : opType == HcclCMDType::HCCL_CMD_ALLREDUCE) {
447 : // case 2.1
448 9 : if (CheckUserInMemNotLargerThanCCLInMem(opType, param, commInputSize, userRankSize)) {
449 : // case 2.4: 在hccl_communicator.cc的ExecOp之前已经该让图模式走单算子模式了,理论上不会进入此条件
450 7 : HCCL_INFO("[CollAlgOperator][OpRetry][AICPU]The retry with inplace case is expected to be supported, "
451 : "therefore HcclWorkflowMode is set to [%u]",
452 : static_cast<u8>(GetWorkflowMode()));
453 7 : return ExecutorSupportInPlace(param, algName, retryEnable, inPlaceSupportRetryStatus);
454 : } else {
455 : // case 2.3 UsrIn > CCLIn
456 2 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::USER_LARGER_THAN_CCL;
457 2 : return false;
458 : }
459 : }
460 : // 其他算子类型不支持
461 2 : inPlaceSupportRetryStatus = InplaceSupportRetryStatus::NOT_BASIC_OP_CASE;
462 2 : return false;
463 : }
464 :
465 9 : u32 CalGCD(std::vector<u32> &nums)
466 : {
467 9 : if (nums.size() == 0) {
468 0 : return 1;
469 : }
470 9 : std::sort(nums.begin(), nums.end(), [](const u32 &num1, const u32 &num2) {
471 23 : return num1 > num2;
472 : });
473 :
474 9 : u32 curGcd = nums[0];
475 26 : for (u32 i = 1; i < nums.size(); i++) {
476 17 : curGcd = CalGCD(curGcd, nums[i]);
477 : }
478 9 : HCCL_DEBUG("[CalGCD]size[%u], gcd[%u]", nums.size(), curGcd);
479 9 : return curGcd;
480 : }
481 :
482 17 : u32 CalGCD(u32 a, u32 b)
483 : {
484 17 : if (a == 0 || b == 0) {
485 0 : return 1;
486 : }
487 :
488 17 : u32 gcd = b;
489 22 : while (a % b != 0) {
490 5 : gcd = a % b;
491 5 : a = b;
492 5 : b = gcd;
493 : }
494 17 : HCCL_DEBUG("[CalGCD]a[%u] b[%u], gcd[%u]", a, b, gcd);
495 17 : return gcd;
496 : }
497 : }
|