LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/impl/coll_executor/coll_reduce - coll_reduce_executor.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 19.4 % 144 28
Test Date: 2026-08-18 17:47:01 Functions: 28.6 % 7 2

            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 "coll_reduce_executor.h"
      12              : 
      13              : namespace hccl {
      14              : 
      15            2 : CollReduceExecutor::CollReduceExecutor(const HcclDispatcher dispatcher, std::unique_ptr<TopoMatcher>& topoMatcher)
      16            2 :     : CollCommExecutor(dispatcher, topoMatcher)
      17            5 : {}
      18              : 
      19            1 : HcclResult CollReduceExecutor::Orchestrate(OpParam& param, AlgResourceResponse& algRes)
      20              : {
      21            1 :     HcclUs startut = TIME_NOW();
      22              : 
      23            1 :     tag_ = param.tag;
      24            1 :     if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_HD || algType_.algoLevel2 == AlgTypeLevel2::ALG_LEVEL2_HD) {
      25            0 :         std::string appendTag = "";
      26            0 :         u32 serverNumPerSuperPod
      27            0 :             = topoAttr_.superPodNum == 0 ? topoAttr_.moduleNum : topoAttr_.moduleNum / topoAttr_.superPodNum;
      28            0 :         if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_HD) {
      29            0 :             u32 part1Size = FACTOR_TWO * (serverNumPerSuperPod - (1 << static_cast<u32>(log2(serverNumPerSuperPod))));
      30            0 :             u32 rootId = param.root / topoAttr_.deviceNumPerAggregation % serverNumPerSuperPod;
      31            0 :             appendTag += "L1_" + std::to_string((rootId >= part1Size) || ((rootId % FACTOR_TWO) == 0));
      32              :         }
      33            0 :         if (algType_.algoLevel2 == AlgTypeLevel2::ALG_LEVEL2_HD) {
      34            0 :             u32 part1Size = FACTOR_TWO * (topoAttr_.superPodNum - (1 << static_cast<u32>(log2(topoAttr_.superPodNum))));
      35            0 :             u32 rootId = param.root / topoAttr_.deviceNumPerAggregation / serverNumPerSuperPod;
      36            0 :             appendTag += (appendTag.empty() ? "L2_" : "_L2_")
      37            0 :                          + std::to_string((rootId >= part1Size) || ((rootId % FACTOR_TWO) == 0));
      38              :         }
      39            0 :         tag_ = param.tag + '_' + appendTag;
      40            0 :         if (param.opBaseAtraceInfo != nullptr) {
      41            0 :             CHK_RET(param.opBaseAtraceInfo->SavealgtypeTraceInfo(appendTag, param.tag));
      42              :         }
      43            0 :     }
      44              : 
      45            1 :     algResResp_ = &algRes;
      46            1 :     HcclResult ret = HCCL_SUCCESS;
      47            1 :     bool needLaunchAtTheEnd = true; // 是否需要在Orchestrate()结束时launch任务
      48            1 :     ExecMem execMem;
      49            1 :     execMem.count = param.DataDes.count;
      50            1 :     execMem.inputPtr = param.inputPtr;
      51            1 :     execMem.outputPtr = param.outputPtr;
      52              :     // 图模式和单卡场景下不需要Loop
      53            1 :     HCCL_DEBUG("[CollReduceExecutor][Orchestrate]workflowMode is %d", workflowMode_);
      54            1 :     if (workflowMode_ != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
      55            1 :         execMem.inputMem = algRes.paramInputMem;
      56            1 :         execMem.outputMem = algRes.paramOutputMem;
      57            1 :         execMem.scratchMem = algRes.scratchMem;
      58            1 :         ret = KernelRun(param, execMem);
      59            1 :         if (algOpContext_.opRetryHandler.isPostSync == true) {
      60              :             // post Sync
      61            0 :             CHK_RET(RetryPostSync(param, execMem));
      62              :         }
      63            0 :     } else if (topoAttr_.userRankSize == 1) {
      64            0 :         execMem.inputMem = algRes.cclInputMem;
      65            0 :         execMem.outputMem = algRes.cclOutputMem;
      66            0 :         execMem.scratchMem = algRes.scratchMem;
      67            0 :         ret = KernelRun(param, execMem);
      68            0 :         needLaunchAtTheEnd = false;
      69              :     } else {
      70            0 :         ret = RunLoop(param, algRes);
      71            0 :         needLaunchAtTheEnd = false;
      72              :     }
      73            1 :     CHK_PRT_RET(
      74              :         ret != HCCL_SUCCESS,
      75              :         HCCL_ERROR(
      76              :             "[CollReduceExecutor][Orchestrate]errNo[0x%016llx]reduce executor kernel run failed", HCCL_ERROR_CODE(ret)),
      77              :         ret);
      78              : 
      79              :     // Enforce task launch at the end of Orchestrate
      80              :     // 注意: 不要删除这里的强制launch, 否则会导致aicpu cache功能问题
      81            1 :     if (needLaunchAtTheEnd) {
      82            1 :         HCCL_INFO("%s: enforce task launch at the end of Orchestrate", __func__);
      83            1 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
      84              :     }
      85              : 
      86            1 :     HCCL_INFO(
      87              :         "tag[%s], Reduce executor orchestrate success, take time [%lld]us.", tag_.c_str(),
      88              :         DURATION_US(TIME_NOW() - startut));
      89            1 :     return HCCL_SUCCESS;
      90            1 : }
      91              : 
      92            0 : HcclResult CollReduceExecutor::RunLoop(OpParam& param, AlgResourceResponse& algRes)
      93              : {
      94            0 :     u32 unitSize = SIZE_TABLE[param.DataDes.dataType];
      95            0 :     ReduceType reduceType
      96            0 :         = ((param.reduceType != HCCL_REDUCE_PROD) && (param.DataDes.dataType != HCCL_DATA_TYPE_INT64)) ?
      97              :               ReduceType::INLINE_REDUCE :
      98              :               ReduceType::TBE_REDUCE;
      99              : 
     100            0 :     u8* curInputPtr = static_cast<u8*>(param.inputPtr);
     101            0 :     u8* curOutputPtr = static_cast<u8*>(param.outputPtr);
     102            0 :     CHK_PTR_NULL(curInputPtr);
     103            0 :     CHK_PTR_NULL(curOutputPtr);
     104              : 
     105            0 :     u64 maxCountPerLoop = CalcLoopMaxCount(unitSize, algRes); // override
     106              : 
     107            0 :     HCCL_DEBUG(
     108              :         "[CollReduceExecutor][RunLoop]tag[%s], userRankSize is [%u], maxCountPerLoop is [%llu].", tag_.c_str(),
     109              :         topoAttr_.userRankSize, maxCountPerLoop);
     110              : 
     111            0 :     u64 inputOffset = 0;
     112            0 :     u64 outputOffset = 0;
     113            0 :     u64 countLeft = param.DataDes.count;
     114            0 :     while (countLeft > 0) {
     115            0 :         curInputPtr += inputOffset;
     116            0 :         curOutputPtr += outputOffset;
     117              :         // 判断剩余数据量对应的output size是否大于中转output size
     118            0 :         u64 curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
     119            0 :         u64 curSize = curCount * unitSize; // 单位:字节
     120              : 
     121            0 :         HCCL_DEBUG(
     122              :             "[CollReduceExecutor][RunLoop]tag[%s], inputOffset[%llu], outputOffset[%llu], "
     123              :             "sendBuf[%p], recvBuf[%p], sendCount[%llu], dataType[%d].",
     124              :             tag_.c_str(), inputOffset, outputOffset, curInputPtr, curOutputPtr, curCount, param.DataDes.dataType);
     125              : 
     126            0 :         ExecMem execMem;
     127            0 :         execMem.count = curCount;
     128            0 :         execMem.inputMem = algRes.cclInputMem;
     129            0 :         execMem.outputMem = algRes.cclOutputMem;
     130            0 :         execMem.scratchMem = algRes.scratchMem;
     131              :         // 使用当前Loop偏移到的地址作为当前的inputPtr和outputPtr
     132            0 :         execMem.inputPtr = curInputPtr;
     133            0 :         execMem.outputPtr = curOutputPtr;
     134              : 
     135            0 :         CHK_RET(RunLoopInner(param, reduceType, execMem));
     136              : 
     137            0 :         countLeft -= curCount;
     138            0 :         inputOffset = curSize;
     139            0 :         outputOffset = curSize;
     140            0 :     }
     141            0 :     if (algOpContext_.opRetryHandler.isPostSync == true) {
     142            0 :         ExecMem execMem;
     143            0 :         execMem.count = param.DataDes.count;
     144            0 :         execMem.inputPtr = param.inputPtr;
     145            0 :         execMem.outputPtr = param.outputPtr;
     146            0 :         execMem.inputMem = algRes.cclInputMem;
     147            0 :         execMem.outputMem = algRes.cclOutputMem;
     148            0 :         execMem.scratchMem = algRes.scratchMem;
     149              :         // post Sync
     150            0 :         CHK_RET(RetryPostSync(param, execMem));
     151            0 :     }
     152            0 :     return HCCL_SUCCESS;
     153              : }
     154              : 
     155            0 : HcclResult CollReduceExecutor::RunLoopInner(OpParam& param, const ReduceType& reduceType, ExecMem& execMem)
     156              : {
     157            0 :     u32 unitSize = SIZE_TABLE[param.DataDes.dataType];
     158            0 :     u64 curSize = execMem.count * unitSize; // 单位:字节
     159            0 :     HCCL_DEBUG(
     160              :         "[CollReduceExecutor][RunLoopInner]inputMem[%p][%llu], outputMem[%p][%llu], "
     161              :         "intputPtr[%p], outputPtr[%p], curCount[%llu], curSize[%llu]",
     162              :         execMem.inputMem.ptr(), execMem.inputMem.size(), execMem.outputMem.ptr(), execMem.outputMem.size(),
     163              :         execMem.inputPtr, execMem.outputPtr, execMem.count, curSize);
     164            0 :     CHK_PRT_RET(
     165              :         (execMem.count == 0), HCCL_ERROR("[CollReduceExecutor][RunLoopInner]In OP_BASE curCount is zero."),
     166              :         HCCL_E_PARA);
     167              : 
     168              :     /* 设置子图复用标志 */
     169            0 :     bool isRootRank = param.root == topoAttr_.realUserRank ? true : false;
     170            0 :     auto autoSelectedAlgTypeLevel1 = static_cast<u32>(algType_.algoLevel1);
     171            0 :     bool hugeData = IsHugeData(curSize); // override
     172              :     /* TBE reduce 当总count数超过INT32_MAX时,不使能子图复用 */
     173            0 :     if (reduceType == ReduceType::TBE_REDUCE) {
     174            0 :         hugeData = hugeData || param.DataDes.count > INT32_MAX;
     175              :     }
     176            0 :     HCCL_DEBUG("[CollReduceExecutor][RunLoopInner]IsHugeData:[%u]", hugeData);
     177            0 :     u8 deterministic = topoMatcher_->GetExternalInputHcclDeterministic();
     178            0 :     auto opMeta = HcclOpMetaInfo::GetOneForReduce(
     179              :         isRootRank, param.root, autoSelectedAlgTypeLevel1, param.DataDes.dataType, reduceType, hugeData, deterministic);
     180            0 :     CHK_RET(InitTask(dispatcher_, param.stream, opMeta.isEnableCache, opMeta.GetCacheKey()));
     181              : 
     182            0 :     execMem.inputMem = DeviceMem::create(execMem.inputMem.ptr(), curSize);
     183            0 :     execMem.outputMem = DeviceMem::create(execMem.outputMem.ptr(), curSize);
     184              : 
     185              :     // 执行
     186              :     // 如果使用in CCL buffer,需要将user buffer in中的结果拷贝到CCL buffer in
     187            0 :     DeviceMem inMem(execMem.inputPtr, curSize);
     188            0 :     DeviceMem inCommMem = execMem.inputMem.range(0, curSize);
     189            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, inCommMem, inMem, param.stream));
     190            0 :     HCCL_DEBUG("[CollReduceExecutor][RunLoopInner]copy from user in to ccl in.");
     191              : 
     192            0 :     HcclResult ret = KernelRun(param, execMem);
     193            0 :     CHK_PRT_RET(
     194              :         ret != HCCL_SUCCESS,
     195              :         HCCL_ERROR(
     196              :             "[CollReduceExecutor][RunLoopInner]errNo[0x%016llx]kernel run error, tag[%s], "
     197              :             "inputMem ptr[%p], outputMem ptr[%p], count[%llu], dataType[%d], reduce op type[%d]",
     198              :             HCCL_ERROR_CODE(ret), tag_.c_str(), execMem.inputMem.ptr(), execMem.outputMem.ptr(), execMem.count,
     199              :             param.DataDes.dataType, param.reduceType),
     200              :         ret);
     201              : 
     202            0 :     if (topoAttr_.realUserRank == param.root) { // 只root rank需要把数据从中转内存拷贝出去
     203            0 :         DeviceMem outMem(execMem.outputPtr, curSize);
     204            0 :         DeviceMem outCommMem = execMem.outputMem.range(0, curSize);
     205            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, outMem, outCommMem, param.stream));
     206            0 :     }
     207              : 
     208            0 :     CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     209            0 :     return ret;
     210            0 : }
     211              : 
     212            0 : u64 CollReduceExecutor::CalcLoopMaxCount(const u32 unitSize, const AlgResourceResponse& algRes)
     213              : {
     214              :     // 中转内存单次最多能够接受的output count
     215            0 :     u64 maxCountPerLoop = algRes.cclInputMem.size() / unitSize;
     216            0 :     HCCL_WARNING(
     217              :         "[CollReduceExecutor][CalcLoopMaxCount]"
     218              :         "using default maxCountPerLoop[%llu] as CCLBuffSize / unitSize.",
     219              :         maxCountPerLoop);
     220            0 :     return maxCountPerLoop;
     221              : }
     222              : 
     223            0 : bool CollReduceExecutor::IsHugeData(const u64 curSize)
     224              : {
     225            0 :     HCCL_WARNING("[CollReduceExecutor][IsHugeData]opMeta is using the default option.");
     226            0 :     bool hugeData = (curSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE) || (curSize > SDMA_SEND_MAX_SIZE);
     227            0 :     return hugeData;
     228              : }
     229              : 
     230            0 : HcclResult CollReduceExecutor::RetryPostSync(OpParam& param, ExecMem& execMem)
     231              : {
     232            0 :     if ((algResResp_->slaveStreams).size() == 0) {
     233            0 :         CHK_RET(PostSyncWithoutSubstream(param, execMem));
     234              :     } else {
     235            0 :         PrepareData postSyncPrepareData;
     236            0 :         postSyncPrepareData.subStreamsPtr = &algResResp_->slaveStreams;
     237            0 :         postSyncPrepareData.signalPtr = &algResResp_->notifiesMain;
     238            0 :         postSyncPrepareData.signalAuxPtr = &algResResp_->notifiesAux;
     239            0 :         postSyncPrepareData.stream = param.stream;
     240            0 :         CHK_RET(PostSyncWithSubstream(param, execMem, postSyncPrepareData));
     241            0 :     }
     242            0 :     return HCCL_SUCCESS;
     243              : }
     244              : } // namespace hccl
        

Generated by: LCOV version 2.0-1