LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/impl/coll_executor/coll_scatter - coll_scatter_executor.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 10.1 % 158 16
Test Date: 2026-07-28 12:11:00 Functions: 30.0 % 10 3

            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_scatter_executor.h"
      12              : #include "device_capacity.h"
      13              : 
      14              : namespace hccl {
      15            1 : CollScatterExecutor::CollScatterExecutor(const HcclDispatcher dispatcher,
      16            1 :                                 std::unique_ptr<TopoMatcher> &topoMatcher)
      17            1 :     : CollCommExecutor(dispatcher, topoMatcher)
      18              : {
      19            4 : }
      20              : 
      21            4 : HcclResult CollScatterExecutor::CalcCommInfo(std::vector<LevelNSubCommTransport>& opTransport)
      22              : {
      23            4 :     TransportMemType inputType = TransportMemType::RESERVED;
      24            4 :     TransportMemType outputType = TransportMemType::RESERVED;
      25            4 :     CHK_RET(CalcTransportMemType(inputType, outputType));
      26            4 :     CHK_RET(CalcLevel0CommInfo(inputType, outputType, opTransport));
      27            4 :     CHK_RET(CalcLevel1CommInfo(inputType, outputType, opTransport));
      28            4 :     return HCCL_SUCCESS;
      29              : }
      30              : 
      31            4 : HcclResult CollScatterExecutor::CalcTransportMemType(TransportMemType &inputType, TransportMemType &outputType)
      32              : {
      33            4 :     if (workflowMode_ == HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
      34            4 :         inputType = TransportMemType::CCL_INPUT;
      35            4 :         outputType = TransportMemType::CCL_INPUT;
      36              :     } else {
      37            0 :         inputType = TransportMemType::PARAM_INPUT;
      38            0 :         outputType = TransportMemType::PARAM_INPUT;
      39              :     }
      40            4 :     return HCCL_SUCCESS;
      41              : }
      42              : 
      43            0 : bool CollScatterExecutor::IsHugeData(u64 curSize)
      44              : {
      45            0 :     bool hugeData = curSize * topoAttr_.userRankSize / HCCL_INTERNODE_MAX_DATA_RATE > RDMA_SEND_MAX_SIZE ||
      46              :         curSize > SDMA_SEND_MAX_SIZE;
      47            0 :     return hugeData;
      48              : }
      49              : 
      50            0 : HcclResult CollScatterExecutor::RunLoop(OpParam &param, AlgResourceResponse &algRes)
      51              : {
      52            0 :     auto dataType = param.DataDes.dataType;
      53            0 :     u32 unitSize = SIZE_TABLE[dataType];
      54            0 :     RankId root = param.root;
      55              : 
      56            0 :     auto totalRecvCount = param.DataDes.count;
      57              : 
      58            0 :     u8 *curUserInputPtr = static_cast<u8 *>(param.inputPtr);
      59            0 :     u8 *curUserOutputPtr = static_cast<u8 *>(param.outputPtr);
      60            0 :     if (topoAttr_.userRank == root) {
      61            0 :         CHK_PTR_NULL(curUserInputPtr);
      62              :     }
      63            0 :     CHK_PTR_NULL(curUserOutputPtr);
      64              : 
      65            0 :     auto inCCLbuffer = algRes.cclInputMem;
      66            0 :     auto outCCLbuffer = algRes.cclOutputMem;
      67              : 
      68              :     // 中转内存单次最多能够接受的output count
      69            0 :     u64 maxCountPerLoop = inCCLbuffer.size() / topoAttr_.userRankSize / HCCL_MIN_SLICE_ALIGN
      70            0 :         * HCCL_MIN_SLICE_ALIGN / unitSize;
      71            0 :     HCCL_DEBUG("[CollScatterExecutor][RunLoop]tag[%s], userRankSize is [%u], root is [%u], "
      72              :                "maxCountPerLoop is [%llu], totalRecvCount is [%llu]",
      73              :         tag_.c_str(), topoAttr_.userRankSize, root, maxCountPerLoop, totalRecvCount);
      74              : 
      75            0 :     for (u64 countLeft = totalRecvCount, curRecvCount = 0, inputOffset = 0, outputOffset = 0;
      76            0 :         countLeft > 0; countLeft -= curRecvCount) {
      77            0 :         curUserInputPtr += inputOffset;
      78            0 :         curUserOutputPtr += outputOffset;
      79              : 
      80              :         // 判断剩余数据量对应的input size是否大于中转input size
      81            0 :         curRecvCount =
      82            0 :             ((countLeft * unitSize * topoAttr_.userRankSize) > inCCLbuffer.size()) ? maxCountPerLoop : countLeft;
      83            0 :         CHK_PRT_RET((curRecvCount == 0), HCCL_ERROR("[RunLoop][Scatter]In OP_BASE curRecvCount is zero"), HCCL_E_PARA);
      84            0 :         u64 curRecvSize = curRecvCount * unitSize;               // 单位:字节
      85            0 :         u64 curSendSize = topoAttr_.userRankSize * curRecvSize;  // 单位:字节
      86              : 
      87            0 :         DeviceMem curCCLInputMem(inCCLbuffer.ptr(), curSendSize);
      88            0 :         DeviceMem curCCLOutputMem(outCCLbuffer.ptr(), curRecvSize);
      89              : 
      90            0 :         ExecMem execMem;
      91            0 :         execMem.count = curRecvCount;
      92            0 :         execMem.inputMem = curCCLInputMem;
      93            0 :         execMem.outputMem = curCCLOutputMem;
      94            0 :         execMem.scratchMem = algRes.scratchMem;
      95              :         // 使用当前Loop偏移到的地址作为当前的inputPtr和outputPtr
      96            0 :         execMem.inputPtr = curUserInputPtr;
      97            0 :         execMem.outputPtr = curUserOutputPtr;
      98              : 
      99            0 :         HCCL_DEBUG("[RunLoop][Scatter] ScatterLoop: inputOffset[%llu], outputOffset[%llu], "
     100              :             "curUserInputPtr[%p], curUserOutputPtr[%p], curRecvCount[%llu], curRecvSize[%llu], "
     101              :             "curSendSize[%llu], inCCLbuffer.ptr[%p], outCCLbuffer.ptr[%p]",
     102              :             inputOffset, outputOffset, curUserInputPtr, curUserOutputPtr, curRecvCount, curRecvSize,
     103              :             curSendSize, inCCLbuffer.ptr(), outCCLbuffer.ptr());
     104              : 
     105            0 :         CHK_RET(RunLoopInner(param, execMem, algRes));
     106              : 
     107            0 :         inputOffset = curRecvSize;
     108            0 :         outputOffset = curRecvSize;
     109            0 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     110            0 :     }
     111            0 :     return HCCL_SUCCESS;
     112            0 : }
     113              : 
     114            0 : HcclResult CollScatterExecutor::RunLoopInner(OpParam &param, ExecMem &execMem, AlgResourceResponse &algRes)
     115              : {
     116            0 :     auto dataType = param.DataDes.dataType;
     117            0 :     u32 unitSize = SIZE_TABLE[dataType];
     118            0 :     RankId root = param.root;
     119              : 
     120            0 :     auto totalRecvCount = param.DataDes.count;
     121            0 :     u64 totalRecvSize = totalRecvCount * unitSize;
     122              : 
     123            0 :     u64 recvSize = execMem.outputMem.size();
     124              : 
     125            0 :     auto meta = HcclOpMetaInfo::GetOneForScatter(root, IsHugeData(execMem.outputMem.size()));
     126            0 :     CHK_RET(InitTask(dispatcher_, param.stream, meta.isEnableCache, meta.GetCacheKey()));
     127              : 
     128            0 :     DeviceMem dstMem;
     129            0 :     DeviceMem srcMem;
     130            0 :     if (topoAttr_.userRank == root) {
     131              :         // 本rank为root节点,非root节点不需要拷贝到中转内存
     132            0 :         for (u32 i = 0; i < topoAttr_.userRankSize; i++) {
     133              :             // 拷贝input上每个slice的数据到中转内存,源端每个slice的size固定为totalRecvSize
     134            0 :             srcMem = DeviceMem::create((u8*)execMem.inputPtr + totalRecvSize * i, recvSize);
     135            0 :             dstMem = algRes.cclInputMem.range(recvSize * i, recvSize);
     136            0 :             CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     137              :         }
     138              :     }
     139              : 
     140            0 :     if (recvSize % HCCL_MIN_SLICE_ALIGN != 0) {
     141              :         // 不支持内存不对齐的轮次
     142            0 :         DMAReduceFlag_ = false;
     143              :     }
     144              : 
     145              :     /* 入参的正确性由HCCL确保 */
     146            0 :     HcclResult ret = KernelRun(param, execMem);
     147              : 
     148            0 :     CHK_PRT_RET(ret != HCCL_SUCCESS,
     149              :         HCCL_ERROR("[CollScatterExecutor][RunLoop]errNo[0x%016llx] OP_BASE hcclComm scatter error, tag[%s], "
     150              :                    "input_ptr[%p], output_ptr[%p], recvSize[%llu], data_type[%d], root[%u]",
     151              :             HCCL_ERROR_CODE(ret), tag_.c_str(), algRes.cclInputMem.ptr(), algRes.cclOutputMem.ptr(),
     152              :             recvSize, dataType, root),
     153              :         ret);
     154              : 
     155              :     // 将 CCLOut 上的数据搬运到 userOut
     156            0 :     if (!DMAReduceFlag_) {
     157            0 :         srcMem = algRes.cclOutputMem.range(0, recvSize);
     158            0 :         dstMem = DeviceMem::create(execMem.outputPtr, recvSize);
     159            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dstMem, srcMem, param.stream));
     160              :     }
     161            0 :     return HCCL_SUCCESS;
     162            0 : }
     163              : 
     164            0 : HcclResult CollScatterExecutor::PrepareDataSlice(u64 dataCount, u32 unitSize, u32 sliceNum,
     165              :     std::vector<Slice> &dataSlice)
     166              : {
     167            0 :     CHK_PRT_RET((sliceNum == 0), HCCL_ERROR("[CollScatterExecutor][PrepareDataSlice]sliceNum is zero."), HCCL_E_PARA);
     168              : 
     169            0 :     dataSlice.resize(sliceNum);
     170            0 :     u64 sliceSize = dataCount * unitSize;
     171            0 :     for (u32 i = 0; i < sliceNum; i++) {
     172            0 :         dataSlice[i].size = sliceSize;
     173            0 :         dataSlice[i].offset = (i * sliceSize);
     174              :     }
     175            0 :     return HCCL_SUCCESS;
     176              : }
     177              : 
     178            0 : HcclResult CollScatterExecutor::ReorderSlice(std::vector<Slice> &dataSlice, std::vector<u32> &order)
     179              : {
     180            0 :     CHK_PRT_RET((dataSlice.size() != order.size()),
     181              :         HCCL_ERROR("[ReorderSlice] data slice size [%zu], not equal to order size [%zu]",
     182              :             dataSlice.size(), order.size()), HCCL_E_INTERNAL);
     183            0 :     std::vector<Slice> tempDataSegsSlice(dataSlice.size());
     184            0 :     for (size_t i = 0; i < dataSlice.size(); i++) {
     185            0 :         CHK_PRT_RET(order[i] >= dataSlice.size(),
     186              :             HCCL_ERROR("[ReorderSlice] order value [%u] >=  dataSlice size [%zu]", order[i], dataSlice.size()),
     187              :             HCCL_E_INTERNAL);
     188            0 :         tempDataSegsSlice[i] = dataSlice[order[i]];
     189              :     }
     190            0 :     dataSlice = tempDataSegsSlice;
     191            0 :     return HCCL_SUCCESS;
     192            0 : }
     193              : 
     194            0 : HcclResult CollScatterExecutor::KernelRunLevel1(DeviceMem& inputMem, u64 count, HcclDataType dataType,
     195              :     u32 &commIndex, u32 root, u32 &subRoot, CommPlane commLevel, Stream& stream)
     196              : {
     197            0 :     CHK_RET(CheckCommSize(commLevel, commIndex + 1));
     198            0 :     SubCommInfo subCommInfo = GetSubCommInfo(commLevel, commIndex);
     199              : 
     200            0 :     u32 subCommSize = subCommInfo.localRankSize;
     201              : 
     202            0 :     if (subCommSize <= 1 || subRoot != topoAttr_.userRank) {
     203            0 :         HCCL_INFO("[Scatter][KernelRunLevel1]: no need to run intra-server, subCommSize[%u], subRoot[%u]," \
     204              :             "userRank[%u]", subCommSize, subRoot, topoAttr_.userRank);
     205            0 :         return HCCL_SUCCESS;
     206              :     }
     207              : 
     208            0 :     HCCL_INFO("[Scatter][KernelRunLevel1]: start to run intra-server, subCommSize[%u], subRoot[%u]," \
     209              :         "userRank[%u]", subCommSize, subRoot, topoAttr_.userRank);
     210              : 
     211            0 :     u32 rootRankLevel1 = 0;
     212            0 :     CHK_RET(GetRankByUserRank(commLevel, commIndex, root, rootRankLevel1));
     213              : 
     214            0 :     std::unique_ptr<AlgTemplateBase> level1TempAlg;
     215            0 :     if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_NB) {
     216              :         // server间NB算法走NB
     217            0 :         level1TempAlg = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_SCATTER_NB, dispatcher_);
     218            0 :         HCCL_CONFIG_INFO(HCCL_ALG, "[%s] Run TEMPLATE_SCATTER_NB in COMM_LEVEL1", __func__);
     219            0 :     } else if (algType_.algoLevel1 == AlgTypeLevel1::ALG_LEVEL1_NHR) {
     220            0 :         level1TempAlg = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_SCATTER_NHR, dispatcher_);
     221            0 :         HCCL_CONFIG_INFO(HCCL_ALG, "[%s] Run TEMPLATE_SCATTER_NHR in COMM_LEVEL1", __func__);
     222              :     } else {
     223            0 :         level1TempAlg = AlgTemplateRegistry::Instance().GetAlgTemplate(
     224            0 :             TemplateType::TEMPLATE_SCATTER_RING, dispatcher_);
     225            0 :         HCCL_CONFIG_INFO(HCCL_ALG, "[%s] Run TEMPLATE_SCATTER_RING in COMM_LEVEL1", __func__);
     226              :     }
     227              : 
     228            0 :     CHK_SMART_PTR_NULL(level1TempAlg);
     229            0 :     CHK_RET(level1TempAlg->Prepare(inputMem, inputMem, inputMem, count * topoAttr_.userRankSize,
     230              :         dataType, stream, HCCL_REDUCE_RESERVED, rootRankLevel1, std::vector<Slice>(0))); // count是output的数据个数
     231            0 :     CHK_RET(level1TempAlg->RegisterProfiler(
     232              :         (subCommSize << PROF_RANKSIZE_OFFSET_OF_PLANEID) + subCommInfo.localRank,
     233              :         PROF_STAGE_0, HCCL_EXEC_STEP_NOT_SET, stream));
     234              : 
     235            0 :     CHK_RET(RunTemplate(level1TempAlg, subCommInfo));
     236              : 
     237            0 :     return HCCL_SUCCESS;
     238            0 : }
     239              : 
     240            0 : HcclResult CollScatterExecutor::Orchestrate(OpParam& param, AlgResourceResponse& algRes)
     241              : {
     242            0 :     HcclUs startut = TIME_NOW();
     243            0 :     tag_ = param.tag;
     244            0 :     algResResp_ = &algRes;
     245            0 :     HcclResult ret = HCCL_SUCCESS;
     246            0 :     bool needLaunchAtTheEnd = true; // 是否需要在Orchestrate()结束时launch任务
     247              :     // 图模式和单卡场景下不需要Loop
     248            0 :     ExecMem execMem;
     249            0 :     execMem.count = param.DataDes.count;
     250            0 :     execMem.inputPtr = param.inputPtr;
     251            0 :     execMem.outputPtr = param.outputPtr;
     252            0 :     if (workflowMode_ != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE) {
     253            0 :         execMem.inputMem = algRes.paramInputMem;
     254            0 :         execMem.outputMem = algRes.paramOutputMem;
     255            0 :         execMem.scratchMem = algRes.scratchMem;
     256            0 :         ret = KernelRun(param, execMem);
     257            0 :     } else if (topoAttr_.userRankSize == 1) {
     258            0 :         ret = KernelRun(param, execMem);
     259            0 :         needLaunchAtTheEnd = false;
     260              :     } else {
     261            0 :         ret = RunLoop(param, algRes);
     262            0 :         needLaunchAtTheEnd = false;
     263              :     }
     264            0 :     CHK_PRT_RET(ret != HCCL_SUCCESS,
     265              :         HCCL_ERROR("[CollScatterExecutor][Orchestrate]errNo[0x%016llx]Scatter executor kernel run failed",
     266              :             HCCL_ERROR_CODE(ret)), ret);
     267              : 
     268              :     // Enforce task launch at the end of Orchestrate
     269              :     // 注意: 不要删除这里的强制launch, 否则会导致aicpu cache功能问题
     270            0 :     if (needLaunchAtTheEnd) {
     271            0 :         HCCL_INFO("%s: enforce task launch at the end of Orchestrate", __func__);
     272            0 :         CHK_RET(LaunchTaskExtend(dispatcher_, param.stream, algResResp_->slaveStreams));
     273              :     }
     274              : 
     275            0 :     HCCL_INFO("tag[%s] Scatter executor orchestrate success, take time [%lld]us.",
     276              :         param.tag.c_str(), DURATION_US(TIME_NOW() - startut));
     277            0 :     return HCCL_SUCCESS;
     278            0 : }
     279              : 
     280              : }
        

Generated by: LCOV version 2.0-1