LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/base/alg_template/temp_scatter - scatter_ring_direct.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 114 0
Test Date: 2026-08-18 17:47:01 Functions: 0.0 % 12 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 "scatter_ring_direct.h"
      12              : #include "alg_template_register.h"
      13              : 
      14              : namespace hccl {
      15            0 : ScatterRingDirect::ScatterRingDirect(const HcclDispatcher dispatcher) : AlgTemplateBase(dispatcher) {}
      16              : 
      17            0 : ScatterRingDirect::~ScatterRingDirect() {}
      18              : 
      19            0 : HcclResult ScatterRingDirect::Prepare(
      20              :     HcomCollOpInfo* opInfo, const u32 userRank, const std::vector<u32>& ringsOrders,
      21              :     const std::vector<Slice>& userMemInputSlices)
      22              : {
      23            0 :     opInfo_ = opInfo;
      24            0 :     userRank_ = userRank;
      25            0 :     ringsOrder_ = ringsOrders;
      26            0 :     userMemInputSlices_ = userMemInputSlices;
      27            0 :     return HCCL_SUCCESS;
      28              : }
      29              : 
      30              : // reduce scatter ring direct算法的函数入口
      31            0 : HcclResult ScatterRingDirect::RunAsync(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
      32              : {
      33              :     // 基本的检查
      34            0 :     CHK_RET(CheckParameters(rank, rankSize, links));
      35              : 
      36              :     // 判断rank_size == 1, 若inputMem_ != outputMem_,才需要搬运
      37            0 :     if (rankSize == 1) {
      38            0 :         CHK_RET(OneRankMemcpy());
      39            0 :         return HCCL_SUCCESS;
      40              :     }
      41              :     // 收集邻居信息
      42            0 :     CHK_RET(GetInitializedNeighborLinks(rank, rankSize, links));
      43              :     // 填充slice_
      44            0 :     CHK_RET(SetSlices(rank, rankSize));
      45              : 
      46              :     // 运行scatter, ring算法
      47            0 :     CHK_RET(RunScatter(rank, rankSize));
      48              : 
      49            0 :     if (barrierSwitchOn_) {
      50              :         // 执行barrier,保证数据收发完成
      51            0 :         CHK_RET(ExecuteBarrier(leftLink_, rightLink_));
      52              :     }
      53              : 
      54            0 :     HCCL_INFO("ScatterRingDirect finished: rank[%u]", rank);
      55            0 :     return HCCL_SUCCESS;
      56              : }
      57              : 
      58            0 : HcclResult ScatterRingDirect::CheckParameters(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
      59              : {
      60            0 :     CHK_PTR_NULL(opInfo_);
      61            0 :     CHK_RET(CheckConcurrentDirectParameters(rank, rankSize, links));
      62              :     // 判断ringsOrder数量是否正确
      63            0 :     CHK_PRT_RET(
      64              :         ringsOrder_.size() != rankSize,
      65              :         HCCL_ERROR(
      66              :             "[ScatterRingDirect] ringsOrder size[%u] is not equal to rank size[%u]", ringsOrder_.size(), rankSize),
      67              :         HCCL_E_PARA);
      68              :     // 判断userMemInputSlices数量是否正确
      69            0 :     CHK_PRT_RET(
      70              :         userMemInputSlices_.size() != rankSize,
      71              :         HCCL_ERROR(
      72              :             "[ScatterRingDirect] userMemInputSlices size[%u] is not equal to rank size[%u]", userMemInputSlices_.size(),
      73              :             rankSize),
      74              :         HCCL_E_PARA);
      75            0 :     HCCL_INFO("ScatterRingDirect CheckParameters success");
      76            0 :     return HCCL_SUCCESS;
      77              : }
      78              : 
      79            0 : HcclResult ScatterRingDirect::OneRankMemcpy()
      80              : {
      81            0 :     const Slice& srcSlice = userMemInputSlices_[0];
      82            0 :     const Slice& dstSlice = slices_[0];
      83            0 :     DeviceMem src;
      84            0 :     DeviceMem dst;
      85            0 :     if (opInfo_->inputAddr == nullptr) {
      86            0 :         src = inputMem_.range(srcSlice.offset, srcSlice.size);
      87              :     } else {
      88            0 :         src = DeviceMem::create(static_cast<u8*>(opInfo_->inputAddr) + srcSlice.offset, srcSlice.size);
      89              :     }
      90            0 :     if (opInfo_->outputAddr != nullptr) {
      91              :         // opInfo_->outputAddr != nullptr指示要将输出发送至user output
      92            0 :         u64 stepOffset = slices_[ringsOrder_[0]].offset;
      93            0 :         HCCL_DEBUG(
      94              :             "Memcpy operation: stream[main], rank[%u] starts to rcv offset[%llu], size[%llu] at userMemOut_", userRank_,
      95              :             stepOffset, dstSlice.size);
      96            0 :         dst = DeviceMem::create(static_cast<u8*>(opInfo_->outputAddr) + stepOffset, dstSlice.size);
      97              :     } else {
      98              :         // opInfo_->outputAddr == nullptr指示要将输出发送至CCL buffer
      99            0 :         HCCL_DEBUG(
     100              :             "Memcpy operation: stream[main], rank[%u] starts to rcv offset[%llu], size[%llu] at outputMem_", userRank_,
     101              :             dstSlice.offset, dstSlice.size);
     102            0 :         dst = outputMem_.range(dstSlice.offset, dstSlice.size);
     103              :     }
     104            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_));
     105            0 :     return HCCL_SUCCESS;
     106            0 : }
     107              : 
     108              : HcclResult
     109            0 : ScatterRingDirect::GetInitializedNeighborLinks(const u32 rank, const u32 rankSize, const std::vector<LINK>& links)
     110              : {
     111              :     // 收集左邻居信息
     112            0 :     leftLink_ = links[(rank + rankSize - 1) % rankSize];
     113            0 :     CHK_SMART_PTR_NULL(leftLink_);
     114              : 
     115              :     // 收集右邻居信息
     116            0 :     rightLink_ = links[(rank + 1) % rankSize];
     117            0 :     CHK_SMART_PTR_NULL(rightLink_);
     118            0 :     HCCL_INFO("ScatterRingDirect finished to GetInitializedNeighborLinks");
     119            0 :     return HCCL_SUCCESS;
     120              : }
     121              : 
     122            0 : HcclResult ScatterRingDirect::SetSlices(const u32 rank, const u32 rankSize)
     123              : {
     124            0 :     if (slices_.size() == 0) {
     125            0 :         slices_.resize(rankSize);
     126              : 
     127              :         // 生成std::vector<Slice> slices_
     128            0 :         u64 sliceSize = count_ * SIZE_TABLE[dataType_];
     129              :         ;
     130              : 
     131            0 :         for (u32 i = 0; i < rankSize; i++) {
     132            0 :             slices_[i].size = sliceSize;
     133              :             // 用于DMA消减过程中,消除src与dst不对位的风险
     134            0 :             slices_[i].offset = RoundUpWithDivisor(i * sliceSize, HCCL_MIN_SLICE_ALIGN);
     135              : 
     136            0 :             HCCL_DEBUG(
     137              :                 "rank[%u], slices[%u].offset=[%llu], slices[%u].size=[%llu]", rank, i, slices_[i].offset, i,
     138              :                 slices_[i].size);
     139              :         }
     140              :     }
     141            0 :     if (UNLIKELY(HcclCheckLogLevel(HCCL_LOG_DEBUG))) {
     142            0 :         for (u32 i = 0; i < slices_.size(); i++) {
     143            0 :             HCCL_DEBUG(
     144              :                 "[ScatterRingDirect][SetSlices]rank[%u], slices[%u].offset=[%llu], slices[%u].size=[%llu]", rank, i,
     145              :                 slices_[i].offset, i, slices_[i].size);
     146              :         }
     147              :     }
     148              :     // 最后一步搬到userMemOut_的offset, 不同的ring环offset不一样
     149            0 :     lastStepOffset_ = slices_[ringsOrder_[0]].offset;
     150            0 :     HCCL_INFO("ScatterRingDirect finished to SetSlices");
     151            0 :     return HCCL_SUCCESS;
     152              : }
     153              : 
     154            0 : HcclResult ScatterRingDirect::RunScatter(const u32 rank, const u32 rankSize)
     155              : {
     156            0 :     HCCL_INFO("ScatterRingDirect starts, the input param rank[%u]", rank);
     157              :     // 空拷贝用于后续操作附着
     158            0 :     CHK_RET(ExecEmptyTask(inputMem_, outputMem_, stream_, dispatcher_));
     159              :     // 例如rank[0,1,2,3]中,rank0的rxSliceIdx = 2,txSliceIdx = 3, subSliceIdx = 1
     160            0 :     u32 txSliceIdx = (rank + rankSize - 1) % rankSize;
     161            0 :     u32 rxSliceIdx = (rank + rankSize - DMA_REDUCE_TWO_OFFSET) % rankSize;
     162            0 :     u32 subSliceIdx = (rank + rankSize - DMA_REDUCE_TWO_OFFSET) % rankSize; // 只存在于根节点
     163            0 :     u32 stepsFromRank2Root = (rank + rankSize - root_) % rankSize;
     164            0 :     for (u32 step = 0; step < rankSize - 1; step++) {
     165            0 :         const Slice& subSlice = userMemInputSlices_[subSliceIdx];
     166            0 :         const Slice& cclSlice = slices_[subSliceIdx];
     167            0 :         const Slice& txSlice = slices_[txSliceIdx];
     168            0 :         const Slice& rxSlice = slices_[rxSliceIdx];
     169              : 
     170            0 :         CHK_RET(RunScatterOnRootRank(step, subSlice, cclSlice, rank, rankSize));
     171            0 :         CHK_RET(RunScatterOnOtherRank(stepsFromRank2Root, step, txSlice, rxSlice, rankSize));
     172              : 
     173              :         // 更新索引
     174            0 :         subSliceIdx = (subSliceIdx + rankSize - 1) % rankSize;
     175            0 :         txSliceIdx = (txSliceIdx + rankSize - 1) % rankSize;
     176            0 :         rxSliceIdx = (rxSliceIdx + rankSize - 1) % rankSize;
     177              :     }
     178            0 :     HCCL_INFO("ScatterRingDirect finished to RunScatter");
     179            0 :     return HCCL_SUCCESS;
     180              : }
     181              : 
     182            0 : HcclResult ScatterRingDirect::RunScatterOnOtherRank(
     183              :     const u32 stepsFromRank2Root, const u32 step, const Slice& txSlice, const Slice& rxSlice, const u32 rankSize)
     184              : {
     185            0 :     bool needSend = stepsFromRank2Root <= step;
     186            0 :     bool needReceive = stepsFromRank2Root > 0 && stepsFromRank2Root <= (step + 1);
     187              :     // Ack
     188            0 :     if (needReceive) {
     189            0 :         CHK_RET(leftLink_->TxAck(stream_));
     190              :     }
     191            0 :     if (needSend) {
     192            0 :         CHK_RET(rightLink_->RxAck(stream_));
     193              :     }
     194              : 
     195            0 :     DeviceMem src;
     196              :     // 不同的rank会在不同的step开始持续发送操作,距离root节点越近,越早step开始发送操作
     197            0 :     if (needSend) {
     198            0 :         src = inputMem_.range(txSlice.offset, txSlice.size);
     199            0 :         CHK_RET(rightLink_->TxAsync(
     200              :             UserMemType::INPUT_MEM, txSlice.offset + baseOffset_, src.ptr(), txSlice.size, stream_));
     201              :     }
     202              :     // 不同的rank会在不同的step开始持续发送操作,距离root节点越近,越早step开始发送操作
     203            0 :     DeviceMem dst;
     204            0 :     if (needReceive) {
     205            0 :         HCCL_DEBUG(
     206              :             "MemcpyAsync operation: step[%u] stream[main], src rank[%u] starts to send offset[%llu] size[%llu] "
     207              :             "from leftMem_",
     208              :             step, leftLink_->GetRemoteRank(), rxSlice.offset, rxSlice.size);
     209            0 :         if (step == rankSize - DMA_REDUCE_TWO_OFFSET && opInfo_->outputAddr != nullptr) {
     210            0 :             HCCL_DEBUG(
     211              :                 "MemcpyAsync operation: step[%u] stream[main], dst rank[%u] starts to rcv offset[%llu], "
     212              :                 "size[%llu] "
     213              :                 "at userMemOut_",
     214              :                 step, userRank_, lastStepOffset_, rxSlice.size);
     215            0 :             dst = DeviceMem::create(static_cast<u8*>(opInfo_->outputAddr) + lastStepOffset_, rxSlice.size);
     216              :         } else {
     217            0 :             HCCL_DEBUG(
     218              :                 "MemcpyAsync operation: step[%u] stream[main], dst rank[%u] starts to rcv offset[%llu], "
     219              :                 "size[%llu] "
     220              :                 "at inputMem_",
     221              :                 step, userRank_, rxSlice.offset, rxSlice.size);
     222            0 :             dst = inputMem_.range(rxSlice.offset, rxSlice.size);
     223              :         }
     224            0 :         CHK_RET(
     225              :             leftLink_->RxAsync(UserMemType::INPUT_MEM, rxSlice.offset + baseOffset_, dst.ptr(), rxSlice.size, stream_));
     226              :     }
     227            0 :     return HCCL_SUCCESS;
     228            0 : }
     229              : 
     230            0 : HcclResult ScatterRingDirect::RunScatterOnRootRank(
     231              :     const u32 step, const Slice& subSlice, const Slice& cclSlice, const u32 rank, const u32 rankSize)
     232              : {
     233            0 :     if (step == rankSize - DMA_REDUCE_TWO_OFFSET && opInfo_->outputAddr != nullptr && rank == root_) {
     234            0 :         HCCL_DEBUG(
     235              :             "MemcpyAsync operation: step[%u] stream[main], dst rank[%u] starts to rcv offset[%llu], "
     236              :             "size[%llu] at userMemOut_",
     237              :             step, userRank_, lastStepOffset_, subSlice.size);
     238            0 :         DeviceMem src = inputMem_.range(cclSlice.offset, cclSlice.size);
     239            0 :         DeviceMem dst = DeviceMem::create(static_cast<u8*>(opInfo_->outputAddr) + lastStepOffset_, subSlice.size);
     240            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream_));
     241            0 :     }
     242            0 :     return HCCL_SUCCESS;
     243              : }
     244              : REGISTER_TEMPLATE(TemplateType::TEMPLATE_SCATTER_RING_DIRECT, ScatterRingDirect);
     245              : } // namespace hccl
        

Generated by: LCOV version 2.0-1