LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/impl/coll_executor/coll_all_gather - coll_all_gather_executor.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 31.3 % 342 107
Test Date: 2026-08-18 17:47:01 Functions: 40.0 % 20 8

            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_all_gather_executor.h"
      12              : #include <numeric>
      13              : 
      14              : namespace hccl {
      15           12 : CollAllGatherExecutor::CollAllGatherExecutor(const HcclDispatcher dispatcher, std::unique_ptr<TopoMatcher>& topoMatcher)
      16           12 :     : CollCommExecutor(dispatcher, topoMatcher)
      17           15 : {}
      18              : 
      19            7 : HcclResult CollAllGatherExecutor::Orchestrate(OpParam& param, AlgResourceResponse& algRes)
      20              : {
      21            7 :     HcclUs startut = TIME_NOW();
      22            7 :     tag_ = param.tag;
      23            7 :     algResResp_ = &algRes;
      24              : 
      25            7 :     const u64 count = param.GetDataCount(topoAttr_.userRank);
      26            7 :     const HcclDataType dataType = param.GetDataType();
      27            7 :     bool needLaunchAtTheEnd = !is310P3Common_; // 是否需要在Orchestrate()结束时launch任务
      28              : 
      29            7 :     HcclResult ret = HCCL_SUCCESS;
      30              :     // 图模式和单卡场景下不需要Loop
      31            7 :     if (workflowMode_ != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
      32            5 :         u64 countSize = count * SIZE_TABLE[dataType];
      33            5 :         u64 totalSize = CalcTotalCount(param) * SIZE_TABLE[dataType];
      34            5 :         ExecMem execMem;
      35            5 :         execMem.count = count;
      36            5 :         execMem.inputMem = DeviceMem::create(algRes.paramInputMem.ptr(), countSize);
      37            5 :         execMem.outputMem = DeviceMem::create(algRes.paramOutputMem.ptr(), totalSize);
      38            5 :         execMem.scratchMem = algRes.scratchMem;
      39            5 :         execMem.inputPtr = param.inputPtr;
      40            5 :         execMem.outputPtr = param.outputPtr;
      41            5 :         HCCL_DEBUG(
      42              :             "[CollAllGatherExecutor][Orchestrate]offload inputMem[%p][%llu], outputMem[%p][%llu],"
      43              :             "scratchMem[%p][%llu], inputPtr[%p] outputPtr[%p], count[%llu].",
      44              :             execMem.inputMem.ptr(), execMem.inputMem.size(), execMem.outputMem.ptr(), execMem.outputMem.size(),
      45              :             execMem.scratchMem.ptr(), execMem.scratchMem.size(), execMem.inputPtr, execMem.outputPtr, execMem.count);
      46            5 :         ret = KernelRun(param, execMem);
      47            7 :     } else if (topoAttr_.userRankSize == 1) {
      48            0 :         ExecMem execMem;
      49            0 :         execMem.count = count;
      50            0 :         execMem.inputMem = algRes.cclInputMem;
      51            0 :         execMem.outputMem = algRes.cclOutputMem;
      52            0 :         execMem.scratchMem = algRes.scratchMem;
      53            0 :         execMem.inputPtr = param.inputPtr;
      54            0 :         execMem.outputPtr = param.outputPtr;
      55            0 :         ret = KernelRun(param, execMem);
      56            0 :         needLaunchAtTheEnd = false;
      57            2 :     } else if (desc_.isZeroCopy) {
      58            0 :         u64 totalSize = param.DataDes.count * SIZE_TABLE[param.DataDes.dataType];
      59              :         // 在Level1和Level2执行RunLoop
      60            0 :         if (topoAttr_.serverNum > 1) {
      61            0 :             ret = RunLoop(param, algRes);
      62            0 :             CHK_PRT_RET(
      63              :                 ret != HCCL_SUCCESS,
      64              :                 HCCL_ERROR(
      65              :                     "[CollAllGatherExecutor][Orchestrate]errNo[0x%016llx]AllGather executor run loop failed",
      66              :                     HCCL_ERROR_CODE(ret)),
      67              :                 ret);
      68              :         } else { // 单机场景,数据直接从UserInput搬到UserOutput
      69              :             DeviceMem dstMem = DeviceMem::create(
      70            0 :                 static_cast<u8*>(algRes.paramOutputMem.ptr()) + totalSize * topoAttr_.userRank, totalSize);
      71            0 :             DeviceMem srcMem = DeviceMem::create(algRes.paramInputMem.ptr(), totalSize);
      72            0 :             CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
      73            0 :         }
      74              :         // 在Level0执行KernelRun
      75            0 :         ExecMem execMem;
      76            0 :         execMem.count = param.DataDes.count;
      77            0 :         execMem.inputMem = DeviceMem::create(algRes.paramInputMem.ptr(), totalSize);
      78            0 :         execMem.outputMem = DeviceMem::create(algRes.paramOutputMem.ptr(), totalSize * topoAttr_.userRankSize);
      79            0 :         execMem.scratchMem = algRes.scratchMem;
      80            0 :         execMem.inputPtr = param.inputPtr;
      81            0 :         execMem.outputPtr = param.outputPtr;
      82            0 :         ret = KernelRunIntraServerPost(param, execMem);
      83            0 :     } else {
      84            2 :         if (isAllGatherV_) {
      85            0 :             ret = RunLoopV(param, algRes);
      86              :         } else {
      87            2 :             ret = RunLoop(param, algRes);
      88              :         }
      89            2 :         needLaunchAtTheEnd = false;
      90              :     }
      91            7 :     CHK_PRT_RET(
      92              :         ret != HCCL_SUCCESS,
      93              :         HCCL_ERROR(
      94              :             "[CollAllGatherExecutor][Orchestrate]errNo[0x%016llx]AllGather executor kernel run failed",
      95              :             HCCL_ERROR_CODE(ret)),
      96              :         ret);
      97              : 
      98              :     // Enforce task launch at the end of Orchestrate
      99              :     // 注意: 不要删除这里的强制launch, 否则会导致aicpu cache功能问题
     100            7 :     if (needLaunchAtTheEnd) {
     101            5 :         HCCL_INFO("%s: enforce task launch at the end of Orchestrate", __func__);
     102            5 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     103              :     }
     104              : 
     105            7 :     HCCL_INFO(
     106              :         "tag[%s], Allgather executor orchestrate success, take time [%lld]us", param.tag.c_str(),
     107              :         DURATION_US(TIME_NOW() - startut));
     108            7 :     return HCCL_SUCCESS;
     109              : }
     110              : 
     111            0 : u64 CollAllGatherExecutor::CalcLoopMaxCount(const u64 cclBuffSize, const u32 unitSize)
     112              : {
     113              :     // 中转内存单次最多能够接受的output count
     114            0 :     u64 maxCountPerLoop = cclBuffSize / topoAttr_.userRankSize / HCCL_MIN_SLICE_ALIGN * HCCL_MIN_SLICE_ALIGN / unitSize;
     115            0 :     HCCL_WARNING(
     116              :         "[CollAllGatherExecutor][CalcLoopMaxCount]"
     117              :         "using default maxCountPerLoop[%llu] as CCLBuffSize / unitSize",
     118              :         maxCountPerLoop);
     119            0 :     return maxCountPerLoop;
     120              : }
     121              : 
     122           18 : bool CollAllGatherExecutor::IsHugeData(const u64 curSize)
     123              : {
     124           36 :     bool hugeData = curSize * topoAttr_.userRankSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE
     125           18 :                     || curSize > SDMA_SEND_MAX_SIZE;
     126           18 :     return hugeData;
     127              : }
     128              : 
     129            2 : bool CollAllGatherExecutor::IsSmallData([[maybe_unused]] const u64 size)
     130              : {
     131            2 :     HCCL_INFO("[CollAllGatherExecutor][IsSmallData]opMeta is using the default option: not small data");
     132            2 :     return false;
     133              : }
     134              : 
     135            5 : u64 CollAllGatherExecutor::CalcTotalCount(const OpParam& param) const
     136              : {
     137            5 :     if (isAllGatherV_) {
     138            0 :         const auto* countsPtr = static_cast<const u64*>(param.VDataDes.counts);
     139            0 :         return std::accumulate(countsPtr, countsPtr + topoAttr_.userRankSize, 0ULL);
     140              :     }
     141            5 :     return param.DataDes.count * topoAttr_.userRankSize;
     142              : }
     143              : 
     144            0 : bool CollAllGatherExecutor::CalcCountsDispls(
     145              :     const u64 maxTotalCount, std::vector<u64>& countsLeft, std::vector<u64>& displs, std::vector<u64>& curCounts,
     146              :     std::vector<u64>& curDispls)
     147              : {
     148            0 :     bool finished = true;
     149              : 
     150            0 :     curCounts.resize(countsLeft.size(), 0);
     151            0 :     curDispls.resize(displs.size(), 0);
     152              : 
     153              :     // 先设置本轮的displacements,等于入参displs
     154            0 :     std::copy(displs.begin(), displs.end(), curDispls.begin());
     155              : 
     156              :     // 分配好每个rank的counts
     157            0 :     for (auto i = 0U; i < countsLeft.size(); ++i) {
     158            0 :         const auto curCount = countsLeft[i] < maxTotalCount ? countsLeft[i] : maxTotalCount;
     159            0 :         curCounts[i] = curCount;
     160            0 :         countsLeft[i] -= curCount;
     161            0 :         displs[i] += curCount;
     162              : 
     163            0 :         if (countsLeft[i] != 0) {
     164            0 :             finished = false;
     165              :         }
     166              :     }
     167              : 
     168            0 :     PrintCountsDispls(finished, curCounts, curDispls);
     169              : 
     170            0 :     return finished;
     171              : }
     172              : 
     173            0 : void CollAllGatherExecutor::PrintCountsDispls(
     174              :     bool finished, const std::vector<u64>& curCounts, const std::vector<u64>& curDispls)
     175              : {
     176            0 :     if (HcclCheckLogLevel(DLOG_DEBUG)) {
     177            0 :         std::ostringstream curLoopInfo;
     178            0 :         curLoopInfo << "counts[ ";
     179            0 :         for (auto count : curCounts) {
     180            0 :             curLoopInfo << count << " ";
     181              :         }
     182            0 :         curLoopInfo << "], displs[ ";
     183            0 :         for (auto displ : curDispls) {
     184            0 :             curLoopInfo << displ << " ";
     185              :         }
     186            0 :         curLoopInfo << "]";
     187            0 :         HCCL_DEBUG(
     188              :             "[CollAllGatherExecutor][CountsDispls]finished[%u], Current loop info: %s", finished,
     189              :             curLoopInfo.str().c_str());
     190            0 :     }
     191            0 : }
     192              : 
     193            0 : std::vector<u64> CollAllGatherExecutor::GetCounts(const OpParam& param) const
     194              : {
     195            0 :     const auto* countsPtr = static_cast<const u64*>(param.VDataDes.counts);
     196            0 :     return std::vector<u64>(countsPtr, countsPtr + topoAttr_.userRankSize);
     197              : }
     198              : 
     199            0 : std::vector<u64> CollAllGatherExecutor::GetDispls(const OpParam& param) const
     200              : {
     201            0 :     const auto* displsPtr = static_cast<const u64*>(param.VDataDes.displs);
     202            0 :     return std::vector<u64>(displsPtr, displsPtr + topoAttr_.userRankSize);
     203              : }
     204              : 
     205            0 : u64 CollAllGatherExecutor::GetCurrentCount(
     206              :     [[maybe_unused]] const OpParam& param, const std::vector<u64>& curCounts) const
     207              : {
     208            0 :     return curCounts[topoAttr_.userRank];
     209              : }
     210              : 
     211            0 : u64 CollAllGatherExecutor::CalcCurrentTotalCount(
     212              :     [[maybe_unused]] const OpParam& param, const std::vector<u64>& curCounts) const
     213              : {
     214            0 :     return std::accumulate(curCounts.cbegin(), curCounts.cend(), 0ULL);
     215              : }
     216              : 
     217              : HcclOpMetaInfoDef
     218            0 : CollAllGatherExecutor::GetOpMetaInfo(u32 algTypeLevel1, bool hugeData, bool smallData, bool dataSplit) const
     219              : {
     220            0 :     return HcclOpMetaInfo::GetOneForAllGatherV(algTypeLevel1, hugeData, smallData, CopyPattern::BCOPY, dataSplit);
     221              : }
     222              : 
     223            0 : void CollAllGatherExecutor::UpdateOpParam(
     224              :     OpParam& param, std::vector<u64>& curCounts, std::vector<u64>& curDispls) const
     225              : {
     226            0 :     param.VDataDes.counts = curCounts.data();
     227            0 :     param.VDataDes.displs = curDispls.data();
     228            0 : }
     229              : 
     230              : // 基于性能考量,合并RunLoop和RunLoopInner
     231            2 : HcclResult CollAllGatherExecutor::RunLoop(OpParam& param, AlgResourceResponse& algRes)
     232              : {
     233            2 :     u32 unitSize = SIZE_TABLE[param.DataDes.dataType];
     234              : 
     235            2 :     u8* curInputPtr = static_cast<u8*>(param.inputPtr);
     236            2 :     u8* curOutputPtr = static_cast<u8*>(param.outputPtr);
     237            2 :     void* commInputPtr = algRes.cclInputMem.ptr();
     238            2 :     u8* commOutputPtr = static_cast<u8*>(algRes.cclOutputMem.ptr());
     239            2 :     CHK_PTR_NULL(curInputPtr);
     240            2 :     CHK_PTR_NULL(curOutputPtr);
     241            2 :     CHK_PTR_NULL(commInputPtr);
     242            2 :     CHK_PTR_NULL(commOutputPtr);
     243              : 
     244            2 :     u64 maxCountPerLoop = CalcLoopMaxCount(algRes.cclInputMem.size(), unitSize);
     245            2 :     CHK_PRT_RET(
     246              :         maxCountPerLoop == 0,
     247              :         HCCL_ERROR(
     248              :             "[CollAllGatherExecutor][RunLoop]tag[%s], userRankSize is [%u], maxCountPerLoop is [%llu].",
     249              :             param.tag.c_str(), topoAttr_.userRankSize, maxCountPerLoop),
     250              :         HCCL_E_PARA);
     251              : 
     252            2 :     bool smallData = IsSmallData(param.DataDes.count * unitSize);
     253           20 :     for (u64 countLeft = param.DataDes.count, curCount = 0, inputOffset = 0, outputOffset = 0; countLeft > 0;
     254           18 :          countLeft -= curCount) {
     255           18 :         curInputPtr += inputOffset;
     256           18 :         curOutputPtr += outputOffset;
     257              :         // 判断剩余数据量对应的output size是否大于中转output size
     258           18 :         curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
     259           18 :         u64 curSize = curCount * unitSize; // 单位:字节
     260              : 
     261           18 :         HCCL_DEBUG(
     262              :             "[CollAllGatherExecutor][RunLoop]tag[%s], inputOffset[%llu], outputOffset[%llu], "
     263              :             "sendBuf[%p], recvBuf[%p], sendCount[%llu], dataType[%d]",
     264              :             param.tag.c_str(), inputOffset, outputOffset, curInputPtr, curOutputPtr, curCount, param.DataDes.dataType);
     265              : 
     266           18 :         if (!is310P3Common_) {
     267              :             /* 设置子图复用标志 */
     268           18 :             auto autoSelectedAlgTypeLevel1 = static_cast<u32>(algType_.algoLevel1);
     269           18 :             bool hugeData = IsHugeData(curSize); // override
     270           18 :             bool dataSplit = false;
     271           18 :             auto opMeta = HcclOpMetaInfo::GetOneForAllGather(
     272              :                 autoSelectedAlgTypeLevel1, hugeData, smallData, CopyPattern::BCOPY, dataSplit);
     273           18 :             CHK_RET(InitTask(dispatcher_, param.stream, opMeta.isEnableCache, opMeta.GetCacheKey()));
     274              :         }
     275              : 
     276              :         // 执行
     277           18 :         if (!DMAReduceFlag_) {
     278              :             // 如果使用in CCL buffer,需要将user buffer in中的结果拷贝到CCL buffer in
     279            0 :             DeviceMem srcMem = DeviceMem::create(curInputPtr, curSize);
     280            0 :             DeviceMem dstMem = DeviceMem::create(commInputPtr, curSize);
     281            0 :             CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     282            0 :             HCCL_DEBUG("[CollAllGatherExecutor][RunLoop]copy from user in to ccl in.");
     283            0 :         }
     284              : 
     285              :         // 使用当前Loop偏移到的地址作为当前的inputPtr和outputPtr
     286           18 :         ExecMem execMem;
     287           18 :         execMem.count = curCount;
     288           18 :         execMem.inputMem = DeviceMem::create(commInputPtr, curSize);
     289           18 :         u32 sliceNum = desc_.isZeroCopy ? topoAttr_.serverNum : topoAttr_.userRankSize;
     290           18 :         execMem.outputMem = DeviceMem::create(commOutputPtr, curSize * sliceNum);
     291           18 :         execMem.scratchMem = algRes.scratchMem;
     292           18 :         execMem.inputPtr = curInputPtr;
     293           18 :         execMem.outputPtr = curOutputPtr;
     294           18 :         HcclResult ret = HCCL_SUCCESS;
     295           18 :         if (!desc_.isZeroCopy) {
     296           18 :             ret = KernelRun(param, execMem);
     297              :         } else {
     298            0 :             ret = KernelRunInterServer(param, execMem);
     299              :         }
     300           18 :         CHK_PRT_RET(
     301              :             ret != HCCL_SUCCESS,
     302              :             HCCL_ERROR(
     303              :                 "[CollAllGatherExecutor][RunLoop]errNo[0x%016llx]kernel run error, tag[%s], "
     304              :                 "inputMem ptr[%p], outputMem ptr[%p], count[%llu], dataType[%d].",
     305              :                 HCCL_ERROR_CODE(ret), param.tag.c_str(), commInputPtr, commOutputPtr, curCount, param.DataDes.dataType),
     306              :             ret);
     307              : 
     308           18 :         if (!DMAReduceFlag_) {
     309              :             // 如果使用CCL buffer,需要将CCL buffer out中的结果拷贝到user buffer out
     310            0 :             for (u32 i = 0; i < topoAttr_.userRankSize; i++) {
     311              :                 // 拷贝中转output上每个slice的数据到output内存,目的端中每个slice的size固定为output的size
     312            0 :                 DeviceMem dstMem = DeviceMem::create(curOutputPtr + param.DataDes.count * unitSize * i, curSize);
     313            0 :                 DeviceMem srcMem = DeviceMem::create(commOutputPtr + curSize * i, curSize);
     314            0 :                 CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     315            0 :             }
     316              :         }
     317              : 
     318           18 :         if (!is310P3Common_) {
     319           18 :             CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     320              :         }
     321              : 
     322           18 :         inputOffset = curSize;
     323           18 :         outputOffset = curSize;
     324           18 :     }
     325            2 :     return HCCL_SUCCESS;
     326              : }
     327              : 
     328            0 : HcclResult CollAllGatherExecutor::RunLoopV(OpParam& param, AlgResourceResponse& algRes)
     329              : {
     330            0 :     auto counts = GetCounts(param);
     331            0 :     auto displs = GetDispls(param);
     332            0 :     const HcclDataType dataType = param.GetDataType();
     333            0 :     u32 unitSize = SIZE_TABLE[dataType];
     334              : 
     335            0 :     u8* curInputPtr = static_cast<u8*>(param.inputPtr);
     336            0 :     u8* curOutputPtr = static_cast<u8*>(param.outputPtr);
     337            0 :     u8* commInputPtr = static_cast<u8*>(algRes.cclInputMem.ptr());
     338            0 :     u8* commOutputPtr = static_cast<u8*>(algRes.cclOutputMem.ptr());
     339              : 
     340            0 :     if (UNLIKELY(curInputPtr == nullptr)) {
     341              :         // 若本rank的input count为0,此时允许curInputPtr传入空指针,为保证后续流程正常执行,赋值为cclin的地址
     342            0 :         curInputPtr = commInputPtr;
     343            0 :         HCCL_DEBUG("Since the input count is 0, set curInputPtr to ccl input[%p]", curInputPtr);
     344              :     } else {
     345            0 :         CHK_PTR_NULL(curInputPtr);
     346              :     }
     347            0 :     CHK_PTR_NULL(curOutputPtr);
     348            0 :     CHK_PTR_NULL(commInputPtr);
     349            0 :     CHK_PTR_NULL(commOutputPtr);
     350              : 
     351            0 :     u64 maxCountPerLoop = CalcLoopMaxCount(algRes.cclInputMem.size(), unitSize);
     352            0 :     CHK_PRT_RET(
     353              :         maxCountPerLoop == 0,
     354              :         HCCL_ERROR(
     355              :             "[CollAllGatherExecutor][RunLoopV]tag[%s], userRankSize is [%u], maxCountPerLoop is [%llu].",
     356              :             param.tag.c_str(), topoAttr_.userRankSize, maxCountPerLoop),
     357              :         HCCL_E_PARA);
     358              : 
     359            0 :     bool finished = false;
     360            0 :     while (!finished) {
     361            0 :         auto curCounts = std::vector<u64>();
     362            0 :         auto curDispls = std::vector<u64>();
     363              :         // 每轮loop需要重新计算counts和displs
     364            0 :         finished = CalcCountsDispls(maxCountPerLoop, counts, displs, curCounts, curDispls);
     365            0 :         u64 curCount = GetCurrentCount(param, curCounts);
     366            0 :         u64 curSize = curCount * unitSize; // 单位:字节
     367            0 :         const u64 totalSize = CalcCurrentTotalCount(param, curCounts) * unitSize;
     368              : 
     369            0 :         HCCL_DEBUG(
     370              :             "[CollAllGatherExecutor][RunLoopV]tag[%s], sendBuf[%p], recvBuf[%p], sendSize[%llu], "
     371              :             "recvSize[%llu], cclInputMem[%u], cclOutputMem[%u], dataType[%d]",
     372              :             param.tag.c_str(), curInputPtr, curOutputPtr, curSize, totalSize, algRes.cclInputMem.size(),
     373              :             algRes.cclOutputMem.size(), dataType);
     374              : 
     375              :         /* 设置子图复用标志 */
     376            0 :         auto autoSelectedAlgTypeLevel1 = static_cast<u32>(algType_.algoLevel1);
     377            0 :         bool hugeData = IsHugeData(curSize); // override
     378            0 :         bool smallData = IsSmallData(curSize);
     379            0 :         bool dataSplit = false;
     380            0 :         auto opMeta = GetOpMetaInfo(autoSelectedAlgTypeLevel1, hugeData, smallData, dataSplit);
     381            0 :         CHK_RET(InitTask(dispatcher_, param.stream, opMeta.isEnableCache, opMeta.GetCacheKey()));
     382              : 
     383              :         // 使用当前Loop偏移到的地址作为当前的inputPtr和outputPtr
     384            0 :         ExecMem execMem;
     385            0 :         execMem.count = curCount;
     386            0 :         execMem.inputMem = DeviceMem::create(commInputPtr, curSize);
     387            0 :         execMem.outputMem = DeviceMem::create(commOutputPtr, totalSize);
     388            0 :         execMem.scratchMem = algRes.scratchMem;
     389            0 :         execMem.inputPtr = curInputPtr;
     390            0 :         execMem.outputPtr = curOutputPtr;
     391            0 :         UpdateOpParam(param, curCounts, curDispls);
     392            0 :         HcclResult ret = KernelRun(param, execMem);
     393            0 :         CHK_PRT_RET(
     394              :             ret != HCCL_SUCCESS,
     395              :             HCCL_ERROR(
     396              :                 "[CollAllGatherExecutor][RunLoopV]errNo[0x%016llx]kernel run error, tag[%s], "
     397              :                 "inputMem ptr[%p], outputMem ptr[%p], count[%llu], dataType[%d]",
     398              :                 HCCL_ERROR_CODE(ret), param.tag.c_str(), commInputPtr, commOutputPtr, curCount, dataType),
     399              :             ret);
     400              : 
     401            0 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     402              : 
     403            0 :         curInputPtr += curSize;
     404              :         // AllGatherV curOutputPtr不需要偏移,偏移由displs计算
     405            0 :     }
     406            0 :     return HCCL_SUCCESS;
     407            0 : }
     408              : 
     409              : HcclResult
     410           18 : CollAllGatherExecutor::PrepareAllgatherSlice(u32 sliceNum, u64 inputMemSize, std::vector<Slice>& dataSegsSlice) const
     411              : {
     412           18 :     Slice sliceTemp;
     413           54 :     for (u32 i = 0; i < sliceNum; i++) { // 根据数据量计算每个环上数据的偏移和大小
     414           36 :         sliceTemp.size = inputMemSize;
     415           36 :         sliceTemp.offset = inputMemSize * i;
     416           36 :         dataSegsSlice.push_back(sliceTemp);
     417              :     }
     418           18 :     return HCCL_SUCCESS;
     419              : }
     420              : 
     421            0 : HcclResult CollAllGatherExecutor::CalculateLevel1AllgatherSlice(
     422              :     u64 inputMemSize, u32 level0RankSize, u32 level1RankSize, std::vector<std::vector<Slice>> multRingsSliceZero,
     423              :     std::vector<std::vector<Slice>>& multRingsSlice) const
     424              : {
     425            0 :     for (u32 ringIndex = 0; ringIndex < multRingsSliceZero.size(); ringIndex++) {
     426            0 :         std::vector<Slice> level1DataSlice;
     427            0 :         for (u32 level0Idx = 0; level0Idx < level0RankSize; level0Idx++) {
     428            0 :             CHK_PRT_RET(
     429              :                 multRingsSliceZero[ringIndex].size() < level0RankSize,
     430              :                 HCCL_ERROR("[CalculateLevel1AllgatherSlice]multRingsSliceZero[ringIndex]"
     431              :                            "size is smaller than level0RankSize."),
     432              :                 HCCL_E_INTERNAL);
     433            0 :             for (u32 level1Idx = 0; level1Idx < level1RankSize; level1Idx++) {
     434            0 :                 Slice tmpSlice;
     435            0 :                 tmpSlice.size = multRingsSliceZero[ringIndex][level0Idx].size;
     436              :                 tmpSlice.offset
     437            0 :                     = multRingsSliceZero[ringIndex][level0Idx].offset + level1Idx * level0RankSize * inputMemSize;
     438            0 :                 level1DataSlice.push_back(tmpSlice);
     439              :             }
     440              :         }
     441            0 :         multRingsSlice.push_back(level1DataSlice);
     442            0 :     }
     443            0 :     return HCCL_SUCCESS;
     444              : }
     445              : 
     446           36 : HcclResult CollAllGatherExecutor::CalculateLevel2AllgatherSlice(
     447              :     u64 inputMemSize, u32 level0RankSize, u32 level1RankSize, u32 level2RankSize,
     448              :     std::vector<std::vector<Slice>> multRingsSliceZero, std::vector<Slice>& level2DataSlice, u32 ringIndex) const
     449              : {
     450          108 :     for (u32 level0Idx = 0; level0Idx < level0RankSize; level0Idx++) {
     451          144 :         for (u32 level2Idx = 0; level2Idx < level2RankSize; level2Idx++) {
     452          216 :             for (u32 level1Idx = 0; level1Idx < level1RankSize; level1Idx++) {
     453          144 :                 Slice tmpSlice;
     454          144 :                 tmpSlice.size = multRingsSliceZero[ringIndex][level0Idx].size;
     455              :                 tmpSlice.offset
     456          144 :                     = multRingsSliceZero[ringIndex][level0Idx].offset
     457          144 :                       + (level1Idx * level0RankSize + level2Idx * level0RankSize * level1RankSize) * inputMemSize;
     458          144 :                 level2DataSlice.push_back(tmpSlice);
     459              :             }
     460              :         }
     461              :     }
     462           36 :     return HCCL_SUCCESS;
     463              : }
     464              : 
     465            0 : HcclResult CollAllGatherExecutor::AllGatherLevel2(
     466              :     const std::string& tag, DeviceMem& inputMem, DeviceMem& outputMem, u64 count, HcclDataType dataType, Stream& stream,
     467              :     HcomCollOpInfo* opInfo)
     468              : {
     469            0 :     u32 perDataSize = 0;
     470            0 :     CHK_RET(SalGetDataTypeSize(dataType, perDataSize));
     471              : 
     472            0 :     SubCommInfo level0CommInfo = GetSubCommInfo(COMM_LEVEL0, COMM_INDEX_0);
     473            0 :     u32 commIndex = level0CommInfo.localRank;
     474            0 :     SubCommInfo level1CommInfo = GetSubCommInfo(COMM_LEVEL1, commIndex);
     475            0 :     CHK_RET(CheckCommSize(COMM_LEVEL2, COMM_INDEX_0));
     476            0 :     SubCommInfo level2CommInfo = GetSubCommInfo(COMM_LEVEL2, COMM_INDEX_0);
     477              : 
     478            0 :     u64 inputMemSize = inputMem.size();
     479            0 :     u32 level0RankSize = level0CommInfo.localRankSize;
     480            0 :     u32 level1RankSize = level1CommInfo.localRankSize;
     481            0 :     u32 level2RankSize = level2CommInfo.localRankSize;
     482            0 :     u32 level0ServerIndex = level0CommInfo.localRank;
     483            0 :     u32 level1ServerIndex = level1CommInfo.localRank;
     484              : 
     485            0 :     std::unique_ptr<AlgTemplateBase> level2AGExecutor;
     486              :     level2AGExecutor
     487            0 :         = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_ALL_GATHER_RING, dispatcher_);
     488            0 :     HCCL_INFO("AllGather ring: using ring algo inter-server.");
     489            0 :     CHK_SMART_PTR_NULL(level2AGExecutor);
     490              : 
     491              :     // 计算slice, 不同超节点相同slice
     492            0 :     std::vector<Slice> level2DataSegsSlice;
     493            0 :     Slice sliceTemp;
     494            0 :     for (u32 i = 0; i < level2RankSize; i++) {
     495            0 :         sliceTemp.size = inputMemSize;
     496            0 :         sliceTemp.offset = i * level1RankSize * level0RankSize * inputMemSize;
     497            0 :         level2DataSegsSlice.push_back(sliceTemp);
     498              :     }
     499              :     //  outputMem传整块,通过baseOffset偏移
     500            0 :     u64 level2BaseOffset = (level0ServerIndex + level1ServerIndex * level1RankSize) * inputMemSize;
     501            0 :     CHK_RET(level2AGExecutor->Prepare(
     502              :         outputMem, outputMem, inputMem, count, dataType, stream, HCCL_REDUCE_RESERVED, INVALID_VALUE_RANKID,
     503              :         level2DataSegsSlice, level2BaseOffset));
     504              : 
     505            0 :     CHK_RET(level2AGExecutor->RegisterProfiler(
     506              :         (level2RankSize << PROF_RANKSIZE_OFFSET_OF_PLANEID) + level2CommInfo.localRank, PROF_STAGE_0,
     507              :         HCCL_EXEC_STEP_NOT_SET, stream));
     508              : 
     509            0 :     CHK_RET(RunTemplate(level2AGExecutor, level2CommInfo));
     510            0 :     HCCL_INFO("AllGather double ring [superpod] level2 AllGather run success");
     511              : 
     512              :     // 第二步,各个AI Server 间 AllGather (ring/NHR)
     513            0 :     HCCL_INFO("commIdx:%u Tag[%s].commLevel1.size():%u", commIndex, tag.c_str(), level1RankSize);
     514              : 
     515            0 :     if (level1RankSize > 1) {
     516            0 :         std::unique_ptr<AlgTemplateBase> level1AGExecutor;
     517            0 :         if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_RING) {
     518              :             level1AGExecutor
     519            0 :                 = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_ALL_GATHER_RING, dispatcher_);
     520            0 :             HCCL_INFO("AllGather ring: using ring algo inter-server.");
     521            0 :         } else if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_NB) {
     522              :             level1AGExecutor
     523            0 :                 = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_ALL_GATHER_NB, dispatcher_);
     524            0 :             HCCL_INFO("AllGather ring: using nonuniform-bruck algo inter-server.");
     525            0 :         } else if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_NHR) {
     526              :             level1AGExecutor
     527            0 :                 = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_ALL_GATHER_NHR, dispatcher_);
     528            0 :             HCCL_INFO("AllGather ring: using nonuniform-hierarchical-ring algo inter-server.");
     529              :         } else {
     530            0 :             HCCL_ERROR("AllGather ring: unsupported algtype [%s].", AlgTypeToStr(algType_).c_str());
     531            0 :             return HCCL_E_NOT_SUPPORT;
     532              :         }
     533            0 :         CHK_SMART_PTR_NULL(level1AGExecutor);
     534              : 
     535              :         // 计算slice, 不同超节点相同slice
     536            0 :         std::vector<Slice> level1DataSegsSlice;
     537            0 :         for (u32 j = 0; j < level2RankSize; j++) {
     538            0 :             for (u32 i = 0; i < level1RankSize; i++) {
     539            0 :                 sliceTemp.size = inputMemSize;
     540              :                 sliceTemp.offset
     541            0 :                     = (i * level0RankSize + j * level1RankSize * level0RankSize + level0ServerIndex) * inputMemSize;
     542            0 :                 level1DataSegsSlice.push_back(sliceTemp);
     543              :             }
     544              :         }
     545              : 
     546            0 :         CHK_RET(level1AGExecutor->Prepare(
     547              :             outputMem, outputMem, inputMem, count, dataType, stream, HCCL_REDUCE_RESERVED, INVALID_VALUE_RANKID,
     548              :             level1DataSegsSlice, 0));
     549              : 
     550            0 :         CHK_RET(level1AGExecutor->RegisterProfiler(
     551              :             (level1RankSize << PROF_RANKSIZE_OFFSET_OF_PLANEID) + level2CommInfo.localRank, PROF_STAGE_1,
     552              :             HCCL_EXEC_STEP_NOT_SET, stream));
     553              : 
     554            0 :         CHK_RET(RunTemplate(level1AGExecutor, level1CommInfo));
     555            0 :         HCCL_INFO("AllGather double ring [superpod] level1 AllGather run success");
     556            0 :     }
     557              : 
     558              :     // 节点内做AllGather double ring
     559            0 :     std::vector<Slice> dataSegsSlice;
     560            0 :     std::vector<std::vector<Slice>> multRingsSliceZero; // 数据基于该rank上环0的偏移
     561            0 :     CHK_RET(PrepareAllgatherSlice(level0RankSize, inputMemSize, dataSegsSlice));
     562              : 
     563              :     //  多环数据切分
     564            0 :     if (topoType_ == TopoType::TOPO_TYPE_NP_DOUBLE_RING) {
     565            0 :         multRingsSliceZero = PrepareMultiRingSlice(dataSegsSlice, tag, false, topoAttr_.nicList);
     566              :     } else {
     567            0 :         multRingsSliceZero.push_back(dataSegsSlice);
     568              :     }
     569            0 :     std::vector<std::vector<Slice>> multRingsSlice;
     570            0 :     for (u32 ringIndex = 0; ringIndex < multRingsSliceZero.size(); ringIndex++) {
     571            0 :         std::vector<Slice> level2DataSlice;
     572            0 :         CHK_RET(CalculateLevel2AllgatherSlice(
     573              :             inputMemSize, level0RankSize, level1RankSize, level2RankSize, multRingsSliceZero, level2DataSlice,
     574              :             ringIndex));
     575            0 :         multRingsSlice.push_back(level2DataSlice);
     576            0 :     }
     577              : 
     578            0 :     std::vector<std::vector<Slice>> multRingsUserMemSlice;
     579            0 :     if (!DMAReduceFlag_) {
     580            0 :         multRingsUserMemSlice = multRingsSlice;
     581              :     } else {
     582            0 :         for (u32 ringIndex = 0; ringIndex < multRingsSlice.size(); ringIndex++) {
     583            0 :             std::vector<Slice> level2UserMemSlice;
     584            0 :             for (auto& cclSlice : multRingsSlice[ringIndex]) {
     585            0 :                 Slice tmpSlice;
     586            0 :                 tmpSlice.size = cclSlice.size;
     587              :                 tmpSlice.offset
     588            0 :                     = (cclSlice.offset / inputMemSize) * count * perDataSize + multRingsSliceZero[ringIndex][0].offset;
     589            0 :                 level2UserMemSlice.push_back(tmpSlice);
     590            0 :                 HCCL_DEBUG(
     591              :                     "rank[%u], ringIndex[%u], tmpSlice.offset=[%llu], size=[%llu]", topoAttr_.userRank, ringIndex,
     592              :                     tmpSlice.offset, tmpSlice.size);
     593              :             }
     594            0 :             multRingsUserMemSlice.push_back(level2UserMemSlice);
     595            0 :         }
     596              :     }
     597              : 
     598            0 :     CHK_RET(ActiveSlaveStreams(stream));
     599            0 :     if (DMAReduceFlag_ && level1RankSize > 1) {
     600              :         // AllGather输入放在CCL buffer上,通过设置nullptr指示要从CCL buffer获取输入
     601            0 :         opInfo->inputAddr = nullptr;
     602              :     }
     603            0 :     CHK_RET(MultiRingAllGather(
     604              :         tag, inputMem, outputMem, count, dataType, multRingsSlice, stream, PROF_STAGE_2, 0, opInfo,
     605              :         multRingsUserMemSlice));
     606              : 
     607            0 :     HCCL_INFO("AllGather double ring [superpod] level2 AllGather run success");
     608            0 :     return HCCL_SUCCESS;
     609            0 : }
     610              : 
     611              : } // namespace hccl
        

Generated by: LCOV version 2.0-1