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 % 158 0
Test Date: 2026-08-18 17:47:01 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) { return (round + localRank_) % rankSize_; }
      81              : 
      82            0 : bool ReduceScatterPlantLocalReduceCombine::isLastRank(const u32 rankId) { return rankId == rankSize_ - 1; }
      83              : 
      84            0 : bool ReduceScatterPlantLocalReduceCombine::isLastBlockData(const u32 outputIndex)
      85              : {
      86            0 :     return outputIndex == rankSize_ - 1;
      87              : }
      88              : 
      89              : HcclResult
      90            0 : ReduceScatterPlantLocalReduceCombine::RunAsync(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
      91              : {
      92            0 :     HCCL_INFO(
      93              :         "ReduceScatterPlantLocalReduceCombine run: rank[%u] ranksize[%u] inputMem[%p] outputMem[%p].", rank, rankSize,
      94              :         inputMem_.ptr(), outputMem_.ptr());
      95            0 :     CHK_SMART_PTR_NULL(dispatcher_);
      96            0 :     CHK_PTR_NULL(stream_.ptr());
      97            0 :     CHK_PRT_RET(
      98              :         links.size() < rankSize,
      99              :         HCCL_ERROR(
     100              :             "[ReduceScatterPlantLocalReduceCombine][RunAsync]rank[%u] "
     101              :             "linksize[%llu] is less than rankSize[%u]",
     102              :             rank, links.size(), rankSize),
     103              :         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              : HcclResult
     145            0 : ReduceScatterPlantLocalReduceCombine::RunAlltoAllRDMA(u32 round, u64 sliceSize, 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              : HcclResult
     181            0 : ReduceScatterPlantLocalReduceCombine::RunAlltoAllSDMA(u32 round, u64 sliceSize, 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(
     203              :             dispatcher_, dst, src, stream_, links[round]->GetRemoteRank(), 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(
     239              :             "[ReduceScatterPlantLocalReduceCombine][RunLocalReduce]data type[%s] out of range[%d, %d]",
     240              :             GetDataTypeEnumStr(dataType_).c_str(), HCCL_DATA_TYPE_INT8, static_cast<int>(HCCL_DATA_TYPE_RESERVED) - 1);
     241            0 :         return HCCL_E_INTERNAL;
     242              :     }
     243            0 :     u64 count = sliceSize / dataUnitSize;
     244              : 
     245            0 :     for (u32 round = 0; round < reduceStep; round++) {
     246            0 :         u32 tailIndex = std::min(rankSize_, static_cast<u32>(1 << static_cast<int>(reduceStep - round))) - 1;
     247            0 :         u32 headIndex = static_cast<u32>(1 << static_cast<int>((reduceStep - round - 1)));
     248            0 :         u32 reduceSubStreamNum = std::min(tailIndex - headIndex, DEVICE_EIGHT / FACTOR_NUM_TWO - 1);
     249              : 
     250              :         // LR主流通知从流可以开始接受数据
     251            0 :         for (u32 offset = 0; offset < reduceSubStreamNum; offset++) {
     252            0 :             u32 streamId = offset;
     253              :             // 只有reduce任务 > 1时才需要主从流同步: LR主流通知从流, 从流Wait LR主流
     254            0 :             CHK_RET(LocalNotify::Post(stream_, dispatcher_, (*meshSignalAuxPtr_)[streamId], profilerInput_.stage));
     255            0 :             CHK_RET(LocalNotify::Wait(
     256              :                 subStreams_[streamId], dispatcher_, (*meshSignalAuxPtr_)[streamId], profilerInput_.stage));
     257              :         }
     258              : 
     259              :         // LocalReduce操作
     260            0 :         for (u32 offset = 0; offset <= tailIndex - headIndex; offset++) {
     261            0 :             u32 inputIndex = CalcOutputIndex(headIndex + offset); // reduce的源数据offset
     262            0 :             u32 outputIndex = CalcOutputIndex(offset);            // reduce的目标offset
     263              : 
     264            0 :             u32 streamOffset = offset % (reduceSubStreamNum + 1);
     265            0 :             Stream& subStream = streamOffset == 0 ? stream_ : subStreams_[streamOffset - 1];
     266              : 
     267            0 :             if (sliceSize == 0) {
     268            0 :                 continue;
     269              :             }
     270              : 
     271              :             void* srcPtr;
     272              :             void* dstPtr;
     273            0 :             if (isNeedSpaceBorrow_ && isLevel0LastRank_ && !isLastRank(localRank_) && isLastBlockData(inputIndex)) {
     274            0 :                 srcPtr = static_cast<u8*>(inputMem_.ptr()) + memBlockInfo_.userInputOffsets[localRank_];
     275              :             } else {
     276            0 :                 srcPtr = static_cast<u8*>(outputMem_.ptr()) + memBlockInfo_.outputOffsets[inputIndex];
     277              :             }
     278              : 
     279            0 :             if (isNeedSpaceBorrow_ && isLevel0LastRank_ && !isLastRank(localRank_) && isLastBlockData(outputIndex)) {
     280            0 :                 dstPtr = static_cast<u8*>(inputMem_.ptr()) + memBlockInfo_.userInputOffsets[localRank_];
     281              :             } else {
     282            0 :                 dstPtr = static_cast<u8*>(outputMem_.ptr()) + memBlockInfo_.outputOffsets[outputIndex];
     283              :             }
     284              : 
     285            0 :             CHK_RET(HcclReduceAsync(
     286              :                 dispatcher_, srcPtr, count, dataType_, reductionOp_, subStream, dstPtr, INVALID_VALUE_RANKID,
     287              :                 LinkType::LINK_ONCHIP, INLINE_REDUCE_BIT));
     288              :         }
     289              : 
     290              :         // 从流通知LR主流可以开始下一轮
     291            0 :         for (u32 offset = 0; offset < reduceSubStreamNum; offset++) {
     292            0 :             u32 streamId = offset;
     293              :             // 只有reduce任务 > 1时才需要主从流同步: LR主流通知从流, 从流Wait LR主流
     294            0 :             CHK_RET(LocalNotify::Post(
     295              :                 subStreams_[streamId], dispatcher_, (*meshSignalPtr_)[streamId], profilerInput_.stage));
     296            0 :             CHK_RET(LocalNotify::Wait(stream_, dispatcher_, (*meshSignalPtr_)[streamId], profilerInput_.stage));
     297              :         }
     298              : 
     299            0 :         CHK_RET(AlgTemplateBase::ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
     300              :     }
     301              : 
     302            0 :     return HCCL_SUCCESS;
     303              : }
     304              : REGISTER_TEMPLATE(
     305              :     TemplateType::TEMPLATE_REDUCESCATTER_PLANT_LOCAL_REDUCE_COMBINE, ReduceScatterPlantLocalReduceCombine);
     306              : } // namespace hccl
        

Generated by: LCOV version 2.0-1