LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/base/alg_template/temp_reduce_scatter - reduce_scatter_nhr_v1.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 152 0
Test Date: 2026-08-18 17:47:01 Functions: 0.0 % 13 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 "reduce_scatter_nhr_v1.h"
      12              : #include "alg_template_register.h"
      13              : 
      14              : namespace hccl {
      15              : 
      16            0 : ReduceScatterNHRV1::ReduceScatterNHRV1(const HcclDispatcher dispatcher) : NHRV1Base(dispatcher) {}
      17              : 
      18            0 : ReduceScatterNHRV1::~ReduceScatterNHRV1() {}
      19              : 
      20            0 : HcclResult ReduceScatterNHRV1::Prepare(u64 reduceAttrBitMap, HcomCollOpInfo* opInfo)
      21              : {
      22              :     (void)opInfo;
      23            0 :     reduceAttr_ = reduceAttrBitMap;
      24            0 :     return HCCL_SUCCESS;
      25              : }
      26              : 
      27            0 : HcclResult ReduceScatterNHRV1::RunAsync(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
      28              : {
      29              :     // 基本的检查
      30            0 :     CHK_RET(SimpleCheck(rank, rankSize, links));
      31            0 :     HCCL_INFO(
      32              :         "ReduceScatterNHRV1 run: rank[%u] ranksize[%u] inputMem[%p] outputMem[%p] count[%llu]", rank, rankSize,
      33              :         inputMem_.ptr(), outputMem_.ptr(), count_);
      34              : 
      35              :     // 判断rank_size == 1
      36            0 :     if (rankSize == 1) {
      37            0 :         if (inputMem_ != outputMem_) {
      38            0 :             return HcclD2DMemcpyAsync(dispatcher_, outputMem_, inputMem_, stream_);
      39              :         }
      40            0 :         return HCCL_SUCCESS;
      41              :     }
      42              : 
      43              :     // 处理和检查Slices
      44            0 :     if (slices_.size() == 0) {
      45            0 :         CHK_RET(SetDefaultSlices(rank, rankSize));
      46              :     }
      47            0 :     CHK_RET(CheckSlices(rankSize));
      48              : 
      49              :     // 获取通信关系
      50            0 :     RingInfo info = GetRingInfo(rankSize);
      51              : 
      52              :     // 垂直方向做Ring
      53            0 :     CHK_RET(RunReduceScatterOnVertical(rank, links, info));
      54              : 
      55              :     // 水平方向做Ring
      56            0 :     CHK_RET(RunReduceScatterOnHorizontal(rank, links, info));
      57              : 
      58              :     // 额外的搬运(从(x,sqrt-1)搬运到(x,sqrt))
      59              :     /* 一个可能的优化点:
      60              :     以8节点为例:    0   1   2
      61              :                     3   4   5
      62              :                     6   7
      63              :     当前的做法是:{0,1}、{3,4}、{6、7}做水平Ring,0/3/6/7拿到各自的那份结果,1拿到1和2的结果,4拿到4和5的结果,
      64              :                  最后1把2的结果发给2,4把5的结果发给5
      65              :     一种可能的更优做法是:以ReduceOp=Sum为例,首先把2和5的数据都置为0,
      66              :                         然后直接{0,1,2}、{3,4,5}、{6,7}做水平Ring,避免不等分Ring和额外的拷贝步骤,但需要调用TBE-asign
      67              :     */
      68            0 :     CHK_RET(RunLastCopyStep(rank, links, info));
      69              : 
      70              :     // 搬运数据到OutputMem
      71            0 :     CHK_RET(RunCopyDataToOutputMem(rank));
      72              : 
      73            0 :     HCCL_INFO("ReduceScatterNHRV1 finished: rank[%u] end", rank);
      74            0 :     return HCCL_SUCCESS;
      75            0 : }
      76              : 
      77            0 : HcclResult ReduceScatterNHRV1::SimpleCheck(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
      78              : {
      79              :     // 判断stream, dispatcher是否为空
      80            0 :     CHK_SMART_PTR_NULL(dispatcher_);
      81            0 :     CHK_PTR_NULL(stream_.ptr());
      82              : 
      83              :     // 检查memory
      84            0 :     CHK_PRT_RET(
      85              :         !outputMem_ || !inputMem_, HCCL_ERROR("[ReduceScatterNHRV1]rank[%u] inputmem or outputmem is null", rank),
      86              :         HCCL_E_PTR);
      87              : 
      88              :     // 判断links数量是否正确
      89            0 :     CHK_PRT_RET(
      90              :         links.size() < rankSize,
      91              :         HCCL_ERROR(
      92              :             "[ReduceScatterNHRV1]rank[%u] link size[%llu] is less than "
      93              :             "rank size[%u]",
      94              :             rank, links.size(), rankSize),
      95              :         HCCL_E_INTERNAL);
      96            0 :     return HCCL_SUCCESS;
      97              : }
      98              : 
      99            0 : HcclResult ReduceScatterNHRV1::SetDefaultSlices(const u32 rank, const u32 rankSize)
     100              : {
     101            0 :     u32 unitSize = DataUnitSize(dataType_);
     102            0 :     CHK_PRT_RET(
     103              :         unitSize == 0, HCCL_ERROR("[ReduceScatterNHRV1]rank[%u] unit data size is zero", rank), HCCL_E_INTERNAL);
     104              : 
     105            0 :     slices_.resize(rankSize);
     106            0 :     u64 sliceSize = count_ * unitSize;
     107            0 :     for (u32 i = 0; i < rankSize; i++) {
     108            0 :         slices_[i].size = sliceSize;
     109            0 :         slices_[i].offset = (i * sliceSize);
     110            0 :         HCCL_DEBUG(
     111              :             "rank[%u], slices[%u].offset=[%llu], slices[%u].size=[%llu] ", rank, i, slices_[i].offset, i,
     112              :             slices_[i].size);
     113              :     }
     114            0 :     return HCCL_SUCCESS;
     115              : }
     116              : 
     117            0 : HcclResult ReduceScatterNHRV1::CheckSlices(const u32 rankSize)
     118              : {
     119            0 :     CHK_PRT_RET(
     120              :         slices_.size() != rankSize,
     121              :         HCCL_ERROR("[ReduceScatterNHRV1]slices.size[%u] should be equal to rankSize[%u]", slices_.size(), rankSize),
     122              :         HCCL_E_INTERNAL);
     123              : 
     124            0 :     for (u32 idx = 1; idx < slices_.size(); idx++) {
     125            0 :         CHK_PRT_RET(
     126              :             slices_[idx - 1].offset + slices_[idx - 1].size != slices_[idx].offset,
     127              :             HCCL_ERROR(
     128              :                 "[ReduceScatterNHRV1]only support continuous slices, but get "
     129              :                 "slices[%u].offset[%u], slices[%u].size[%u], slices[%u].offset[%u]",
     130              :                 idx - 1, slices_[idx - 1].offset, idx - 1, slices_[idx - 1].size, idx, slices_[idx].offset),
     131              :             HCCL_E_INTERNAL);
     132              :     }
     133            0 :     return HCCL_SUCCESS;
     134              : }
     135              : 
     136            0 : HcclResult ReduceScatterNHRV1::RunReduceScatterBrokenRing(
     137              :     const u32 rank, const std::vector<LINK>& links, const std::vector<Slice>& slices)
     138              : {
     139              :     std::unique_ptr<AlgTemplateBase> tempAlg
     140            0 :         = AlgTemplateRegistry::Instance().GetAlgTemplate(TemplateType::TEMPLATE_REDUCESCATTER_RING, dispatcher_);
     141            0 :     CHK_SMART_PTR_NULL(tempAlg);
     142            0 :     CHK_RET(tempAlg->Prepare(reduceAttr_));
     143              : 
     144            0 :     if (!barrierSwitchOn_) {
     145            0 :         tempAlg->CloseBarrier();
     146              :     }
     147              : 
     148            0 :     CHK_RET(
     149              :         tempAlg->Prepare(inputMem_, inputMem_, scratchMem_, count_, dataType_, stream_, reductionOp_, root_, slices));
     150              : 
     151            0 :     CHK_RET(tempAlg->RegisterProfiler(profilerInput_.planeID, profilerInput_.stage, profilerInput_.step, stream_));
     152              : 
     153            0 :     return tempAlg->RunAsync(rank, links.size(), links);
     154            0 : }
     155              : 
     156              : HcclResult
     157            0 : ReduceScatterNHRV1::RunReduceScatterOnVertical(const u32 rank, const std::vector<LINK>& links, const RingInfo& info)
     158              : {
     159            0 :     u32 hIndex = info.GetHIndex(rank); // 查找自己位于第几列
     160              : 
     161              :     // 构造新的links和slices
     162            0 :     std::vector<LINK> subLinks;
     163            0 :     std::vector<Slice> subSlices;
     164            0 :     u32 sliceIndexOffset = 0;                                                         // slice数量的累计偏移
     165            0 :     u32 hIndexForRing = (hIndex < info.GetRowSize()) ? hIndex : info.GetVIndex(rank); // 属于第几个垂直Ring
     166            0 :     u32 vSizeForRing = info.GetVSizeByHIndex(hIndexForRing);                          // 所属垂直Ring的大小
     167            0 :     for (u32 vIdx = 0; vIdx < vSizeForRing; vIdx++) {                                 // 处理垂直方向上的Rank
     168              :         // 增加link
     169            0 :         u32 rankInRing = info.GetRank(vIdx, hIndexForRing);
     170            0 :         CHK_PRT_RET(
     171              :             rankInRing >= links.size(),
     172              :             HCCL_ERROR(
     173              :                 "[ReduceScatterNHRV1][Vertical] rank[%u] out of range, "
     174              :                 "rankInRing=%u, links.size=%u",
     175              :                 rank, rankInRing, links.size()),
     176              :             HCCL_E_INTERNAL);
     177            0 :         HCCL_DEBUG("[ReduceScatterNHRV1][Vertical] rank[%u] links[%u]=%u", rank, vIdx, rankInRing);
     178            0 :         subLinks.push_back(links[rankInRing]);
     179              : 
     180              :         // 寻找要合并的slice
     181            0 :         u32 nSlices = info.GetHSizeByVIndex(vIdx);
     182            0 :         Slice& headSlice = slices_[sliceIndexOffset];
     183            0 :         Slice& tailSlice = slices_[sliceIndexOffset + nSlices - 1];
     184              : 
     185              :         // 增加slice
     186            0 :         Slice slice;
     187            0 :         slice.offset = headSlice.offset;
     188            0 :         slice.size = tailSlice.offset + tailSlice.size - headSlice.offset;
     189            0 :         HCCL_DEBUG(
     190              :             "[ReduceScatterNHRV1][Vertical] rank[%u] subSlices[%u].offset=%llu, subSlices[%u].size=%llu", rank, vIdx,
     191              :             slice.offset, vIdx, slice.size);
     192            0 :         subSlices.push_back(slice);
     193              : 
     194              :         // 更新偏移
     195            0 :         sliceIndexOffset += nSlices;
     196              :     }
     197              : 
     198              :     // -- 可能还涉及跳跃的一个链接,比如8节点
     199              :     // ---- 0   1   2
     200              :     // ---- 3   4   5
     201              :     // ---- 6   7
     202              :     // -- 两个垂直Ring分别是{0,3,6,2}和{1,4,7,5},而不是{0,3,6}和{1,4,7}
     203            0 :     if (info.GetHSizeByVIndex(hIndexForRing) > info.GetRowSize()) {
     204              :         // 添加link
     205            0 :         u32 rankInRing = info.GetRank(hIndexForRing, info.GetRowSize());
     206            0 :         CHK_PRT_RET(
     207              :             rankInRing >= links.size(),
     208              :             HCCL_ERROR(
     209              :                 "[ReduceScatterNHRV1][Vertical] rank[%u] out of range, "
     210              :                 "rankInRing=%u, links.size=%u",
     211              :                 rank, rankInRing, links.size()),
     212              :             HCCL_E_INTERNAL);
     213            0 :         HCCL_DEBUG("[ReduceScatterNHRV1][Vertical] rank[%u] links[%u]=%u", rank, subLinks.size(), rankInRing);
     214            0 :         subLinks.push_back(links[rankInRing]);
     215              : 
     216              :         // 添加slice
     217            0 :         Slice slice;
     218            0 :         slice.offset = 0;
     219            0 :         slice.size = 0;
     220            0 :         HCCL_DEBUG(
     221              :             "[ReduceScatterNHRV1][Vertical] rank[%u] subSlices[%u].offset=%llu, subSlices[%u].size=%llu", rank,
     222              :             subLinks.size(), slice.offset, subLinks.size(), slice.size);
     223            0 :         subSlices.push_back(slice);
     224              :     }
     225              : 
     226              :     // 长度不足2,直接跳过
     227            0 :     if (subLinks.size() < 2) {
     228            0 :         return HCCL_SUCCESS;
     229              :     }
     230              : 
     231              :     // 计算在垂直Ring中的rank号
     232            0 :     u32 subRank = (hIndex == hIndexForRing) ? info.GetVIndex(rank) : vSizeForRing;
     233            0 :     HCCL_DEBUG("[ReduceScatterNHRV1][Vertical] rank[%u] subRank=%u", rank, subRank);
     234              : 
     235              :     // 执行Broken Ring ReduceScatter
     236            0 :     return RunReduceScatterBrokenRing(subRank, subLinks, subSlices);
     237            0 : }
     238              : 
     239              : HcclResult
     240            0 : ReduceScatterNHRV1::RunReduceScatterOnHorizontal(const u32 rank, const std::vector<LINK>& links, const RingInfo& info)
     241              : {
     242            0 :     u32 hIndex = info.GetHIndex(rank);
     243            0 :     if (hIndex >= info.GetRowSize()) {
     244            0 :         return HCCL_SUCCESS;
     245              :     }
     246              : 
     247              :     // 构造新的links和slices
     248            0 :     u32 vIndex = info.GetVIndex(rank);
     249            0 :     std::vector<LINK> subLinks;
     250            0 :     std::vector<Slice> subSlices;
     251            0 :     for (u32 hIdx = 0; hIdx < info.GetRowSize(); hIdx++) {
     252              :         // 增加link
     253            0 :         u32 rankInRing = info.GetRank(vIndex, hIdx);
     254            0 :         CHK_PRT_RET(
     255              :             rankInRing >= links.size(),
     256              :             HCCL_ERROR(
     257              :                 "[ReduceScatterNHRV1][Horizontal] rank[%u] out of range, "
     258              :                 "rankInRing=%u, links.size=%u",
     259              :                 rank, rankInRing, links.size()),
     260              :             HCCL_E_INTERNAL);
     261            0 :         HCCL_DEBUG("[ReduceScatterNHRV1][Horizontal] rank[%u] links[%u]=%u", rank, hIdx, rankInRing);
     262            0 :         subLinks.push_back(links[rankInRing]);
     263              : 
     264              :         // 增肌slice(CheckSlices()已经约束slices_里的Slice都是连续的)
     265              :         // -- 比如8节点在做完水平Ring后
     266              :         // ---- 0   1   2
     267              :         // ---- 3   4   5
     268              :         // ---- 6   7
     269              :         // -- 0/3/6/7节点只拿到自己那份ReduceScatter结果,而1拿到1和2的两份数据、4拿到4和5的两份数据
     270            0 :         u64 sliceSize = slices_[rankInRing].size;
     271            0 :         if (hIdx == info.GetRowSize() - 1 && info.GetHSizeByVIndex(vIndex) > info.GetRowSize()) {
     272            0 :             sliceSize += slices_[rankInRing + 1].size;
     273              :         }
     274              : 
     275            0 :         Slice slice;
     276            0 :         slice.offset = slices_[rankInRing].offset;
     277            0 :         slice.size = sliceSize;
     278            0 :         HCCL_DEBUG(
     279              :             "[ReduceScatterNHRV1][Horizontal] rank[%u] subSlices[%u].offset=%llu, subSlices[%u].size=%llu", rank, hIdx,
     280              :             slice.offset, hIdx, slice.size);
     281            0 :         subSlices.push_back(slice);
     282              :     }
     283              : 
     284              :     // 长度不足2,直接跳过
     285            0 :     if (subLinks.size() < 2) {
     286            0 :         return HCCL_SUCCESS;
     287              :     }
     288              : 
     289              :     // 计算在水平Ring中的rank号
     290            0 :     u32 subRank = hIndex;
     291            0 :     HCCL_DEBUG("[ReduceScatterNHRV1][Horizontal] rank[%u] subRank=%u", rank, subRank);
     292              : 
     293              :     // 执行Broken Ring ReduceScatter
     294            0 :     return RunReduceScatterBrokenRing(subRank, subLinks, subSlices);
     295            0 : }
     296              : 
     297            0 : HcclResult ReduceScatterNHRV1::RunLastCopyStep(const u32 rank, const std::vector<LINK>& links, const RingInfo& info)
     298              : {
     299              :     HcclResult ret;
     300              : 
     301            0 :     u32 hIndex = info.GetHIndex(rank); // 查找自己位于第几列
     302            0 :     u32 vIndex = info.GetVIndex(rank); // 查找自己位于第几行
     303            0 :     if (hIndex >= info.GetRowSize() - 1 && info.GetHSizeByVIndex(vIndex) > info.GetRowSize()) {
     304            0 :         u32 peerRank = (hIndex == info.GetRowSize() - 1) ? rank + 1 : rank - 1;
     305              : 
     306              :         // 检查指针
     307            0 :         CHK_SMART_PTR_NULL(links[peerRank]);
     308              : 
     309              :         // TxAck
     310            0 :         ret = links[peerRank]->TxAck(stream_);
     311            0 :         CHK_PRT_RET(
     312              :             ret != HCCL_SUCCESS,
     313              :             HCCL_ERROR("[ReduceScatterNHRV1][RunLastCopyStep]rank[%u] tx ack from peerank[%u] failed", rank, peerRank),
     314              :             ret);
     315              : 
     316              :         // RxAck
     317            0 :         ret = links[peerRank]->RxAck(stream_);
     318            0 :         CHK_PRT_RET(
     319              :             ret != HCCL_SUCCESS,
     320              :             HCCL_ERROR("[ReduceScatterNHRV1][RunLastCopyStep]rank[%u] rx ack from peerank[%u] failed", rank, peerRank),
     321              :             ret);
     322              : 
     323            0 :         if (hIndex == info.GetRowSize() - 1) { // 发数据
     324            0 :             Slice& txSlice = slices_[peerRank];
     325            0 :             DeviceMem srcMem = inputMem_.range(txSlice.offset, txSlice.size);
     326            0 :             HCCL_DEBUG("tx srcMem[%p] range[%llu] size[%llu] ", srcMem.ptr(), txSlice.offset, txSlice.size);
     327            0 :             CHK_RET(ExecuteTxSync(
     328              :                 links[peerRank], UserMemType::INPUT_MEM, txSlice.offset + baseOffset_, srcMem.ptr(), srcMem.size(),
     329              :                 stream_));
     330              : 
     331            0 :             ret = links[peerRank]->TxWaitDone(stream_);
     332            0 :             CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[ReduceScatterNHRV1][RunLastCopyStep]TxWaitDone failed"), ret);
     333            0 :         } else { // 收数据
     334            0 :             Slice& rxSlice = slices_[rank];
     335            0 :             DeviceMem dstMem = inputMem_.range(rxSlice.offset, rxSlice.size);
     336            0 :             HCCL_DEBUG("rx dstMem[%p] range[%llu], size[%llu] ", dstMem.ptr(), rxSlice.offset, rxSlice.size);
     337            0 :             CHK_RET(ExecuteRxSync(
     338              :                 links[peerRank], UserMemType::INPUT_MEM, rxSlice.offset + baseOffset_, dstMem.ptr(), dstMem.size(),
     339              :                 stream_));
     340              : 
     341            0 :             ret = links[peerRank]->RxWaitDone(stream_);
     342            0 :             CHK_PRT_RET(ret != HCCL_SUCCESS, HCCL_ERROR("[ReduceScatterNHRV1][RunLastCopyStep]RxWaitDone failed"), ret);
     343            0 :         }
     344              : 
     345              :         // 如果不Barrier,SDMA结果在数据量超过CCL Buffer之后结果不正确
     346            0 :         CHK_RET(ExecuteBarrier(links[peerRank], stream_));
     347              :     }
     348            0 :     return HCCL_SUCCESS;
     349              : }
     350              : 
     351            0 : HcclResult ReduceScatterNHRV1::RunCopyDataToOutputMem(const u32 rank)
     352              : {
     353            0 :     if (inputMem_ != outputMem_) {
     354            0 :         Slice& srcSlice = slices_[rank];
     355            0 :         DeviceMem dst = outputMem_.range(0, srcSlice.size);
     356            0 :         DeviceMem src = inputMem_.range(srcSlice.offset, srcSlice.size);
     357            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_));
     358            0 :     }
     359            0 :     return HCCL_SUCCESS;
     360              : }
     361              : REGISTER_TEMPLATE(TemplateType::TEMPLATE_REDUCESCATTER_NHR_V1, ReduceScatterNHRV1);
     362              : } // namespace hccl
        

Generated by: LCOV version 2.0-1