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

Generated by: LCOV version 2.0-1