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

Generated by: LCOV version 2.0-1