LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/impl/coll_executor/coll_reduce_scatter - coll_reduce_scatter_executor.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 33.5 % 361 121
Test Date: 2026-07-28 12:11:00 Functions: 41.2 % 17 7

            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_scatter_executor.h"
      12              : #include <numeric>
      13              : 
      14              : namespace hccl {
      15              : 
      16           48 : CollReduceScatterExecutor::CollReduceScatterExecutor(const HcclDispatcher dispatcher,
      17           48 :     std::unique_ptr<TopoMatcher> &topoMatcher)
      18           48 :     : CollCommExecutor(dispatcher, topoMatcher)
      19              : {
      20           49 : }
      21              : 
      22           14 : HcclResult CollReduceScatterExecutor::Orchestrate(OpParam& param, AlgResourceResponse& algRes)
      23              : {
      24           14 :     HcclUs startut = TIME_NOW();
      25           14 :     ParseParam(param);
      26           14 :     tag_ = param.tag;
      27           14 :     algResResp_ = &algRes;
      28           14 :     const u64 count = param.GetDataCount(topoAttr_.userRank);
      29           14 :     const HcclDataType dataType = param.GetDataType();
      30           14 :     HcclResult ret = HCCL_SUCCESS;
      31           14 :     bool needLaunchAtTheEnd = !is310P3Common_; // 是否需要在Orchestrate()结束时launch任务
      32              :     // 图模式和单卡场景下不需要Loop
      33           14 :     if (workflowMode_ != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
      34           12 :         ExecMem execMem;
      35           12 :         execMem.count = count;
      36           12 :         execMem.scratchMem = algRes.scratchMem;
      37           12 :         execMem.inputPtr = param.inputPtr;
      38           12 :         execMem.outputPtr = param.outputPtr;
      39           12 :         execMem.inputMem = algRes.paramInputMem;
      40           12 :         execMem.outputMem = algRes.paramOutputMem;
      41           12 :         ret = KernelRun(param, execMem);
      42           12 :         if (algOpContext_.opRetryHandler.isPostSync == true) {
      43              :             // post Sync
      44            0 :             CHK_RET(RetryPostSync(param, execMem));
      45              :         }
      46           14 :     } else if (topoAttr_.userRankSize == 1) {
      47            0 :         ExecMem execMem;
      48            0 :         execMem.count = count;
      49            0 :         execMem.inputPtr = param.inputPtr;
      50            0 :         execMem.outputPtr = param.outputPtr;
      51            0 :         execMem.inputMem = algRes.cclInputMem;
      52            0 :         execMem.outputMem = algRes.cclOutputMem;
      53            0 :         execMem.scratchMem = algRes.scratchMem;
      54            0 :         ret = KernelRun(param, execMem);
      55            0 :         needLaunchAtTheEnd = false;
      56            2 :     } else if (desc_.isZeroCopy) {
      57              :         // 在Level0执行KernelRun
      58            0 :         ExecMem execMem;
      59            0 :         execMem.count = count;
      60            0 :         execMem.inputPtr = param.inputPtr;
      61            0 :         execMem.outputPtr = param.outputPtr;
      62            0 :         execMem.inputMem = algRes.paramInputMem;
      63            0 :         execMem.outputMem = algRes.paramOutputMem;
      64            0 :         execMem.scratchMem = algRes.paramInputMem;
      65            0 :         ret = KernelRunIntraServerPre(param, execMem);
      66            0 :         CHK_PRT_RET(ret != HCCL_SUCCESS,
      67              :             HCCL_ERROR("[CollReduceScatterExecutor][Orchestrate]errNo[0x%016llx]ReduceScatter executor KernelRunIntraServerPre failed",
      68              :                 HCCL_ERROR_CODE(ret)), ret);
      69            0 :         if (algOpContext_.opRetryHandler.isPostSync == true) {
      70              :             // post Sync
      71            0 :             CHK_RET(RetryPostSync(param, execMem));
      72              :         }
      73              :         // 在Level1和Level2执行RunLoop
      74            0 :         if (topoAttr_.serverNum > 1) {
      75            0 :             ret = RunLoop(param, algRes); 
      76              :         } else {        // 单机场景,数据直接从UserInput搬到UserOutput
      77            0 :             u64 totalSize = count * SIZE_TABLE[dataType];
      78            0 :             DeviceMem srcMem = DeviceMem::create(static_cast<u8 *>(algRes.paramInputMem.ptr()) + totalSize * topoAttr_.userRank, totalSize);
      79            0 :             DeviceMem dstMem = DeviceMem::create(algRes.paramOutputMem.ptr(), totalSize);
      80            0 :             CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
      81            0 :         }
      82            0 :     } else {
      83            2 :         if (algOpContext_.opRetryHandler.isInplacePreSync == true) {
      84              :             /*当重执行场景,UserInMem > CCLBuffer时,需要在reduce scatter算子前增加一个PreSync函数,提升重执行成功概率*/
      85            0 :             ExecMem execMem;
      86            0 :             execMem.count = count;
      87            0 :             execMem.inputPtr = param.inputPtr;
      88            0 :             execMem.outputPtr = param.outputPtr;
      89            0 :             execMem.inputMem = algRes.cclInputMem;
      90            0 :             execMem.outputMem = algRes.cclOutputMem;
      91            0 :             execMem.scratchMem = algRes.scratchMem;
      92            0 :             ret = InplaceOpSync(param, execMem);
      93            2 :         } else if (isReduceScatterV_) {
      94            0 :             ret = RunLoopV(param, algRes);
      95            0 :             needLaunchAtTheEnd = false;
      96              :         } else {
      97            2 :             ret = RunLoop(param, algRes);
      98            2 :             needLaunchAtTheEnd = false;
      99              :         }
     100              :     }
     101           14 :     CHK_PRT_RET(ret != HCCL_SUCCESS,
     102              :         HCCL_ERROR("[CollReduceScatterExecutor][Orchestrate]errNo[0x%016llx]executor kernel run failed",
     103              :             HCCL_ERROR_CODE(ret)), ret);
     104              : 
     105              :     // Enforce task launch at the end of Orchestrate
     106              :     // 注意: 不要删除这里的强制launch, 否则会导致aicpu cache功能问题
     107           12 :     if (needLaunchAtTheEnd) {
     108           11 :         HCCL_INFO("%s: enforce task launch at the end of Orchestrate", __func__);
     109           11 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     110              :     }
     111              : 
     112           12 :     HCCL_INFO("tag[%s], ReduceScatter executor orchestrate success, take time [%lld]us.",
     113              :         param.tag.c_str(), DURATION_US(TIME_NOW() - startut));
     114           12 :     return HCCL_SUCCESS;
     115              : }
     116              : 
     117            0 : u64 CollReduceScatterExecutor::CalcLoopMaxCount(const u32 unitSize)
     118              : {
     119              :     // 中转内存单次最多能够接受的output count
     120            0 :     u64 maxCountPerLoop = inCCLbufferSize_ / topoAttr_.userRankSize / HCCL_MIN_SLICE_ALIGN
     121            0 :         * HCCL_MIN_SLICE_ALIGN / unitSize;
     122            0 :     HCCL_INFO("[CollReduceScatterExecutor][CalcLoopMaxCount]using default maxCountPerLoop[%llu] as "
     123              :         "CCLBuffSize / (userRankSize * unitSize). rsv[%u]", maxCountPerLoop, isReduceScatterV_);
     124            0 :     return maxCountPerLoop;
     125              : }
     126              : 
     127            0 : bool CollReduceScatterExecutor::IsHugeData(const u64 curSize, OpParam *param)
     128              : {
     129            0 :     bool hugeData = (curSize * topoAttr_.userRankSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE) ||
     130              :                             (curSize > SDMA_SEND_MAX_SIZE);
     131            0 :     return hugeData;
     132              : }
     133              : 
     134           16 : bool CollReduceScatterExecutor::IsSmallData(const u64 totalSize, const u64 curSize)
     135              : {
     136           16 :     HCCL_INFO("[CollReduceScatterExecutor][IsSmallData]opMeta is using the default option: not small data.");
     137           16 :     return false;
     138              : }
     139              : 
     140            2 : HcclResult CollReduceScatterExecutor::RunLoop(OpParam &param, AlgResourceResponse &algRes)
     141              : {
     142            2 :     u32 unitSize = SIZE_TABLE[param.DataDes.dataType];
     143            4 :     ReduceType reduceType = ((param.reduceType != HCCL_REDUCE_PROD) &&
     144            2 :         (param.DataDes.dataType != HCCL_DATA_TYPE_INT64)) ?
     145              :         ReduceType::INLINE_REDUCE : ReduceType::TBE_REDUCE;
     146              : 
     147            2 :     u8 *curInputPtr = static_cast<u8 *>(param.inputPtr);
     148            2 :     u8 *curOutputPtr = static_cast<u8 *>(param.outputPtr);
     149            2 :     CHK_PTR_NULL(curInputPtr);
     150            2 :     CHK_PTR_NULL(curOutputPtr);
     151              : 
     152            2 :     u64 maxCountPerLoop = CalcLoopMaxCount(unitSize);
     153            2 :     CHK_PRT_RET(maxCountPerLoop == 0,
     154              :         HCCL_ERROR("[CollReduceScatterExecutor][RunLoop]maxCountPerLoop is zero."),
     155              :         HCCL_E_INTERNAL);
     156            1 :     HCCL_DEBUG("[CollReduceScatterExecutor][RunLoop]tag[%s], userRankSize is [%u], maxCountPerLoop is [%llu].",
     157              :         param.tag.c_str(), topoAttr_.userRankSize, maxCountPerLoop);
     158              :     HcclResult ret;
     159            1 :     for (u64 countLeft = param.DataDes.count, curCount = 0, inputOffset = 0, outputOffset = 0;
     160           17 :             countLeft > 0; countLeft -= curCount) {
     161           16 :         curInputPtr += inputOffset;
     162           16 :         curOutputPtr += outputOffset;
     163              :         // 判断剩余数据量对应的output size是否大于中转output size
     164           16 :         curCount = (countLeft > maxCountPerLoop) ? maxCountPerLoop : countLeft;
     165           16 :         u64 curSize = curCount * unitSize; // 单位:字节
     166              : 
     167           16 :         HCCL_DEBUG("[CollReduceScatterExecutor][RunLoop]tag[%s], inputOffset[%llu], outputOffset[%llu], " \
     168              :             "sendBuf[%p], recvBuf[%p], sendCount[%llu], dataType[%d].",
     169              :             param.tag.c_str(), inputOffset, outputOffset, curInputPtr, curOutputPtr, curCount, param.DataDes.dataType);
     170              : 
     171           16 :         ExecMem execMem;
     172           16 :         execMem.count = curCount;
     173           16 :         execMem.inputMem = algRes.cclInputMem;
     174           16 :         execMem.outputMem = algRes.cclOutputMem;
     175           16 :         if (scratchMemFlag_) {
     176            0 :             execMem.scratchMem = algRes.scratchMem;
     177              :         } else {
     178           16 :             execMem.scratchMem = algRes.cclOutputMem; // 不需要申请则传入outputmem为scratchmem
     179              :         }
     180           16 :         HCCL_DEBUG("[CollReduceScatterExecutor][RunLoop]scratchMem address [%p]", execMem.scratchMem.ptr());
     181              : 
     182              :         // 使用当前Loop偏移到的地址作为当前的inputPtr和outputPtr
     183           16 :         execMem.inputPtr = curInputPtr;
     184           16 :         execMem.outputPtr = curOutputPtr;
     185              : 
     186           16 :         ret = RunLoopInner(param, reduceType, execMem);
     187           16 :         CHK_PRT_RET(ret != HCCL_SUCCESS,
     188              :             HCCL_ERROR("[CollReduceScatterExecutor][RunLoop]errNo[0x%016llx]kernel run error, tag[%s]",
     189              :             HCCL_ERROR_CODE(ret), param.tag.c_str()), ret);
     190              : 
     191           16 :         inputOffset = curSize;
     192           16 :         outputOffset = curSize;
     193           16 :     }
     194            1 :     if (algOpContext_.opRetryHandler.isPostSync == true) {
     195            0 :         ExecMem execMem;
     196            0 :         execMem.count = param.DataDes.count;
     197            0 :         execMem.inputPtr = param.inputPtr;
     198            0 :         execMem.outputPtr = param.outputPtr;
     199            0 :         execMem.inputMem = algRes.cclInputMem;
     200            0 :         execMem.outputMem = algRes.cclOutputMem;
     201            0 :         execMem.scratchMem = algRes.scratchMem;
     202            0 :         CHK_RET(RetryPostSync(param, execMem));
     203            0 :     }
     204            1 :     return HCCL_SUCCESS;
     205              : }
     206              : 
     207           16 : HcclResult CollReduceScatterExecutor::RunLoopInner(OpParam &param, const ReduceType &reduceType, ExecMem &execMem)
     208              : {
     209           16 :     u32 unitSize = SIZE_TABLE[param.DataDes.dataType];
     210           16 :     u64 curSize = execMem.count * unitSize; // 单位:字节
     211           16 :     CHK_PRT_RET((execMem.count == 0),
     212              :         HCCL_ERROR("[CollReduceScatterExecutor][RunLoopInner]In OP_BASE curCount is zero."), HCCL_E_PARA);
     213              :         
     214              :     // 不开启dma消减,且通信buffer足够大时,将user in到ccl的拷贝任务合并成一个
     215           16 :     const bool preloadCopyOpt = IsPreloadCopyOptimizeCondition(param, execMem);
     216              : 
     217           16 :     if (!is310P3Common_) {
     218              :         /* 设置子图复用标志 */
     219           16 :         auto autoSelectedAlgTypeLevel1 = static_cast<u32>(algType_.algoLevel1);
     220           16 :         bool hugeData = IsHugeData(curSize, &param);
     221           16 :         bool smallData = IsSmallData(param.DataDes.count * unitSize, curSize);
     222           16 :         bool dataSplit = false;
     223           16 :         u8 deterministic = topoMatcher_->GetExternalInputHcclDeterministic();
     224           16 :         auto opMeta = HcclOpMetaInfo::GetOneForReduceScatter(autoSelectedAlgTypeLevel1, param.DataDes.dataType,
     225              :             reduceType, hugeData, smallData, CopyPattern::BCOPY, dataSplit, deterministic, false, preloadCopyOpt);
     226              : 
     227           16 :         CHK_RET(InitTask(dispatcher_, param.stream, opMeta.isEnableCache, opMeta.GetCacheKey()));
     228              :     }
     229              : 
     230           16 :     if (CCLMemSlice_) {
     231           16 :         u32 sliceNum = desc_.isZeroCopy ? topoAttr_.serverNum : topoAttr_.userRankSize;
     232           16 :         execMem.inputMem = execMem.inputMem.range(0, curSize * sliceNum);
     233           16 :         execMem.outputMem = execMem.outputMem.range(0, curSize);
     234           16 :         if (scratchMemFlag_) {
     235            0 :             execMem.scratchMem = execMem.scratchMem.range(0, curSize * topoAttr_.userRankSize);
     236              :         }
     237              :     }
     238              : 
     239              :     // 执行
     240           16 :     if (!DMAReduceFlag_) {   // 如果使用in CCL buffer,需要将user buffer in中的结果拷贝到CCL buffer in
     241            0 :         DeviceMem dstMem;
     242            0 :         DeviceMem srcMem;
     243            0 :         if (preloadCopyOpt) {
     244              :             // 中转内存大小足够时,一次性搬完
     245            0 :             const u64 copySize = param.DataDes.count * unitSize * topoAttr_.userRankSize;
     246            0 :             dstMem = execMem.inputMem.range(0, copySize);
     247            0 :             srcMem = DeviceMem::create(static_cast<u8 *>(execMem.inputPtr), copySize);
     248            0 :             CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     249              :         } else {
     250            0 :             for (u32 i = 0; i < topoAttr_.userRankSize; i++) {
     251              :                 // 拷贝input上每个slice的数据到中转内存,源端每个slice的size固定为output的size
     252            0 :                 dstMem = execMem.inputMem.range(curSize * i, curSize);
     253            0 :                 srcMem = DeviceMem::create(static_cast<u8 *>(execMem.inputPtr) + param.DataDes.count * unitSize * i,
     254            0 :                     curSize);
     255            0 :                 CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     256              :             }
     257              :         }
     258            0 :     }
     259              : 
     260           16 :     HcclResult ret = HCCL_SUCCESS;
     261           16 :     if (!desc_.isZeroCopy) {  
     262           16 :         ret = KernelRun(param, execMem);
     263              :     } else {
     264            0 :         ret = KernelRunInterServer(param, execMem);
     265              :     }
     266           16 :     CHK_PRT_RET(ret != HCCL_SUCCESS,
     267              :         HCCL_ERROR("[CollReduceScatterExecutor][RunLoopInner]errNo[0x%016llx]kernel run error, tag[%s], " \
     268              :         "inputMem ptr[%p], outputMem ptr[%p], count[%llu], dataType[%d], reduce op type[%d], preloadCopyOpt[%d]",
     269              :         HCCL_ERROR_CODE(ret), param.tag.c_str(), execMem.inputMem.ptr(), execMem.outputMem.ptr(),
     270              :         execMem.count, param.DataDes.dataType, param.reduceType, preloadCopyOpt),
     271              :         ret);
     272              : 
     273           16 :     if (!DMAReduceFlag_) {
     274              :         // 如果使用CCL buffer,需要将CCL buffer out中的结果拷贝到user buffer out
     275            0 :         DeviceMem srcMem = execMem.outputMem.range(0, curSize);
     276            0 :         DeviceMem dstMem = DeviceMem::create(execMem.outputPtr, curSize);
     277            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     278            0 :     }
     279           16 :     HCCL_DEBUG("[CollReduceScatterExecutor][RunLoopInner]inputMem ptr is [%p], outputMem ptr is [%p]",
     280              :         execMem.inputMem.ptr(), execMem.outputMem.ptr());
     281              : 
     282           16 :     if (!is310P3Common_) {
     283           16 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     284              :     }
     285           16 :     return ret;
     286              : }
     287              : 
     288            0 : HcclResult CollReduceScatterExecutor::RunLoopV(OpParam &param, AlgResourceResponse &algRes)
     289              : {
     290              :     // 每轮loop需要重新计算counts和displs
     291            0 :     const auto *countsPtr = static_cast<const u64*>(param.VDataDes.counts);
     292            0 :     auto countsLeft = std::vector<u64>(countsPtr, countsPtr + topoAttr_.userRankSize);
     293            0 :     const auto *displsPtr = static_cast<const u64*>(param.VDataDes.displs);
     294            0 :     auto displs = std::vector<u64>(displsPtr, displsPtr + topoAttr_.userRankSize);
     295              : 
     296            0 :     const HcclDataType dataType = param.VDataDes.dataType;
     297            0 :     const u32 unitSize = SIZE_TABLE[dataType];
     298              : 
     299            0 :     u8 *curInputPtr = static_cast<u8 *>(param.inputPtr);
     300            0 :     u8 *curOutputPtr = static_cast<u8 *>(param.outputPtr);
     301            0 :     CHK_PTR_NULL(curInputPtr);
     302              : 
     303            0 :     if (UNLIKELY(countsLeft[topoAttr_.userRank] == 0 && curOutputPtr == nullptr)) {
     304              :         // 若本rank的output count为0,此时允许curOutputPtr传入空指针,为保证后续流程正常执行,赋值为cclout的地址
     305            0 :         curOutputPtr = static_cast<u8 *>(algRes.cclOutputMem.ptr());
     306            0 :         HCCL_DEBUG("[CollReduceScatterExecutor][RunLoopV]Since the output count is 0, set curOutputPtr to "
     307              :             "ccl output[%p]", curOutputPtr);
     308              :     }
     309            0 :     CHK_PTR_NULL(curOutputPtr);
     310              : 
     311            0 :     ReduceType reduceType = ((param.reduceType != HCCL_REDUCE_PROD) && (dataType != HCCL_DATA_TYPE_INT64)) ?
     312              :         ReduceType::INLINE_REDUCE : ReduceType::TBE_REDUCE;
     313              : 
     314              :     // 计算MaxCountPerLoop
     315            0 :     const u64 maxCountPerLoop = CalcLoopMaxCount(unitSize);
     316              : 
     317              :     HcclResult ret;
     318            0 :     bool finished = false;
     319            0 :     while (!finished) {
     320              :         // 每个块尽可能平分,以均衡利用带宽
     321            0 :         auto curCounts = std::vector<u64>();
     322            0 :         auto curDispls = std::vector<u64>();
     323            0 :         finished = CalcCurCountsAndCurDispls(maxCountPerLoop, countsLeft, displs, curCounts, curDispls, unitSize);
     324              :         // 打印调测信息
     325            0 :         PrintCurCountAndCurDispls(curCounts, curDispls);
     326              : 
     327            0 :         OpParam curParam = param;
     328            0 :         curParam.VDataDes.counts = curCounts.data();
     329            0 :         curParam.VDataDes.displs = curDispls.data();
     330            0 :         curParam.VDataDes.dataType = dataType;
     331              : 
     332            0 :         ExecMem execMem;
     333            0 :         execMem.count = curCounts[topoAttr_.userRank];
     334            0 :         execMem.inputPtr = curInputPtr;
     335            0 :         execMem.outputPtr = curOutputPtr;
     336            0 :         execMem.inputMem = algRes.cclInputMem;
     337            0 :         execMem.outputMem = algRes.cclOutputMem;
     338            0 :         if (scratchMemFlag_) {
     339            0 :             execMem.scratchMem = algRes.scratchMem;
     340              :         } else {
     341            0 :             execMem.scratchMem = algRes.cclOutputMem; // 不需要申请则传入outputmem为scratchmem
     342              :         }
     343            0 :         ret = RunLoopInnerV(curParam, reduceType, execMem);
     344            0 :         CHK_PRT_RET(ret != HCCL_SUCCESS,
     345              :             HCCL_ERROR("[CollReduceScatterExecutor][RunLoopV]errNo[0x%016llx]kernel run error, tag[%s]",
     346              :             HCCL_ERROR_CODE(ret), curParam.tag.c_str()), ret);
     347              : 
     348            0 :         const auto outputSize = curCounts[topoAttr_.userRank] * unitSize;
     349            0 :         curOutputPtr += outputSize;
     350              :         // ReduceScatterV curInputPtr不需要偏移,input的偏移由displs计算
     351            0 :         HCCL_DEBUG("[CollReduceScatterExecutor][RunLoopV]kernel run, finished[%u]", finished);
     352            0 :     }
     353            0 :     return HCCL_SUCCESS;
     354            0 : }
     355              : 
     356            0 : HcclResult CollReduceScatterExecutor::RunLoopInnerV(OpParam &param, const ReduceType &reduceType, ExecMem &execMem)
     357              : {
     358            0 :     const auto *counts = static_cast<u64*>(param.VDataDes.counts);
     359            0 :     u64 count = counts[topoAttr_.userRank];
     360            0 :     HcclDataType dataType = param.VDataDes.dataType;
     361            0 :     u32 unitSize = SIZE_TABLE[dataType];
     362            0 :     u64 curSize = count * unitSize; // 单位:字节;
     363              : 
     364              :     /* 设置子图复用标志 */
     365            0 :     auto autoSelectedAlgTypeLevel1 = static_cast<u32>(algType_.algoLevel1);
     366            0 :     bool hugeData = IsHugeData(curSize, &param);
     367            0 :     u8 deterministic = topoMatcher_->GetExternalInputHcclDeterministic();
     368            0 :     auto opMeta = HcclOpMetaInfo::GetOneForReduceScatterV(autoSelectedAlgTypeLevel1,
     369              :         dataType, reduceType, hugeData, false, CopyPattern::BCOPY, false, deterministic);
     370              : 
     371            0 :     CHK_RET(InitTask(dispatcher_, param.stream, opMeta.isEnableCache, opMeta.GetCacheKey()));
     372              : 
     373            0 :     if (CCLMemSlice_) {
     374            0 :         const u64 inputCounts = std::accumulate(counts, counts + topoAttr_.userRankSize, 0ULL);
     375            0 :         execMem.inputMem = execMem.inputMem.range(0, inputCounts * unitSize);
     376            0 :         execMem.outputMem = execMem.outputMem.range(0, curSize);
     377            0 :         if (scratchMemFlag_) {
     378            0 :             execMem.scratchMem = execMem.scratchMem.range(0, inputCounts * unitSize);
     379              :         }
     380              :     }
     381              : 
     382              :     // 执行
     383            0 :     HcclResult ret = KernelRun(param, execMem);
     384            0 :     CHK_PRT_RET(ret != HCCL_SUCCESS,
     385              :         HCCL_ERROR("[CollReduceScatterExecutor][RunLoopInnerV]errNo[0x%016llx]kernel run error, tag[%s], "
     386              :         "inputMem ptr[%p], outputMem ptr[%p], count[%llu], dataType[%d], reduce op type[%d]", HCCL_ERROR_CODE(ret),
     387              :         param.tag.c_str(), execMem.inputMem.ptr(), execMem.outputMem.ptr(), execMem.count, dataType, param.reduceType),
     388              :         ret);
     389              : 
     390            0 :     CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     391            0 :     return ret;
     392              : }
     393              : 
     394            0 : bool CollReduceScatterExecutor::CalcCurCountsAndCurDispls(const u64 maxTotalCount, std::vector<u64> &countsLeft,
     395              :     std::vector<u64> &displs, std::vector<u64> &curCounts, std::vector<u64> &curDispls, u32 unitSize)
     396              : {
     397            0 :     bool finished = false;
     398              : 
     399            0 :     curCounts = std::vector<u64>(countsLeft.size(), 0);
     400            0 :     curDispls = std::vector<u64>(displs.size(), 0);
     401            0 :     auto allocatableCount = maxTotalCount;
     402              : 
     403              :     // 先设置本轮的displacements,等于入参displs
     404            0 :     std::copy(displs.begin(), displs.end(), curDispls.begin());
     405              : 
     406              :     // 分配本轮的counts,如果CCLbuffer空间还没完全利用,则再进行分配
     407            0 :     while (allocatableCount > 0) {
     408              :         // 计算现在还有几个rank还有数据需要去通信(countsLeft不为0)
     409              :         const auto nonZeroCount =
     410            0 :             std::count_if(countsLeft.begin(), countsLeft.end(), [](const u64 count) { return count != 0; });
     411            0 :         if (nonZeroCount == 0) {
     412            0 :             finished = true;
     413            0 :             break;
     414              :         }
     415              : 
     416              :         // 计算每个rank可以分到多少count
     417            0 :         auto perRankCount = allocatableCount / nonZeroCount;
     418            0 :         if (perRankCount == 0) {
     419            0 :             break;
     420              :         }
     421              : 
     422            0 :         const u64 perRankSize = perRankCount * unitSize;
     423            0 :         if (perRankSize > HCCL_MIN_SLICE_ALIGN) {
     424            0 :             perRankCount = perRankSize / HCCL_MIN_SLICE_ALIGN * HCCL_MIN_SLICE_ALIGN / unitSize;    // align for perf
     425            0 :         } else if ((perRankSize < HCCL_MIN_SLICE_ALIGN) && (allocatableCount != maxTotalCount)) {
     426            0 :             break;
     427              :         }
     428              : 
     429              :         // 分配好每个rank的counts
     430            0 :         for (auto i = 0U; i < countsLeft.size(); ++i) {
     431            0 :             const auto curCount = countsLeft[i] < perRankCount ? countsLeft[i] : perRankCount;
     432            0 :             allocatableCount -= curCount;
     433            0 :             curCounts[i] += curCount;
     434            0 :             countsLeft[i] -= curCount;
     435            0 :             displs[i] += curCount;
     436              :         }
     437              :     }
     438            0 :     return finished;
     439              : }
     440              : 
     441            0 : void CollReduceScatterExecutor::PrintCurCountAndCurDispls(const std::vector<u64> &curCounts,
     442              :     const std::vector<u64> &curDispls)
     443              : {
     444            0 :     if (HcclCheckLogLevel(DLOG_DEBUG)) {
     445            0 :         std::ostringstream curLoopInfo;
     446            0 :         curLoopInfo << "counts[ ";
     447            0 :         for (auto count : curCounts) {
     448            0 :             curLoopInfo << count << " ";
     449              :         }
     450            0 :         curLoopInfo << "], displs[ ";
     451            0 :         for (auto displ : curDispls) {
     452            0 :             curLoopInfo << displ << " ";
     453              :         }
     454            0 :         curLoopInfo << "]";
     455            0 :         HCCL_DEBUG("[CollReduceScatterExecutor][PrintCurCountAndCurDispls] Current loop info: %s",
     456              :             curLoopInfo.str().c_str());
     457            0 :     }
     458            0 : }
     459              : 
     460           20 : std::vector<std::vector<Slice>> CollReduceScatterExecutor::ReduceScatterRingSlicePrepare(u32 ringNum, u32 sliceNum,
     461              :     bool useInlineReduce, const DeviceMem& outputMem, std::vector<Slice>& dataSegsSlice, const std::string &tag)
     462              : {
     463           20 :     std::vector<std::vector<Slice>> multiStreamSlice;
     464           20 :     u64 outputMemSize = outputMem.size();
     465           20 :     dataSegsSlice.clear();
     466           20 :     Slice sliceTemp;
     467           57 :     for (u32 i = 0; i < sliceNum; i++) {    // 根据数据量算每个环上数据的偏移和大小
     468           37 :         sliceTemp.size = outputMemSize;
     469           37 :         sliceTemp.offset = outputMemSize * i;
     470           37 :         dataSegsSlice.push_back(sliceTemp);
     471              :     }
     472           20 :     bool ARSFlag = topoMatcher_->GetARSFlag();
     473           20 :     auto nicList = topoAttr_.nicList;
     474           20 :     if (ARSFlag) {
     475            0 :         std::vector<u32> mockNicList;
     476            0 :         for (u32 i = 0; i < sliceNum; i++) {
     477            0 :             mockNicList.push_back(i);
     478              :         }
     479            0 :         nicList = mockNicList;
     480            0 :     }
     481              : 
     482              :     // 再将每个 slice 划分为 ringNum 份
     483           20 :     if (ringNum == LEVEL0_PLANE_NUM_IN_8PRING) {
     484            0 :         if (useInlineReduce) {
     485            0 :             multiStreamSlice = PrepareMultiRingSlice(dataSegsSlice, tag);
     486            0 :         } else if (outputMem.size() % CCE_REDUCE_ALIGN_SIZE == 0) {
     487            0 :             multiStreamSlice = PrepareMultiRingSlice(dataSegsSlice, tag);
     488              :         } else {
     489            0 :             multiStreamSlice = PrepareMultiRingSlice(dataSegsSlice, tag, true);
     490              :         }
     491           20 :     } else if (ringNum == LEVEL0_PLANE_NUM_IN_NPRING_DOUBLE) {
     492              :         // 双环场景,需要传入正确的 niclist (不涉及网口裁剪)
     493           16 :         if (useInlineReduce) {
     494           16 :             multiStreamSlice = PrepareMultiRingSlice(dataSegsSlice, tag, false, nicList);
     495            0 :         } else if (outputMem.size() % CCE_REDUCE_ALIGN_SIZE == 0) {
     496            0 :             multiStreamSlice = PrepareMultiRingSlice(dataSegsSlice, tag, false, nicList);
     497              :         } else {
     498            0 :             multiStreamSlice = PrepareMultiRingSlice(dataSegsSlice, tag, true, nicList);
     499              :         }
     500              :     } else {
     501            4 :         multiStreamSlice.push_back(dataSegsSlice);
     502              :     }
     503              : 
     504           20 :     return multiStreamSlice;
     505           20 : }
     506              : 
     507            0 : HcclResult CollReduceScatterExecutor::PrepareAivBuffers(u32 rankSize, u32 rankId, u32 rankOffset,
     508              :     DeviceMem &inputMem, DeviceMem &outputMem, std::vector<LINK> &links, void **dataBuffers, void **flagBuffers,
     509              :     UserMemType dataMemType, UserMemType flagMemType, u32 dataMemOffset, u32 flagMemOffset)
     510              : {
     511            0 :     void *tmpCCLBufferData = nullptr;
     512            0 :     void *tmpCCLBufferFlag = nullptr;
     513            0 :     for (u32 i = 0; i < rankSize; i++) {
     514            0 :         if (i != rankId) {
     515            0 :             if (links[i + rankOffset] != nullptr) {
     516            0 :                 CHK_RET(links[i + rankOffset]->GetRemoteMem(dataMemType, &(tmpCCLBufferData)));
     517            0 :                 CHK_RET(links[i + rankOffset]->GetRemoteMem(flagMemType, &(tmpCCLBufferFlag)));
     518            0 :                 dataBuffers[i] = static_cast<u8 *>(tmpCCLBufferData) + dataMemOffset;
     519            0 :                 flagBuffers[i] = static_cast<u8 *>(tmpCCLBufferFlag) + flagMemOffset;
     520              :             }
     521              :         } else {
     522            0 :             dataBuffers[i] = static_cast<u8 *>(inputMem.ptr()) + dataMemOffset;
     523            0 :             flagBuffers[i] = static_cast<u8 *>(outputMem.ptr()) + flagMemOffset;
     524              :         }
     525              :     }
     526            0 :     return HCCL_SUCCESS;
     527              : }
     528              : 
     529            0 : std::vector<std::vector<Slice>> CollReduceScatterExecutor::AnyPathReduceScatterRingSlicePrepare(u32 ringNum,
     530              :     u32 sliceNum, bool useInlineReduce, DeviceMem& outputMem, std::vector<Slice>& dataSegsSlice, const std::string &tag)
     531              : {
     532            0 :     std::vector<std::vector<Slice>> multiStreamSlice;
     533            0 :     u64 outputMenSize = outputMem.size();
     534            0 :     dataSegsSlice.clear();
     535            0 :     Slice sliceTemp;
     536            0 :     for (u32 i = 0; i < sliceNum; i++) {    // 根据数据量算每个环上数据的偏移和大小
     537            0 :         sliceTemp.size = outputMenSize;
     538            0 :         sliceTemp.offset = outputMenSize * i;
     539            0 :         dataSegsSlice.push_back(sliceTemp);
     540              :     }
     541              : 
     542              :     // 再将每个 slice 划分为 ringNum 份
     543            0 :     if (ringNum == LEVEL0_PLANE_NUM_IN_8PRING) {
     544            0 :         if (useInlineReduce) {
     545            0 :             multiStreamSlice = AnyPathPrepareMultiRingSlice(dataSegsSlice, tag);
     546            0 :         } else if (outputMem.size() % CCE_REDUCE_ALIGN_SIZE == 0) {
     547            0 :             multiStreamSlice = AnyPathPrepareMultiRingSlice(dataSegsSlice, tag);
     548              :         } else {
     549            0 :             multiStreamSlice = AnyPathPrepareMultiRingSlice(dataSegsSlice, tag, true);
     550              :         }
     551            0 :     } else if (ringNum == LEVEL0_PLANE_NUM_IN_NPRING_DOUBLE) {
     552              :         // 双环场景,需要传入正确的 niclist (不涉及网口裁剪)
     553            0 :         if (useInlineReduce) {
     554            0 :             multiStreamSlice = AnyPathPrepareMultiRingSlice(dataSegsSlice, tag, false, topoAttr_.nicList);
     555            0 :         } else if (outputMem.size() % CCE_REDUCE_ALIGN_SIZE == 0) {
     556            0 :             multiStreamSlice = AnyPathPrepareMultiRingSlice(dataSegsSlice, tag, false, topoAttr_.nicList);
     557              :         } else {
     558            0 :             multiStreamSlice = AnyPathPrepareMultiRingSlice(dataSegsSlice, tag, true, topoAttr_.nicList);
     559              :         }
     560              :     } else {
     561            0 :         multiStreamSlice.push_back(dataSegsSlice);
     562              :     }
     563              : 
     564            0 :     return multiStreamSlice;
     565            0 : }
     566              : 
     567            0 : HcclResult CollReduceScatterExecutor::RetryPostSync(OpParam& param, ExecMem &execMem)
     568              : {
     569            0 :     if ((algResResp_->slaveStreams).size() == 0) {
     570            0 :         CHK_RET(PostSyncWithoutSubstream(param, execMem));
     571              :     } else {
     572            0 :         PrepareData postSyncPrepareData;
     573            0 :         postSyncPrepareData.subStreamsPtr = &algResResp_->slaveStreams;
     574            0 :         postSyncPrepareData.signalPtr = &algResResp_->notifiesMain;
     575            0 :         postSyncPrepareData.signalAuxPtr = &algResResp_->notifiesAux;
     576            0 :         postSyncPrepareData.stream = param.stream;
     577            0 :         CHK_RET(PostSyncWithSubstream(param, execMem, postSyncPrepareData));
     578            0 :     }
     579            0 :     return HCCL_SUCCESS;
     580              : }
     581              : 
     582           16 : bool CollReduceScatterExecutor::IsPreloadCopyOptimizeCondition(const OpParam &param, ExecMem &execMem)
     583              : {
     584              :     // 不开启dma消减,且通信buffer足够大时,将user in到ccl的拷贝任务合并成一个
     585           16 :     return (!DMAReduceFlag_) && (param.DataDes.count == execMem.count);
     586              : }
     587              : } // namespace hccl
        

Generated by: LCOV version 2.0-1