LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/base/alg_template/temp_reduce_scatter - reduce_scatter_plant_local_reduce_combine.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 161 0
Test Date: 2026-07-28 12:11:00 Functions: 0.0 % 17 0

            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 <cmath>
      12              : #include "alg_template_register.h"
      13              : #include "reduce_scatter_plant_local_reduce_combine.h"
      14              : 
      15              : namespace hccl {
      16              : constexpr u32 DEVICE_EIGHT = 8;
      17              : constexpr u32 FACTOR_NUM_TWO = 2;
      18            0 : ReduceScatterPlantLocalReduceCombine::ReduceScatterPlantLocalReduceCombine(const HcclDispatcher dispatcher)
      19            0 :     : AlgTemplateBase(dispatcher)
      20            0 : {}
      21              : 
      22            0 : ReduceScatterPlantLocalReduceCombine::~ReduceScatterPlantLocalReduceCombine()
      23            0 : {}
      24              : 
      25            0 : HcclResult ReduceScatterPlantLocalReduceCombine::Prepare(DeviceMem &cclInMem, DeviceMem &outputMem,
      26              :     const Stream &stream, std::vector<Stream> &subStreams, std::vector<std::shared_ptr<LocalNotify>> &meshSignal,
      27              :     std::vector<std::shared_ptr<LocalNotify>> &meshSignalAux, MemBlockInfo &memBlockInfo,
      28              :     const HcclReduceOp reductionOp, const HcclDataType dataType, bool isUseCclIn, bool isLevel0LastRank, bool isNeedSpaceBorrow)
      29              : {
      30            0 :     inputMem_ = cclInMem;             // 空拷贝 & 存放最后一块数据(Allreduce非整除场景)
      31            0 :     outputMem_ = outputMem;           // 单算子CclOut 图模式Scrach/UserOut,LocalReduce使用
      32            0 :     stream_ = stream;
      33            0 :     subStreams_ = subStreams;
      34            0 :     meshSignalPtr_ = &meshSignal;
      35            0 :     meshSignalAuxPtr_ = &meshSignalAux;
      36            0 :     memBlockInfo_ = std::move(memBlockInfo);
      37            0 :     reductionOp_ = reductionOp;
      38            0 :     dataType_ = dataType;
      39            0 :     isUseCclIn_ = isUseCclIn;//本卡在level0执行完毕后,需要告知level1数据是否存放被存放在CCLin的标识(rank维度)
      40            0 :     isLevel0LastRank_ = isLevel0LastRank;
      41            0 :     isNeedSpaceBorrow_ = isNeedSpaceBorrow;//是否需要借用CCLIN空间完成LocalReuce\alltoall(算子维度)
      42            0 :     return HCCL_SUCCESS;
      43              : }
      44              : 
      45            0 : HcclResult ReduceScatterPlantLocalReduceCombine::MainRecordSub(Stream &mainStream, u32 firstSubStreamIndex,
      46              :     u32 totalTask)
      47              : {
      48            0 :     for (u32 streamIndex = firstSubStreamIndex; streamIndex < totalTask; streamIndex++) {
      49            0 :         CHK_RET(LocalNotify::Post(mainStream, dispatcher_, (*meshSignalAuxPtr_)[streamIndex], profilerInput_.stage));
      50              :     }
      51            0 :     return HCCL_SUCCESS;
      52              : }
      53              : 
      54            0 : HcclResult ReduceScatterPlantLocalReduceCombine::SubWaitMain(u32 firstSubStreamIndex, u32 totalTask)
      55              : {
      56            0 :     for (u32 streamIndex = firstSubStreamIndex; streamIndex < totalTask; streamIndex++) {
      57            0 :         CHK_RET(LocalNotify::Wait(subStreams_[streamIndex], dispatcher_,
      58              :             (*meshSignalAuxPtr_)[streamIndex], profilerInput_.stage));
      59              :     }
      60            0 :     return HCCL_SUCCESS;
      61              : }
      62              : 
      63            0 : HcclResult ReduceScatterPlantLocalReduceCombine::MainWaitSub(Stream &mainStream, u32 firstSubStreamIndex, u32 totalTask)
      64              : {
      65            0 :     for (u32 streamIndex = firstSubStreamIndex; streamIndex < totalTask; streamIndex++) {
      66            0 :         CHK_RET(LocalNotify::Wait(mainStream, dispatcher_, (*meshSignalPtr_)[streamIndex], profilerInput_.stage));
      67              :     }
      68            0 :     return HCCL_SUCCESS;
      69              : }
      70              : 
      71            0 : HcclResult ReduceScatterPlantLocalReduceCombine::SubRecordMain(u32 firstSubStreamIndex, u32 totalTask)
      72              : {
      73            0 :     for (u32 streamIndex = firstSubStreamIndex; streamIndex < totalTask; streamIndex++) {
      74            0 :         CHK_RET(LocalNotify::Post(subStreams_[streamIndex], dispatcher_, (*meshSignalPtr_)[streamIndex],
      75              :             profilerInput_.stage));
      76              :     }
      77            0 :     return HCCL_SUCCESS;
      78              : }
      79              : 
      80            0 : u32 ReduceScatterPlantLocalReduceCombine::CalcOutputIndex(const u32 round)
      81              : {
      82            0 :     return (round + localRank_) % rankSize_;
      83              : }
      84              : 
      85            0 : bool ReduceScatterPlantLocalReduceCombine::isLastRank(const u32 rankId)
      86              : {
      87            0 :     return rankId == rankSize_ - 1;
      88              : }
      89              : 
      90            0 : bool ReduceScatterPlantLocalReduceCombine::isLastBlockData(const u32 outputIndex)
      91              : {
      92            0 :     return outputIndex == rankSize_ - 1;
      93              : }
      94              : 
      95            0 : HcclResult ReduceScatterPlantLocalReduceCombine::RunAsync(const u32 rank, const u32 rankSize,
      96              :     const std::vector<LINK> &links)
      97              : {
      98            0 :     HCCL_INFO("ReduceScatterPlantLocalReduceCombine run: rank[%u] ranksize[%u] inputMem[%p] outputMem[%p].",
      99              :         rank, rankSize, inputMem_.ptr(), outputMem_.ptr());
     100            0 :     CHK_SMART_PTR_NULL(dispatcher_);
     101            0 :     CHK_PTR_NULL(stream_.ptr());
     102            0 :     CHK_PRT_RET(links.size() < rankSize, HCCL_ERROR("[ReduceScatterPlantLocalReduceCombine][RunAsync]rank[%u] "
     103              :         "linksize[%llu] is less than rankSize[%u]", rank, links.size(), rankSize), HCCL_E_INTERNAL);
     104              :     
     105            0 :     rankSize_ = rankSize;
     106            0 :     localRank_ = rank;
     107              : 
     108            0 :     CHK_RET(AlgTemplateBase::ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
     109            0 :     CHK_RET(RunAlltoAll(links));
     110            0 :     CHK_RET(AlgTemplateBase::ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
     111              : 
     112              :     // 执行LocalReduce
     113            0 :     HcclResult ret = RunLocalReduce();
     114            0 :     CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[%s]localRank[%u] LocalReduce failed", __func__, localRank_), ret);
     115            0 :     return HCCL_SUCCESS;
     116              : }
     117              : 
     118            0 : HcclResult ReduceScatterPlantLocalReduceCombine::LocalCopy()
     119              : {
     120            0 :     u64 sliceSize = memBlockInfo_.size[localRank_];
     121            0 :     if (sliceSize == 0) {
     122            0 :         return HCCL_SUCCESS;
     123              :     }
     124              : 
     125            0 :     DeviceMem src;
     126            0 :     if (isNeedSpaceBorrow_ && isUseCclIn_) {
     127            0 :         src = inputMem_.range(memBlockInfo_.userInputOffsets[localRank_], sliceSize);
     128              :     } else {
     129            0 :         src = outputMem_.range(memBlockInfo_.inputOffsets[localRank_], sliceSize);
     130              :     }
     131              : 
     132            0 :     DeviceMem dst;
     133            0 :     u32 outputIndex = CalcOutputIndex(localRank_);
     134            0 :     if (isNeedSpaceBorrow_ && isLevel0LastRank_ && isLastBlockData(outputIndex) && !isLastRank(localRank_)) {
     135            0 :         dst = inputMem_.range(memBlockInfo_.userInputOffsets[localRank_], sliceSize);
     136              :     } else {
     137            0 :         dst = outputMem_.range(memBlockInfo_.outputOffsets[outputIndex], sliceSize);
     138              :     }
     139              : 
     140            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_));
     141            0 :     return HCCL_SUCCESS;
     142            0 : }
     143              : 
     144            0 : HcclResult ReduceScatterPlantLocalReduceCombine::RunAlltoAllRDMA(u32 round, u64 sliceSize, 
     145              :     const std::vector<LINK> &links)
     146              : {
     147            0 :     u64 srcOffset = memBlockInfo_.inputOffsets[round];
     148            0 :     void* srcPtr = static_cast<u8 *>(outputMem_.ptr()) + srcOffset;
     149            0 :     if (isNeedSpaceBorrow_ && isUseCclIn_) {
     150            0 :         srcOffset = sliceSize == 0 ? 0 : memBlockInfo_.userInputOffsets[round];
     151            0 :         srcPtr = static_cast<u8 *>(inputMem_.ptr()) + srcOffset;
     152              :     }
     153              :     
     154            0 :     u32 outputIndex = CalcOutputIndex(round);
     155            0 :     u64 dstOffset = memBlockInfo_.outputOffsets[outputIndex];
     156            0 :     if (isNeedSpaceBorrow_ && isLevel0LastRank_ && !isLastRank(round) && isLastBlockData(outputIndex)) {
     157              :         // 只有level0最后一组的最后一块数据需要放到对方的input上(且非全局最后一张卡)
     158            0 :         dstOffset = sliceSize == 0 ? 0 : memBlockInfo_.userInputOffsets[round];
     159            0 :         CHK_RET(links[round]->TxAsync(UserMemType::INPUT_MEM, dstOffset, srcPtr, sliceSize, stream_));   
     160              :     } else {
     161            0 :         CHK_RET(links[round]->TxAsync(UserMemType::OUTPUT_MEM, dstOffset, srcPtr, sliceSize, stream_));
     162              :     }
     163              : 
     164            0 :     u32 localOutputIndex = CalcOutputIndex(localRank_);
     165            0 :     u64 localDstOffset = memBlockInfo_.outputOffsets[localRank_];
     166            0 :     void* dstPtr = static_cast<u8 *>(outputMem_.ptr()) + localDstOffset;
     167            0 :     if (isNeedSpaceBorrow_ && isLevel0LastRank_ && isLastBlockData(localOutputIndex) && !isLastRank(localRank_)) {
     168            0 :         localDstOffset = memBlockInfo_.userInputOffsets[round];
     169            0 :         dstPtr = static_cast<u8 *>(inputMem_.ptr()) + localDstOffset;
     170              :     }
     171              : 
     172            0 :     u64 remoteSrcOffset = memBlockInfo_.inputOffsets[round];
     173            0 :     CHK_RET(links[round]->RxAsync(UserMemType::OUTPUT_MEM, remoteSrcOffset, dstPtr, sliceSize, stream_));
     174              :     
     175            0 :     CHK_RET(links[round]->PostFinAck(stream_));
     176            0 :     CHK_RET(links[round]->WaitFinAck(stream_));
     177            0 :     return HCCL_SUCCESS;
     178              : }
     179              : 
     180            0 : HcclResult ReduceScatterPlantLocalReduceCombine::RunAlltoAllSDMA(u32 round, u64 sliceSize, 
     181              :     const std::vector<LINK> &links)
     182              : {
     183            0 :     if (sliceSize != 0) {
     184            0 :         DeviceMem src;
     185            0 :         if (isNeedSpaceBorrow_ && isUseCclIn_) {
     186            0 :             src = inputMem_.range(memBlockInfo_.userInputOffsets[round], sliceSize);
     187              :         } else {
     188            0 :             src = outputMem_.range(memBlockInfo_.inputOffsets[round], sliceSize);
     189              :         }
     190              : 
     191            0 :         u32 outputIndex = CalcOutputIndex(round);
     192            0 :         u64 dstOffset = memBlockInfo_.outputOffsets[outputIndex];
     193            0 :         void *remMemPtr = nullptr;
     194            0 :         if (isNeedSpaceBorrow_ && isLevel0LastRank_ && !isLastRank(round) && isLastBlockData(outputIndex)) {
     195            0 :             CHK_RET(links[round]->GetRemoteMem(UserMemType::INPUT_MEM, &remMemPtr));
     196            0 :             dstOffset = memBlockInfo_.userInputOffsets[round];
     197              :         } else {
     198            0 :             CHK_RET(links[round]->GetRemoteMem(UserMemType::OUTPUT_MEM, &remMemPtr));
     199              :         }
     200            0 :         DeviceMem dst = DeviceMem::create(static_cast<u8 *>(remMemPtr) + dstOffset, sliceSize);
     201              : 
     202            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_, links[round]->GetRemoteRank(),
     203              :             links[round]->GetLinkType()));
     204            0 :     }
     205              : 
     206            0 :     CHK_RET(links[round]->TxDataSignal(stream_));
     207            0 :     CHK_RET(links[round]->RxDataSignal(stream_));
     208            0 :     return HCCL_SUCCESS;
     209              : }
     210              : 
     211            0 : HcclResult ReduceScatterPlantLocalReduceCombine::RunAlltoAll(const std::vector<LINK> &links)
     212              : {
     213            0 :     CHK_RET(LocalCopy());
     214            0 :     for (u32 round = 0; round < rankSize_; round++) {
     215            0 :         if (round == localRank_) {
     216            0 :             continue;
     217              :         }
     218            0 :         CHK_SMART_PTR_NULL(links[round]);
     219            0 :         CHK_RET(links[round]->TxAck(stream_));
     220            0 :         CHK_RET(links[round]->RxAck(stream_));
     221              : 
     222            0 :         u64 sliceSize = memBlockInfo_.size[round];
     223            0 :         if (links[round]->GetLinkType() == LinkType::LINK_ROCE) {
     224            0 :             CHK_RET(RunAlltoAllRDMA(round, sliceSize, links));
     225              :         } else {
     226            0 :             CHK_RET(RunAlltoAllSDMA(round, sliceSize, links));
     227              :         }
     228              :     }
     229            0 :     return HCCL_SUCCESS;
     230              : }
     231              : 
     232            0 : HcclResult ReduceScatterPlantLocalReduceCombine::RunLocalReduce()
     233              : {
     234            0 :     u32 reduceStep = static_cast<u32>(std::ceil(log2(rankSize_)));
     235            0 :     u64 sliceSize = memBlockInfo_.size[localRank_];
     236            0 :     u32 dataUnitSize = DataUnitSize(dataType_);
     237            0 :     if (dataUnitSize == 0) {
     238            0 :         HCCL_ERROR("[ReduceScatterPlantLocalReduceCombine][RunLocalReduce]data type[%s] out of range[%d, %d]",
     239              :                 GetDataTypeEnumStr(dataType_).c_str(), HCCL_DATA_TYPE_INT8, static_cast<int>(HCCL_DATA_TYPE_RESERVED) - 1);
     240            0 :         return HCCL_E_INTERNAL;
     241              :     }
     242            0 :     u64 count = sliceSize / dataUnitSize;
     243              : 
     244            0 :     for (u32 round = 0; round < reduceStep; round++) {
     245            0 :         u32 tailIndex = std::min(rankSize_, static_cast<u32>(1 << static_cast<int>(reduceStep - round))) - 1;
     246            0 :         u32 headIndex = static_cast<u32>(1 << static_cast<int>((reduceStep - round - 1)));
     247            0 :         u32 reduceSubStreamNum = std::min(tailIndex - headIndex, DEVICE_EIGHT / FACTOR_NUM_TWO - 1);
     248              : 
     249              :         // LR主流通知从流可以开始接受数据
     250            0 :         for (u32 offset = 0; offset < reduceSubStreamNum; offset++) {
     251            0 :             u32 streamId = offset;
     252              :             // 只有reduce任务 > 1时才需要主从流同步: LR主流通知从流, 从流Wait LR主流
     253            0 :             CHK_RET(LocalNotify::Post(stream_, dispatcher_, (*meshSignalAuxPtr_)[streamId], profilerInput_.stage));
     254            0 :             CHK_RET(LocalNotify::Wait(subStreams_[streamId], dispatcher_, (*meshSignalAuxPtr_)[streamId],
     255              :                 profilerInput_.stage));
     256              :         }
     257              : 
     258              :         // LocalReduce操作
     259            0 :         for (u32 offset = 0; offset <= tailIndex - headIndex; offset++) {   
     260            0 :             u32 inputIndex = CalcOutputIndex(headIndex + offset); // reduce的源数据offset
     261            0 :             u32 outputIndex = CalcOutputIndex(offset);            // reduce的目标offset
     262              : 
     263            0 :             u32 streamOffset = offset % (reduceSubStreamNum + 1);
     264            0 :             Stream &subStream = streamOffset == 0 ? stream_ : subStreams_[streamOffset - 1];
     265              : 
     266            0 :             if (sliceSize == 0) {
     267            0 :                 continue;
     268              :             }
     269              :             
     270              :             void *srcPtr;
     271              :             void *dstPtr;
     272            0 :             if (isNeedSpaceBorrow_ && isLevel0LastRank_ && !isLastRank(localRank_) && isLastBlockData(inputIndex)) {
     273            0 :                 srcPtr = static_cast<u8 *>(inputMem_.ptr()) + memBlockInfo_.userInputOffsets[localRank_];
     274              :             } else {
     275            0 :                 srcPtr = static_cast<u8 *>(outputMem_.ptr()) + memBlockInfo_.outputOffsets[inputIndex];
     276              :             }
     277              : 
     278            0 :             if (isNeedSpaceBorrow_ && isLevel0LastRank_ && !isLastRank(localRank_) && isLastBlockData(outputIndex)) {
     279            0 :                 dstPtr = static_cast<u8 *>(inputMem_.ptr()) + memBlockInfo_.userInputOffsets[localRank_];
     280              :             } else {
     281            0 :                 dstPtr = static_cast<u8 *>(outputMem_.ptr()) + memBlockInfo_.outputOffsets[outputIndex];
     282              :             }
     283              : 
     284            0 :             CHK_RET(HcclReduceAsync(dispatcher_, srcPtr, count, dataType_, reductionOp_, subStream, dstPtr,
     285              :                 INVALID_VALUE_RANKID, LinkType::LINK_ONCHIP, INLINE_REDUCE_BIT));
     286              :         }
     287              : 
     288              :         // 从流通知LR主流可以开始下一轮
     289            0 :         for (u32 offset = 0; offset < reduceSubStreamNum; offset++) {
     290            0 :             u32 streamId = offset;
     291              :             // 只有reduce任务 > 1时才需要主从流同步: LR主流通知从流, 从流Wait LR主流
     292            0 :             CHK_RET(LocalNotify::Post(subStreams_[streamId], dispatcher_, (*meshSignalPtr_)[streamId],
     293              :                 profilerInput_.stage));
     294            0 :             CHK_RET(LocalNotify::Wait(stream_, dispatcher_, (*meshSignalPtr_)[streamId],
     295              :                 profilerInput_.stage));
     296              :         }
     297              : 
     298            0 :         CHK_RET(AlgTemplateBase::ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
     299              :     }
     300              : 
     301            0 :     return HCCL_SUCCESS;
     302              : }
     303              : REGISTER_TEMPLATE(TemplateType::TEMPLATE_REDUCESCATTER_PLANT_LOCAL_REDUCE_COMBINE, 
     304              :     ReduceScatterPlantLocalReduceCombine);
     305              : } // namespace hccl
        

Generated by: LCOV version 2.0-1