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