LCOV - code coverage report
Current view: top level - legacy/ascend910/algorithm/base/alg_template/temp_alltoallv - alltoallv_continuous_pipeline.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 543 0
Test Date: 2026-08-18 17:47:01 Functions: 0.0 % 40 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 "alltoallv_continuous_pipeline.h"
      12              : 
      13              : #include <vector>
      14              : #include <algorithm>
      15              : #include "alg_template_register.h"
      16              : 
      17              : namespace hccl {
      18            0 : AlltoallvContinuousPipeline::AlltoallvContinuousPipeline(const HcclDispatcher dispatcher) : AlgTemplateBase(dispatcher)
      19            0 : {}
      20              : 
      21            0 : AlltoallvContinuousPipeline::~AlltoallvContinuousPipeline() {}
      22              : 
      23            0 : HcclResult AlltoallvContinuousPipeline::PrepareSendRecvInfo(std::vector<SendRecvInfo>& sendRecvInfoList)
      24              : {
      25            0 :     if (sendRecvInfoList.size() == 1) {
      26              :         // 真实业务场景
      27            0 :         SendRecvInfo& localSendRecvInfo = sendRecvInfoList[0];
      28            0 :         localSendCounts_ = std::move(localSendRecvInfo.sendCounts);
      29            0 :         localSendDispls_ = std::move(localSendRecvInfo.sendDispls);
      30            0 :         localRecvCounts_ = std::move(localSendRecvInfo.recvCounts);
      31            0 :         localRecvDispls_ = std::move(localSendRecvInfo.recvDispls);
      32            0 :         needCollectInfo_ = true; // 需要收集信息
      33            0 :         std::copy(localRecvCounts_.begin(), localRecvCounts_.end(), intraRecvCounts_[intraRankId_].begin());
      34              :     } else {
      35              :         // 适配算法分析器,实际业务不会走这个分支
      36            0 :         SendRecvInfo& localSendRecvInfo = sendRecvInfoList[userRank_];
      37              : 
      38            0 :         std::copy(
      39              :             localSendRecvInfo.sendCounts.begin(), localSendRecvInfo.sendCounts.end(),
      40            0 :             std::back_inserter(localSendCounts_));
      41            0 :         std::copy(
      42              :             localSendRecvInfo.sendDispls.begin(), localSendRecvInfo.sendDispls.end(),
      43            0 :             std::back_inserter(localSendDispls_));
      44            0 :         std::copy(
      45              :             localSendRecvInfo.recvCounts.begin(), localSendRecvInfo.recvCounts.end(),
      46            0 :             std::back_inserter(localRecvCounts_));
      47            0 :         std::copy(
      48              :             localSendRecvInfo.recvDispls.begin(), localSendRecvInfo.recvDispls.end(),
      49            0 :             std::back_inserter(localRecvDispls_));
      50              : 
      51            0 :         for (u32 intraRankIdx = 0; intraRankIdx < intraRankSize_; ++intraRankIdx) {
      52            0 :             const u32 remoteRank = interRankId_ * intraRankSize_ + intraRankIdx;
      53            0 :             SendRecvInfo& sendRecvInfo = sendRecvInfoList[remoteRank];
      54            0 :             std::copy(
      55            0 :                 sendRecvInfo.recvCounts.begin(), sendRecvInfo.recvCounts.end(), intraRecvCounts_[intraRankIdx].begin());
      56              :         }
      57            0 :         needCollectInfo_ = false;
      58              :     }
      59              : 
      60            0 :     intraLoopNum_ = GetLocalLoopNum();
      61            0 :     return HCCL_SUCCESS;
      62              : }
      63              : 
      64            0 : HcclResult AlltoallvContinuousPipeline::PrepareTopoInfo(
      65              :     const u32 userRank, const SubCommInfo& level0CommInfo, const SubCommInfo& level1CommInfo)
      66              : {
      67            0 :     constexpr u32 MIN_RANKSIZE = 2;
      68            0 :     interRankSize_ = level1CommInfo.localRankSize;
      69            0 :     CHK_PRT_RET(
      70              :         interRankSize_ < MIN_RANKSIZE,
      71              :         HCCL_ERROR(
      72              :             "[AlltoallvContinuousPipeline][PrepareTopoInfo] Unexpected inter rank size[%u], which should >= 2.",
      73              :             interRankSize_),
      74              :         HCCL_E_PARA);
      75              : 
      76            0 :     intraRankSize_ = level0CommInfo.localRankSize;
      77            0 :     CHK_PRT_RET(
      78              :         intraRankSize_ < MIN_RANKSIZE,
      79              :         HCCL_ERROR(
      80              :             "[AlltoallvContinuousPipeline][PrepareTopoInfo] Unexpected intra rank size[%u], which should >= 2.",
      81              :             intraRankSize_),
      82              :         HCCL_E_PARA);
      83              : 
      84            0 :     userRankSize_ = intraRankSize_ * interRankSize_;
      85            0 :     userRank_ = userRank;
      86            0 :     interRankId_ = level1CommInfo.localRank;
      87            0 :     intraRankId_ = level0CommInfo.localRank;
      88            0 :     HCCL_INFO(
      89              :         "[AlltoallvContinuousPipeline][PrepareTopoInfo] userRank[%u], intraRankId[%u], intraRankSize[%u], "
      90              :         "interRankId[%u], interRankSize[%u]",
      91              :         userRank_, intraRankId_, intraRankSize_, interRankId_, interRankSize_);
      92              : 
      93              :     // 按照module将rank分组
      94            0 :     ranksPerModule_.resize(interRankSize_);
      95            0 :     for (u32 interRank = 0; interRank < interRankSize_; ++interRank) {
      96            0 :         ranksPerModule_[interRank].resize(intraRankSize_);
      97            0 :         for (u32 intraRank = 0; intraRank < intraRankSize_; ++intraRank) {
      98            0 :             ranksPerModule_[interRank][intraRank] = interRank * intraRankSize_ + intraRank;
      99              :         }
     100              :     }
     101            0 :     return HCCL_SUCCESS;
     102              : }
     103              : 
     104            0 : HcclResult AlltoallvContinuousPipeline::Prepare(
     105              :     const u32 userRank, const A2aPipelineMemory& a2aPipelineMemory, const SubCommInfo& level0CommInfo,
     106              :     const SubCommInfo& level1CommInfo, const Stream& mainStream, std::vector<Stream>& subStream,
     107              :     std::vector<std::shared_ptr<LocalNotify>>& notifyMain, std::vector<std::shared_ptr<LocalNotify>>& notifySub,
     108              :     std::vector<SendRecvInfo>& sendRecvInfoList, const HcclDataType dataType, const HcclWorkflowMode workMode)
     109              : {
     110              :     // 运行模式:当前只支持单算子
     111            0 :     workMode_ = workMode;
     112            0 :     CHK_PRT_RET(
     113              :         workMode_ != HcclWorkflowMode::HCCL_WORKFLOW_MODE_OP_BASE,
     114              :         HCCL_ERROR("[AlltoallvContinuousPipeline] This template support opbase mode only."), HCCL_E_INTERNAL);
     115              : 
     116              :     // 拓扑信息
     117            0 :     CHK_RET(PrepareTopoInfo(userRank, level0CommInfo, level1CommInfo));
     118              : 
     119              :     // 并发度暂定为1 - 不并发
     120            0 :     rdmaConcurrentNum_ = 1;
     121              : 
     122              :     // 数据类型
     123            0 :     dataType_ = dataType;
     124            0 :     unitSize_ = DataUnitSize(dataType_);
     125              : 
     126              :     // 内存
     127            0 :     inputMem_ = a2aPipelineMemory.userInput;
     128            0 :     outputMem_ = a2aPipelineMemory.userOutput;
     129            0 :     inBuffer_ = a2aPipelineMemory.cclInBuffer;
     130            0 :     outBuffer_ = a2aPipelineMemory.cclOutBuffer;
     131              : 
     132            0 :     flagAreaRefreshData_.resize(userRankSize_);
     133              : 
     134              :     // server内其他卡的recv counts
     135            0 :     intraRecvCounts_.resize(intraRankSize_);
     136            0 :     for (auto& countVec : intraRecvCounts_) {
     137            0 :         countVec.resize(userRankSize_);
     138              :     }
     139              : 
     140              :     // 流和notify
     141            0 :     mainStream_ = mainStream;
     142            0 :     CHK_RET(PartitionSubStreamsAndNotifies(subStream, notifyMain, notifySub));
     143              : 
     144              :     // 链路
     145            0 :     intraLinks_ = level0CommInfo.links;
     146            0 :     interLinks_ = level1CommInfo.links;
     147            0 :     HCCL_INFO(
     148              :         "[AlltoallvContinuousPipeline][Prepare] Link info: interLinksNum[%u], intraLinksNum[%u]", interLinks_.size(),
     149              :         intraLinks_.size());
     150              : 
     151              :     // pingpong模式: module间只有1步:双module
     152            0 :     enablePingPong_ = rdmaConcurrentNum_ >= interRankSize_ - 1;
     153              :     // 切分buffer
     154            0 :     CHK_RET(SplitBuffer(enablePingPong_));
     155              : 
     156              :     // 收发信息
     157            0 :     CHK_RET(PrepareSendRecvInfo(sendRecvInfoList));
     158              : 
     159            0 :     return HCCL_SUCCESS;
     160              : }
     161              : 
     162            0 : HcclResult AlltoallvContinuousPipeline::SplitBuffer(const bool enablePingPong)
     163              : {
     164              :     // 单个counts数组的大小
     165            0 :     const u64 singleRankCountsInfoSize = sizeof(u64) * userRankSize_;
     166              :     // 全局counts的大小
     167            0 :     const u64 globalCountsInfoSize = singleRankCountsInfoSize * userRankSize_;
     168              : 
     169            0 :     const u64 bufferSize = inBuffer_.size();
     170            0 :     u32 blockNum = userRankSize_;
     171              : 
     172            0 :     if (enablePingPong) {
     173              :         // 乒乓模式两倍分块
     174            0 :         blockNum = userRankSize_ * PINGPONG_MEM_NUM;
     175            0 :         HCCL_INFO("[AlltoallvContinuousPipeline][SplitBuffer] Use ping-pong mode.");
     176              :     }
     177              : 
     178            0 :     CHK_PRT_RET(
     179              :         blockNum == 0, HCCL_ERROR("[AlltoallvContinuousPipeline][SplitBuffer]Unexpected blockNum[%u].", blockNum),
     180              :         HCCL_E_INTERNAL);
     181              : 
     182              :     // 初始化用于记录buffer中每个分块当作存放了多少数据的vector
     183              :     // 如果是pingpong模式,需要两倍的大小
     184            0 :     inBufferDataSize_.resize(blockNum);
     185              : 
     186            0 :     u64 alignSize = HCCL_MIN_SLICE_ALIGN;
     187            0 :     const u64 minBufferSize = globalCountsInfoSize + alignSize * blockNum;
     188            0 :     CHK_PRT_RET(
     189              :         bufferSize < minBufferSize,
     190              :         HCCL_ERROR(
     191              :             "[AlltoallvContinuousPipeline][SplitBuffer]Insufficient buffer size [%llu Byte]; it needs to be "
     192              :             "greater than [%llu Byte].",
     193              :             bufferSize, minBufferSize),
     194              :         HCCL_E_MEMORY);
     195              : 
     196            0 :     if (bufferSize > globalCountsInfoSize + HCCL_MIN_SLICE_ALIGN_910_93 * blockNum) {
     197            0 :         alignSize = HCCL_MIN_SLICE_ALIGN_910_93;
     198              :     }
     199              : 
     200            0 :     countsPerBlock_ = (((bufferSize - globalCountsInfoSize) / blockNum) / alignSize * alignSize)
     201            0 :                       / unitSize_; // 前面已经可以保证countsPerBlock_大于0,不再检查
     202            0 :     sizePerBlock_ = countsPerBlock_ * unitSize_;
     203              : 
     204            0 :     for (u32 rank = 0; rank < userRankSize_; ++rank) {
     205            0 :         infoOffsets_.emplace_back(sizePerBlock_ * blockNum + singleRankCountsInfoSize * rank);
     206              :     }
     207              : 
     208            0 :     for (u32 blockIdx = 0; blockIdx < blockNum; ++blockIdx) {
     209            0 :         dataBlockOffsets_.emplace_back(sizePerBlock_ * blockIdx);
     210              :     }
     211              : 
     212            0 :     HCCL_INFO(
     213              :         "[AlltoallvContinuousPipeline][SplitBuffer] Split buffer done, alignSize[%llu], sizePerBlock[%llu], "
     214              :         "countsPerBlock[%llu], blockNum[%u]",
     215              :         alignSize, sizePerBlock_, countsPerBlock_, blockNum);
     216            0 :     return HCCL_SUCCESS;
     217              : }
     218              : 
     219            0 : HcclResult AlltoallvContinuousPipeline::PartitionSubStreamsAndNotifies(
     220              :     const std::vector<Stream>& subStreams, const std::vector<std::shared_ptr<LocalNotify>>& signalMainToSub,
     221              :     const std::vector<std::shared_ptr<LocalNotify>>& signalSubToMain)
     222              : {
     223            0 :     constexpr u32 DEVICE_EIGHT = 8;
     224            0 :     const u32 sdmaConcurrentNum = std::min(intraRankSize_ - 1, DEVICE_EIGHT);
     225            0 :     const u32 totalSubstreamSize = rdmaConcurrentNum_ + sdmaConcurrentNum;
     226            0 :     CHK_PRT_RET(
     227              :         subStreams.size() < totalSubstreamSize || signalMainToSub.size() < totalSubstreamSize
     228              :             || signalSubToMain.size() < totalSubstreamSize,
     229              :         HCCL_ERROR(
     230              :             "[AlltoallvContinuousPipeline] subStreams size [%u] or signalMainToSub size [%u] or signalSubToMain "
     231              :             "size [%u] is small than totalSubstreamSize [%u].",
     232              :             subStreams.size(), signalMainToSub.size(), signalSubToMain.size(), totalSubstreamSize),
     233              :         HCCL_E_PARA);
     234              : 
     235            0 :     u32 index = 0;
     236              : 
     237              :     // 用于SDMA通信的从流和主从同步notify
     238            0 :     for (u32 i = 0; i < sdmaConcurrentNum; ++i) {
     239            0 :         subStreams_.push_back(subStreams[index]);
     240            0 :         sdmaSubStreams_.push_back(subStreams[index]);
     241            0 :         streamNotifyMainToSdmaSub_.push_back(signalMainToSub[index]);
     242            0 :         streamNotifySdmaSubToMain_.push_back(signalSubToMain[index]);
     243            0 :         index++;
     244              :     }
     245              : 
     246              :     // 用于RDMA通信的从流和主从同步notify
     247            0 :     for (u32 i = 0; i < rdmaConcurrentNum_; ++i) {
     248            0 :         subStreams_.push_back(subStreams[index]);
     249            0 :         rdmaSubStreams_.push_back(subStreams[index]);
     250            0 :         streamNotifyMainToRdmaSub_.push_back(signalMainToSub[index]);
     251            0 :         streamNotifyRdmaSubToMain_.push_back(signalSubToMain[index]);
     252            0 :         index++;
     253              :     }
     254              : 
     255            0 :     HCCL_INFO(
     256              :         "[AlltoallvContinuousPipeline][PartitionSubStreamsAndNotifies] Done, sdma: #streams[%zu], "
     257              :         "#notifyMainSub[%zu], #notifySubToMain[%zu]; rdma: #streams[%zu], #notifyMainSub[%zu], "
     258              :         "#notifySubToMain[%zu].",
     259              :         sdmaSubStreams_.size(), streamNotifyMainToSdmaSub_.size(), streamNotifySdmaSubToMain_.size(),
     260              :         rdmaSubStreams_.size(), streamNotifyMainToRdmaSub_.size(), streamNotifyRdmaSubToMain_.size());
     261              : 
     262            0 :     return HCCL_SUCCESS;
     263              : }
     264              : 
     265            0 : inline u32 AlltoallvContinuousPipeline::GetSdmaSubStreamIdx(const u32 remoteRank) const
     266              : {
     267            0 :     return (remoteRank > intraRankId_ ? remoteRank - 1 : remoteRank) % sdmaSubStreams_.size();
     268              : }
     269              : 
     270            0 : inline u64 AlltoallvContinuousPipeline::GetLocalSendCountOfRank(const u32 targetRank) const
     271              : {
     272            0 :     return localSendCounts_[targetRank];
     273              : }
     274              : 
     275            0 : inline u64 AlltoallvContinuousPipeline::GetLocalSendDisplOfRank(const u32 targetRank) const
     276              : {
     277            0 :     return localSendDispls_[targetRank];
     278              : }
     279              : 
     280            0 : inline u64 AlltoallvContinuousPipeline::GetLocalRecvCountOfRank(const u32 sourceRank) const
     281              : {
     282            0 :     return localRecvCounts_[sourceRank];
     283              : }
     284              : 
     285            0 : inline u64 AlltoallvContinuousPipeline::GetLocalRecvDisplOfRank(const u32 sourceRank) const
     286              : {
     287            0 :     return localRecvDispls_[sourceRank];
     288              : }
     289              : 
     290            0 : inline u64 AlltoallvContinuousPipeline::GetDataBlockOffset(const u32 rank, const u32 bufferIdx) const
     291              : {
     292            0 :     if (enablePingPong_) {
     293            0 :         return dataBlockOffsets_[(bufferIdx % PINGPONG_MEM_NUM) * userRankSize_ + rank];
     294              :     }
     295            0 :     return dataBlockOffsets_[rank];
     296              : }
     297              : 
     298            0 : u32 AlltoallvContinuousPipeline::GetLocalLoopNum() const
     299              : {
     300            0 :     u64 maxCount = 0;
     301            0 :     for (u32 rank = 0; rank < userRankSize_; ++rank) {
     302            0 :         if (rank != userRank_) {
     303            0 :             const u64 sendCount = GetLocalSendCountOfRank(rank);
     304            0 :             maxCount = maxCount < sendCount ? sendCount : maxCount;
     305            0 :             const u64 recvCount = GetLocalRecvCountOfRank(rank);
     306            0 :             maxCount = maxCount < recvCount ? recvCount : maxCount;
     307              :         }
     308              :     }
     309              : 
     310              :     // 向上取整
     311            0 :     const u32 localLoopNum = static_cast<u32>((maxCount + countsPerBlock_ - 1) / countsPerBlock_);
     312            0 :     HCCL_INFO(
     313              :         "[AlltoallvContinuousPipeline][GetLocalLoopNum] maxCount[%llu], localLoopNum[%u]", maxCount, localLoopNum);
     314            0 :     return localLoopNum;
     315              : }
     316              : 
     317            0 : HcclResult AlltoallvContinuousPipeline::UpdateLocalSendInfo(const u32 targetRank, const u64 count)
     318              : {
     319            0 :     HCCL_DEBUG(
     320              :         "[AlltoallvContinuousPipeline][UpdateLocalSendInfo]userRank[%u], count[%llu], before "
     321              :         "update, send info of rank[%u] is [count:%llu, displ:%llu].",
     322              :         userRank_, count, targetRank, localSendCounts_[targetRank], localSendDispls_[targetRank]);
     323              : 
     324            0 :     const u64 maxCount = std::min(localSendCounts_[targetRank], count);
     325            0 :     localSendCounts_[targetRank] -= maxCount;
     326            0 :     localSendDispls_[targetRank] += maxCount;
     327              : 
     328            0 :     HCCL_DEBUG(
     329              :         "[AlltoallvContinuousPipeline][UpdateLocalSendInfo]userRank[%u], count[%llu], after "
     330              :         "update, send info of rank[%u] is [count:%llu, displ:%llu].",
     331              :         userRank_, count, targetRank, localSendCounts_[targetRank], localSendDispls_[targetRank]);
     332              : 
     333            0 :     return HCCL_SUCCESS;
     334              : }
     335              : 
     336            0 : HcclResult AlltoallvContinuousPipeline::UpdateLocalRecvInfo(const u32 sourceRank, const u64 count)
     337              : {
     338            0 :     HCCL_DEBUG(
     339              :         "[AlltoallvContinuousPipeline][UpdateLocalRecvInfo]userRank[%u], count[%llu], before "
     340              :         "update, receive info of rank[%u] is [count:%llu, displ:%llu].",
     341              :         userRank_, count, sourceRank, localRecvCounts_[sourceRank], localRecvDispls_[sourceRank]);
     342              : 
     343            0 :     const u64 maxCount = std::min(localRecvCounts_[sourceRank], count);
     344            0 :     localRecvCounts_[sourceRank] -= maxCount;
     345            0 :     localRecvDispls_[sourceRank] += maxCount;
     346              : 
     347            0 :     HCCL_DEBUG(
     348              :         "[AlltoallvContinuousPipeline][UpdateLocalRecvInfo]userRank[%u], count[%llu], after "
     349              :         "update, receive info of rank[%u] is [count:%llu, displ:%llu].",
     350              :         userRank_, count, sourceRank, localRecvCounts_[sourceRank], localRecvDispls_[sourceRank]);
     351              : 
     352            0 :     return HCCL_SUCCESS;
     353              : }
     354              : 
     355            0 : HcclResult AlltoallvContinuousPipeline::NotifySdmaSubStreamStart()
     356              : {
     357            0 :     for (u32 streamIndex = 0; streamIndex < sdmaSubStreams_.size(); ++streamIndex) {
     358            0 :         CHK_RET(
     359              :             LocalNotify::Post(mainStream_, dispatcher_, streamNotifySdmaSubToMain_[streamIndex], INVALID_VALUE_STAGE));
     360            0 :         CHK_RET(LocalNotify::Wait(
     361              :             sdmaSubStreams_[streamIndex], dispatcher_, streamNotifySdmaSubToMain_[streamIndex], INVALID_VALUE_STAGE));
     362              :     }
     363            0 :     return HCCL_SUCCESS;
     364              : }
     365              : 
     366            0 : HcclResult AlltoallvContinuousPipeline::WaitSdmaSubStreamFinish()
     367              : {
     368            0 :     for (u32 streamIndex = 0; streamIndex < sdmaSubStreams_.size(); ++streamIndex) {
     369            0 :         CHK_RET(LocalNotify::Post(
     370              :             sdmaSubStreams_[streamIndex], dispatcher_, streamNotifyMainToSdmaSub_[streamIndex], INVALID_VALUE_STAGE));
     371            0 :         CHK_RET(
     372              :             LocalNotify::Wait(mainStream_, dispatcher_, streamNotifyMainToSdmaSub_[streamIndex], INVALID_VALUE_STAGE));
     373              :     }
     374            0 :     return HCCL_SUCCESS;
     375              : }
     376              : 
     377            0 : HcclResult AlltoallvContinuousPipeline::NotifyRdmaSubStreamStart()
     378              : {
     379            0 :     for (u32 streamIndex = 0; streamIndex < rdmaSubStreams_.size(); ++streamIndex) {
     380            0 :         CHK_RET(
     381              :             LocalNotify::Post(mainStream_, dispatcher_, streamNotifyRdmaSubToMain_[streamIndex], INVALID_VALUE_STAGE));
     382            0 :         CHK_RET(LocalNotify::Wait(
     383              :             rdmaSubStreams_[streamIndex], dispatcher_, streamNotifyRdmaSubToMain_[streamIndex], INVALID_VALUE_STAGE));
     384              :     }
     385            0 :     return HCCL_SUCCESS;
     386              : }
     387              : 
     388            0 : HcclResult AlltoallvContinuousPipeline::WaitRdmaSubStreamFinish()
     389              : {
     390            0 :     for (u32 streamIndex = 0; streamIndex < rdmaSubStreams_.size(); ++streamIndex) {
     391            0 :         CHK_RET(LocalNotify::Post(
     392              :             rdmaSubStreams_[streamIndex], dispatcher_, streamNotifyMainToRdmaSub_[streamIndex], INVALID_VALUE_STAGE));
     393            0 :         CHK_RET(
     394              :             LocalNotify::Wait(mainStream_, dispatcher_, streamNotifyMainToRdmaSub_[streamIndex], INVALID_VALUE_STAGE));
     395              :     }
     396            0 :     return HCCL_SUCCESS;
     397              : }
     398              : 
     399            0 : HcclResult AlltoallvContinuousPipeline::InterSdmaRx(
     400              :     const LINK& linkLeft, const LINK& linkRight, std::vector<TxMemoryInfo>& sendMems,
     401              :     std::vector<RxMemoryInfo>& recvMems, Stream& stream)
     402              : {
     403            0 :     const bool needRecvFromLinkLeft = !recvMems.empty();
     404            0 :     const bool needSendToLinkRight = !sendMems.empty();
     405              : 
     406              :     // 前同步,通知right我已准备好,可以从我这里读;等待left通知它已准备好,可以从它那里读
     407            0 :     if (needSendToLinkRight) {
     408            0 :         CHK_RET(linkRight->TxAck(stream));
     409              :     }
     410            0 :     if (needRecvFromLinkLeft) {
     411            0 :         CHK_RET(linkLeft->RxAck(stream));
     412              :     }
     413              : 
     414              :     // 从left读
     415            0 :     for (const auto& memInfo : recvMems) {
     416            0 :         void* srcMemPtr = nullptr;
     417            0 :         CHK_RET(linkLeft->GetRemoteMem(memInfo.srcMemType, &srcMemPtr));
     418            0 :         DeviceMem dstMem = DeviceMem::create(memInfo.dst, memInfo.len);
     419            0 :         DeviceMem srcMem(static_cast<s8*>(srcMemPtr) + memInfo.srcOffset, memInfo.len);
     420            0 :         CHK_RET(HcclD2DMemcpyAsync(
     421              :             dispatcher_, dstMem, srcMem, stream, linkLeft->GetRemoteRank(), linkLeft->GetLinkType()));
     422            0 :     }
     423              : 
     424              :     // 尾同步,通知left我已读完,等待right通知它已读完
     425            0 :     if (needRecvFromLinkLeft) {
     426            0 :         CHK_RET(linkLeft->TxDataSignal(stream));
     427              :     }
     428            0 :     if (needSendToLinkRight) {
     429            0 :         CHK_RET(linkRight->RxDataSignal(stream));
     430              :     }
     431              : 
     432            0 :     HCCL_DEBUG(
     433              :         "[AlltoallvContinuousPipeline][InterSdmaRx] Done. linkLeft.rank[%u], linkRight.rank[%u], "
     434              :         "recvMems.size[%zu]",
     435              :         linkLeft->GetRemoteRank(), linkRight->GetRemoteRank(), recvMems.size());
     436            0 :     return HCCL_SUCCESS;
     437              : }
     438              : 
     439              : // 跨module通信,通过RDMA从link left读或向link right写
     440            0 : HcclResult AlltoallvContinuousPipeline::InterRdmaTxRx(
     441              :     const LINK& linkLeft, const LINK& linkRight, std::vector<TxMemoryInfo>& sendMems,
     442              :     std::vector<RxMemoryInfo>& recvMems, Stream& stream)
     443              : {
     444            0 :     const bool needRecvFromLinkLeft = !recvMems.empty();
     445            0 :     const bool needSendToLinkRight = !sendMems.empty();
     446              : 
     447            0 :     if (needRecvFromLinkLeft) {
     448            0 :         CHK_RET(linkLeft->TxAck(stream));
     449              :     }
     450            0 :     if (needSendToLinkRight) {
     451            0 :         CHK_RET(linkRight->RxAck(stream));
     452            0 :         CHK_RET(linkRight->TxAsync(sendMems, stream));
     453              :     }
     454            0 :     if (needRecvFromLinkLeft) {
     455            0 :         CHK_RET(linkLeft->RxAsync(recvMems, stream));
     456            0 :         CHK_RET(linkLeft->PostFinAck(stream));
     457              :     }
     458            0 :     if (needSendToLinkRight) {
     459            0 :         CHK_RET(linkRight->WaitFinAck(stream));
     460              :     }
     461              : 
     462            0 :     HCCL_DEBUG(
     463              :         "[AlltoallvContinuousPipeline][InterRdmaTxRx] Done. linkLeft.rank[%u], linkRight.rank[%u], "
     464              :         "sendMems.size[%zu], recvMems.size[%zu]",
     465              :         linkLeft->GetRemoteRank(), linkRight->GetRemoteRank(), sendMems.size(), recvMems.size());
     466            0 :     return HCCL_SUCCESS;
     467              : }
     468              : 
     469              : HcclResult
     470            0 : AlltoallvContinuousPipeline::LocalCopyFromInputToInBuffer(const u32 targetRank, Stream& stream, const u32 loopIdx)
     471              : {
     472              :     // 根据send displs来计算input的位置,取min(countsPerBlock_, count)个数
     473            0 :     const u64 copyCount = std::min(GetLocalSendCountOfRank(targetRank), countsPerBlock_);
     474            0 :     if (copyCount == 0) {
     475            0 :         return HCCL_SUCCESS;
     476              :     }
     477              : 
     478            0 :     const u64 copySize = copyCount * unitSize_;
     479              : 
     480              :     // 从input拷贝到in buffer对应的分块里
     481            0 :     const u64 srcOffset = GetLocalSendDisplOfRank(targetRank) * unitSize_;
     482            0 :     const u64 dstOffset = GetDataBlockOffset(targetRank, loopIdx);
     483            0 :     DeviceMem src = inputMem_.range(srcOffset, copySize);
     484            0 :     DeviceMem dst = inBuffer_.range(dstOffset, copySize);
     485              : 
     486            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream));
     487              : 
     488              :     // 刷新send info
     489            0 :     CHK_RET(UpdateLocalSendInfo(targetRank, copyCount));
     490              : 
     491              :     // 记录in bufer中该分块存放了多少数据
     492            0 :     inBufferDataSize_[targetRank] = copySize;
     493              : 
     494            0 :     HCCL_DEBUG(
     495              :         "[AlltoallvContinuousPipeline][LocalCopy][FromInputToInBuffer] done, userRank[%u], targetRank[%u], "
     496              :         "srcOffset[%llu], dstOffset[%llu], copyCount[%llu], copySize[%llu], loopIdx[%u]",
     497              :         userRank_, targetRank, srcOffset, dstOffset, copyCount, copySize, loopIdx);
     498            0 :     return HCCL_SUCCESS;
     499            0 : }
     500              : 
     501              : HcclResult
     502            0 : AlltoallvContinuousPipeline::LocalCopyFromOutBufferToOutput(const u32 sourceRank, Stream& stream, const u32 loopIdx)
     503              : {
     504            0 :     const u64 copyCount = std::min(GetLocalRecvCountOfRank(sourceRank), countsPerBlock_);
     505            0 :     if (copyCount == 0) {
     506            0 :         return HCCL_SUCCESS;
     507              :     }
     508              : 
     509              :     // 从out buffer对应分块拷贝到output
     510            0 :     const u64 copySize = copyCount * unitSize_;
     511            0 :     const u64 srcOffset = GetDataBlockOffset(sourceRank, loopIdx);
     512            0 :     const u64 dstOffset = GetLocalRecvDisplOfRank(sourceRank) * unitSize_;
     513            0 :     DeviceMem src = outBuffer_.range(srcOffset, copySize);
     514            0 :     DeviceMem dst = outputMem_.range(dstOffset, copySize);
     515              : 
     516            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream));
     517              : 
     518              :     // 刷新receive info
     519            0 :     CHK_RET(UpdateLocalRecvInfo(sourceRank, copyCount));
     520              : 
     521            0 :     HCCL_DEBUG(
     522              :         "[AlltoallvContinuousPipeline][LocalCopy][FromOutBufferToOutput] done, userRank[%u], sourceRank[%u], "
     523              :         "srcOffset[%llu], dstOffset[%llu], copyCount[%llu], copySize[%llu], loopIdx[%u]",
     524              :         userRank_, sourceRank, srcOffset, dstOffset, copyCount, copySize, loopIdx);
     525            0 :     return HCCL_SUCCESS;
     526            0 : }
     527              : 
     528            0 : HcclResult AlltoallvContinuousPipeline::LocalCopySelfDataFromInputToOutput(Stream& stream)
     529              : {
     530            0 :     const u64 copyCount = GetLocalSendCountOfRank(userRank_);
     531            0 :     if (copyCount == 0) {
     532            0 :         return HCCL_SUCCESS;
     533              :     }
     534              : 
     535              :     // 从input拷贝到output
     536            0 :     const u64 copySize = copyCount * unitSize_;
     537            0 :     const u64 srcOffset = GetLocalSendDisplOfRank(userRank_) * unitSize_;
     538            0 :     const u64 dstOffset = GetLocalRecvDisplOfRank(userRank_) * unitSize_;
     539            0 :     DeviceMem src = inputMem_.range(srcOffset, copySize);
     540            0 :     DeviceMem dst = outputMem_.range(dstOffset, copySize);
     541              : 
     542            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream));
     543              : 
     544            0 :     HCCL_DEBUG(
     545              :         "[AlltoallvContinuousPipeline][LocalCopy][SelfDataFromInputToOutput] done, userRank[%u], "
     546              :         "srcOffset[%llu], dstOffset[%llu], copyCount[%llu], copySize[%llu]",
     547              :         userRank_, srcOffset, dstOffset, copyCount, copySize);
     548            0 :     return HCCL_SUCCESS;
     549            0 : }
     550              : 
     551              : HcclResult
     552            0 : AlltoallvContinuousPipeline::SdmaSendFromInputToRemoteOutBuffer(const u32 targetRank, Stream& stream, const u32 loopIdx)
     553              : {
     554            0 :     const u64 sendCount = std::min(GetLocalSendCountOfRank(targetRank), countsPerBlock_);
     555            0 :     if (sendCount == 0) {
     556            0 :         return HCCL_SUCCESS;
     557              :     }
     558              : 
     559              :     // 从input发送到remote out buffer,目的位置是第[本userRank_]个分块
     560            0 :     const u64 sendSize = sendCount * unitSize_;
     561            0 :     const u64 srcOffset = GetLocalSendDisplOfRank(targetRank) * unitSize_;
     562            0 :     const u64 dstOffset = GetDataBlockOffset(userRank_, loopIdx);
     563            0 :     DeviceMem src = inputMem_.range(srcOffset, sendSize);
     564              : 
     565            0 :     const LINK& link = intraLinks_[targetRank % intraRankSize_];
     566            0 :     void* remMemPtr = nullptr;
     567            0 :     CHK_RET(link->GetRemoteMem(UserMemType::OUTPUT_MEM, &remMemPtr));
     568            0 :     DeviceMem dst = DeviceMem::create(static_cast<u8*>(remMemPtr) + dstOffset, sendSize);
     569              : 
     570              :     // 前后同步在外层处理
     571            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream, targetRank, link->GetLinkType()));
     572              : 
     573              :     // 刷新send info
     574            0 :     CHK_RET(UpdateLocalSendInfo(targetRank, sendCount));
     575              : 
     576            0 :     HCCL_DEBUG(
     577              :         "[AlltoallvContinuousPipeline][Sdma][SendFromInputToRemoteOutBuffer] done, userRank[%u], "
     578              :         "targetRank[%u], srcOffset[%llu], dstOffset[%llu], sendCount[%llu], sendSize[%llu], loopIdx[%u]",
     579              :         userRank_, targetRank, srcOffset, dstOffset, sendCount, sendSize, loopIdx);
     580            0 :     return HCCL_SUCCESS;
     581            0 : }
     582              : 
     583            0 : HcclResult AlltoallvContinuousPipeline::SdmaReadFromRemoteOutBufferToOutput(
     584              :     const u32 sourceRank, Stream& stream, const u32 loopIdx)
     585              : {
     586              :     // 需要recv counts信息
     587            0 :     CHK_PRT_RET(
     588              :         needCollectInfo_,
     589              :         HCCL_ERROR("[AlltoallvContinuousPipeline][SdmaReadFromRemoteOutBufferToOutput] No receive info."),
     590              :         HCCL_E_INTERNAL);
     591              : 
     592            0 :     const u64 readCount = std::min(GetLocalRecvCountOfRank(sourceRank), countsPerBlock_);
     593            0 :     if (readCount == 0) {
     594            0 :         return HCCL_SUCCESS;
     595              :     }
     596              : 
     597              :     // 从remote out buffer读取到output,源位置是第[sourceRank / intraRankSize_ * intraRankSize_ + intraRankId_]个分块
     598            0 :     const u64 readSize = readCount * unitSize_;
     599            0 :     const u64 srcBlockIdx = sourceRank / intraRankSize_ * intraRankSize_ + intraRankId_;
     600            0 :     const u64 srcOffset = GetDataBlockOffset(srcBlockIdx, loopIdx);
     601            0 :     const u64 dstOffset = GetLocalRecvDisplOfRank(sourceRank) * unitSize_;
     602              : 
     603            0 :     const LINK& link = intraLinks_[sourceRank % intraRankSize_];
     604            0 :     void* remMemPtr = nullptr;
     605            0 :     CHK_RET(link->GetRemoteMem(UserMemType::OUTPUT_MEM, &remMemPtr));
     606            0 :     DeviceMem src = DeviceMem::create(static_cast<u8*>(remMemPtr) + srcOffset, readSize);
     607              : 
     608            0 :     DeviceMem dst = outputMem_.range(dstOffset, readSize);
     609              : 
     610              :     // 前后同步在外层处理
     611            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, dst, src, stream, sourceRank, link->GetLinkType()));
     612              : 
     613              :     // 刷新receive info
     614            0 :     CHK_RET(UpdateLocalRecvInfo(sourceRank, readCount));
     615              : 
     616            0 :     HCCL_DEBUG(
     617              :         "[AlltoallvContinuousPipeline][Sdma][ReadFromRemoteOutBufferToOutput] done, userRank[%u], "
     618              :         "sourceRank[%u], srcOffset[%llu], dstOffset[%llu], readCount[%llu], readSize[%llu], loopIdx[%u]",
     619              :         userRank_, sourceRank, srcOffset, dstOffset, readCount, readSize, loopIdx);
     620            0 :     return HCCL_SUCCESS;
     621            0 : }
     622              : 
     623            0 : HcclResult AlltoallvContinuousPipeline::InterSendAndReceive(
     624              :     const u32 sendRank, const u32 recvRank, Stream& stream, const u32 loopIdx)
     625              : {
     626              :     // 计算出对端rank所在module的首rank,因为要向对端rank发送[首rank, 首rank+intraRankSize]rank的数据
     627            0 :     const u32 sendModuleFirstRank = sendRank / intraRankSize_ * intraRankSize_;
     628            0 :     const u32 recvModuleFirstRank = recvRank / intraRankSize_ * intraRankSize_;
     629              : 
     630            0 :     std::vector<TxMemoryInfo> sendMems;
     631            0 :     std::vector<RxMemoryInfo> recvMems;
     632            0 :     sendMems.reserve(intraRankSize_);
     633            0 :     recvMems.reserve(intraRankSize_);
     634              : 
     635            0 :     const LINK& sendLink = interLinks_[sendRank / intraRankSize_];
     636            0 :     const LINK& recvLink = interLinks_[recvRank / intraRankSize_];
     637            0 :     const bool isSDMALink = sendLink->IsSpInlineReduce() || recvLink->IsSpInlineReduce();
     638              : 
     639            0 :     for (u32 rankOffset = 0; rankOffset < intraRankSize_; ++rankOffset) {
     640            0 :         const u32 targetRank = sendModuleFirstRank + rankOffset;
     641            0 :         const u64 sendSrcOffset = GetDataBlockOffset(targetRank, loopIdx);
     642            0 :         const u64 sendDstOffset = GetDataBlockOffset(interRankId_ * intraRankSize_ + rankOffset, loopIdx);
     643            0 :         const u64 sendSize = inBufferDataSize_[targetRank];
     644            0 :         inBufferDataSize_[targetRank] = 0;
     645            0 :         if (sendSize > 0) {
     646            0 :             sendMems.emplace_back(TxMemoryInfo{
     647            0 :                 UserMemType::OUTPUT_MEM, sendDstOffset, static_cast<s8*>(inBuffer_.ptr()) + sendSrcOffset, sendSize});
     648              :         }
     649            0 :         HCCL_DEBUG(
     650              :             "[AlltoallvContinuousPipeline][InterSendAndReceive]inter send userRank[%u], sendRank[%u], "
     651              :             "targetRank[%u], srcOffset[%llu], dstOffset[%llu], sendSize[%llu], loopIdx[%u]",
     652              :             userRank_, sendRank, targetRank, sendSrcOffset, sendDstOffset, sendSize, loopIdx);
     653              : 
     654            0 :         const u32 sourceRank = recvModuleFirstRank + intraRankId_;
     655            0 :         const u32 actualTargetRank = interRankId_ * intraRankSize_ + rankOffset;
     656            0 :         const u64 recvSrcOffset = GetDataBlockOffset(actualTargetRank, loopIdx);
     657            0 :         const u64 recvDstOffset = GetDataBlockOffset(recvModuleFirstRank + rankOffset, loopIdx);
     658            0 :         const u64 recvCount = std::min(countsPerBlock_, intraRecvCounts_[rankOffset][sourceRank]);
     659            0 :         const u64 recvSize = recvCount * unitSize_;
     660            0 :         if (recvCount > 0) {
     661            0 :             recvMems.emplace_back(RxMemoryInfo{
     662            0 :                 UserMemType::INPUT_MEM, recvSrcOffset, static_cast<s8*>(outBuffer_.ptr()) + recvDstOffset, recvSize});
     663            0 :             intraRecvCounts_[rankOffset][sourceRank] -= recvCount;
     664              :         }
     665            0 :         HCCL_DEBUG(
     666              :             "[AlltoallvContinuousPipeline][InterSendAndReceive]inter recv userRank[%u], recvRank[%u], "
     667              :             "sourceRank[%u], targetRank[%u], srcOffset[%llu], dstOffset[%llu], readSize[%llu], loopIdx[%u]",
     668              :             userRank_, recvRank, sourceRank, actualTargetRank, recvSrcOffset, recvDstOffset, recvSize, loopIdx);
     669              :     }
     670            0 :     if (isSDMALink) {
     671              :         // SDMA读
     672            0 :         CHK_RET(InterSdmaRx(recvLink, sendLink, sendMems, recvMems, stream));
     673              :     } else {
     674              :         // RDMA
     675            0 :         CHK_RET(InterRdmaTxRx(recvLink, sendLink, sendMems, recvMems, stream));
     676              :     }
     677              : 
     678            0 :     return HCCL_SUCCESS;
     679            0 : }
     680              : 
     681            0 : HcclResult AlltoallvContinuousPipeline::DoSdmaSync(const SdmaSyncType syncType)
     682              : {
     683            0 :     for (u32 rank = 0; rank < intraRankSize_; ++rank) {
     684            0 :         if (rank == intraRankId_) {
     685            0 :             continue;
     686              :         }
     687            0 :         const u32 streamIndex = GetSdmaSubStreamIdx(rank);
     688            0 :         const LINK& link = intraLinks_[rank];
     689            0 :         Stream& subStream = sdmaSubStreams_[streamIndex];
     690            0 :         if (syncType == SdmaSyncType::PRE_SYNC) {
     691              :             // 前同步
     692            0 :             CHK_RET(link->TxAck(subStream));
     693            0 :             CHK_RET(link->RxAck(subStream));
     694              :         } else {
     695              :             // 尾同步
     696            0 :             CHK_RET(link->TxDataSignal(subStream));
     697            0 :             CHK_RET(link->RxDataSignal(subStream));
     698              :         }
     699              :     }
     700            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][DoSdmaSync] Sync done, syncType[%d].", syncType);
     701            0 :     return HCCL_SUCCESS;
     702              : }
     703              : 
     704            0 : HcclResult AlltoallvContinuousPipeline::DoLocalCopy(const u32 beginStepNum, const u32 endStepNum, const u32 loopIdx)
     705              : {
     706            0 :     CHK_PRT_RET(
     707              :         beginStepNum == endStepNum,
     708              :         HCCL_DEBUG(
     709              :             "[AlltoallvContinuousPipeline][DoLocalCopy]beginStepNum[%u] == endStepNum[%u], return success.",
     710              :             beginStepNum, endStepNum),
     711              :         HCCL_SUCCESS);
     712              : 
     713            0 :     for (u32 step = beginStepNum + 1; step < endStepNum + 1; ++step) {
     714            0 :         const u32 sendModuleId = (interRankId_ + step) % interRankSize_;
     715            0 :         for (const auto remoteRank : ranksPerModule_[sendModuleId]) {
     716            0 :             CHK_RET(LocalCopyFromInputToInBuffer(remoteRank, mainStream_, loopIdx));
     717              :         }
     718              :     }
     719            0 :     HCCL_DEBUG(
     720              :         "[AlltoallvContinuousPipeline][DoLocalCopy] done. beginStepNum[%u], endStepNum[%u], loopIdx[%u]", beginStepNum,
     721              :         endStepNum, loopIdx);
     722            0 :     return HCCL_SUCCESS;
     723              : }
     724              : 
     725              : HcclResult
     726            0 : AlltoallvContinuousPipeline::DoIntraDistribution(const u32 beginStepNum, const u32 endStepNum, const u32 loopIdx)
     727              : {
     728            0 :     CHK_PRT_RET(
     729              :         beginStepNum == endStepNum,
     730              :         HCCL_DEBUG(
     731              :             "[AlltoallvContinuousPipeline][DoIntraDistribution]beginStepNum[%u] == endStepNum[%u], return "
     732              :             "success.",
     733              :             beginStepNum, endStepNum),
     734              :         HCCL_SUCCESS);
     735              : 
     736            0 :     for (u32 step = beginStepNum + 1; step < endStepNum + 1; ++step) {
     737            0 :         const u32 recvModuleId = (interRankId_ + interRankSize_ - step) % interRankSize_;
     738            0 :         HCCL_DEBUG("[AlltoallvContinuousPipeline][DoIntraDistribution] recvModuleId[%u]", recvModuleId);
     739            0 :         for (const auto remoteRank : ranksPerModule_[recvModuleId]) {
     740            0 :             const u32 remoteIntraRank = remoteRank % intraRankSize_;
     741            0 :             HCCL_DEBUG("[AlltoallvContinuousPipeline][DoIntraDistribution] remoteIntraRank[%u]", remoteIntraRank);
     742            0 :             if (intraRankId_ == remoteIntraRank) {
     743              :                 // 如果是同号卡,直接从out buffer拷贝到output
     744            0 :                 CHK_RET(LocalCopyFromOutBufferToOutput(remoteRank, mainStream_, loopIdx));
     745              :             } else {
     746              :                 // 如果不是同号卡,从module内它对应的同号卡获取
     747            0 :                 const u32 streamIndex = GetSdmaSubStreamIdx(remoteIntraRank);
     748            0 :                 HCCL_DEBUG(
     749              :                     "[AlltoallvContinuousPipeline][DoIntraDistribution] streamIndex[%u], sdmaSubStreams_.size()[%zu]",
     750              :                     streamIndex, sdmaSubStreams_.size());
     751            0 :                 Stream& subStream = sdmaSubStreams_[streamIndex];
     752            0 :                 CHK_RET(SdmaReadFromRemoteOutBufferToOutput(remoteRank, subStream, loopIdx));
     753              :             }
     754              :         }
     755              :     }
     756              : 
     757            0 :     HCCL_DEBUG(
     758              :         "[AlltoallvContinuousPipeline][DoIntraDistribution] done. beginStepNum[%u], endStepNum[%u], loopIdx[%u]",
     759              :         beginStepNum, endStepNum, loopIdx);
     760            0 :     return HCCL_SUCCESS;
     761              : }
     762              : 
     763              : HcclResult
     764            0 : AlltoallvContinuousPipeline::DoInterSendReceive(const u32 beginStepNum, const u32 endStepNum, const u32 loopIdx)
     765              : {
     766            0 :     CHK_PRT_RET(
     767              :         beginStepNum == endStepNum,
     768              :         HCCL_DEBUG(
     769              :             "[AlltoallvContinuousPipeline][DoInterSendReceive]beginStepNum[%u] == endStepNum[%u], return "
     770              :             "success.",
     771              :             beginStepNum, endStepNum),
     772              :         HCCL_SUCCESS);
     773              : 
     774            0 :     u32 streamIdx = 0;
     775            0 :     for (u32 step = beginStepNum + 1; step < endStepNum + 1; ++step) {
     776            0 :         const u32 sendRank = (userRank_ + step * intraRankSize_) % userRankSize_;
     777            0 :         const u32 recvRank = (userRank_ + userRankSize_ - step * intraRankSize_) % userRankSize_;
     778            0 :         CHK_RET(InterSendAndReceive(sendRank, recvRank, rdmaSubStreams_[streamIdx++], loopIdx));
     779              :     }
     780            0 :     HCCL_DEBUG(
     781              :         "[AlltoallvContinuousPipeline][DoInterSendReceive] done. beginStepNum[%u], endStepNum[%u], loopIdx[%u]",
     782              :         beginStepNum, endStepNum, loopIdx);
     783            0 :     return HCCL_SUCCESS;
     784              : }
     785              : 
     786            0 : HcclResult AlltoallvContinuousPipeline::DoLevel0LocalCopy(const u32 loopIdx)
     787              : {
     788            0 :     for (const auto remoteRank : ranksPerModule_[interRankId_]) {
     789            0 :         if (remoteRank == userRank_) {
     790            0 :             continue;
     791              :         }
     792            0 :         CHK_RET(LocalCopyFromOutBufferToOutput(remoteRank, mainStream_, loopIdx));
     793              :     }
     794            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][DoLevel0LocalCopy] done, loopIdx[%u].", loopIdx);
     795            0 :     return HCCL_SUCCESS;
     796              : }
     797              : 
     798            0 : HcclResult AlltoallvContinuousPipeline::DoLevel0SdmaSend(const u32 loopIdx)
     799              : {
     800            0 :     for (const auto remoteRank : ranksPerModule_[interRankId_]) {
     801            0 :         if (remoteRank == userRank_) {
     802            0 :             continue;
     803              :         }
     804            0 :         const u32 remoteIntraRank = remoteRank % intraRankSize_;
     805            0 :         const u32 streamIndex = GetSdmaSubStreamIdx(remoteIntraRank);
     806            0 :         Stream& subStream = sdmaSubStreams_[streamIndex];
     807            0 :         CHK_RET(SdmaSendFromInputToRemoteOutBuffer(remoteRank, subStream, loopIdx));
     808              :     }
     809              : 
     810            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][DoLevel0SdmaSend] done, loopIdx[%u].", loopIdx);
     811            0 :     return HCCL_SUCCESS;
     812              : }
     813              : 
     814            0 : HcclResult AlltoallvContinuousPipeline::DoIntraInfoBroadcast()
     815              : {
     816            0 :     for (const auto remoteRank : ranksPerModule_[interRankId_]) {
     817            0 :         if (remoteRank == userRank_) {
     818            0 :             continue;
     819              :         }
     820            0 :         const u32 remoteIntraRank = remoteRank % intraRankSize_;
     821            0 :         const u32 streamIndex = GetSdmaSubStreamIdx(remoteIntraRank);
     822            0 :         Stream& subStream = sdmaSubStreams_[streamIndex];
     823              : 
     824            0 :         const LINK& link = intraLinks_[remoteRank % intraRankSize_];
     825            0 :         void* remInPtr = nullptr;
     826            0 :         void* remOutPtr = nullptr;
     827            0 :         CHK_RET(link->GetRemoteMem(UserMemType::INPUT_MEM, &remInPtr));
     828            0 :         CHK_RET(link->GetRemoteMem(UserMemType::OUTPUT_MEM, &remOutPtr));
     829              : 
     830              :         // 前后同步在外层处理,直接发送
     831              :         // 发送counts信息,从output发送到remote out buffer,目的位置是第[本userRank_]个info分块
     832            0 :         const u64 infoSize = userRankSize_ * sizeof(u64);
     833            0 :         const u64 infoOffset = infoOffsets_[userRank_];
     834            0 :         DeviceMem infoSrc = outBuffer_.range(infoOffset, infoSize);
     835            0 :         DeviceMem infoDst = DeviceMem::create(static_cast<u8*>(remOutPtr) + infoOffset, infoSize);
     836            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, infoDst, infoSrc, subStream, remoteRank, link->GetLinkType()));
     837              : 
     838              :         // 发送flag,flag值为[LocalLoopNum + 1],从input发送到remote in buffer,目的位置是第[本userRank_]个u32
     839            0 :         const u64 flagSize = sizeof(u32);
     840            0 :         const u64 flagOffset = infoOffsets_[0] + userRank_ * flagSize;
     841            0 :         DeviceMem flagSrc = inBuffer_.range(flagOffset, flagSize);
     842            0 :         DeviceMem flagDst = DeviceMem::create(static_cast<u8*>(remInPtr) + flagOffset, flagSize);
     843            0 :         CHK_RET(HcclD2DMemcpyAsync(dispatcher_, flagDst, flagSrc, subStream, remoteRank, link->GetLinkType()));
     844              : 
     845            0 :         HCCL_DEBUG(
     846              :             "[AlltoallvContinuousPipeline][DoIntraInfoBroadcast] userRank[%u], send info to remoteRank[%u], "
     847              :             "infoOffset[%llu], infoSize[%llu], flagOffset[%llu], flagSize[%llu]",
     848              :             userRank_, remoteRank, infoOffset, infoSize, flagOffset, flagSize);
     849            0 :     }
     850              : 
     851            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][DoIntraInfoBroadcast] done.");
     852            0 :     return HCCL_SUCCESS;
     853              : }
     854              : 
     855            0 : HcclResult AlltoallvContinuousPipeline::DoLocalWriteInfoAndFlagAndInterSync()
     856              : {
     857            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][DoLocalWriteInfoAndFlagAndInterSync] start.");
     858              : 
     859            0 :     if (!needCollectInfo_) {
     860            0 :         return HCCL_SUCCESS;
     861              :     }
     862              : 
     863              :     // 将counts信息写到out buffer的info区域
     864            0 :     void* infoPtr = localRecvCounts_.data();
     865            0 :     const u64 infoSize = userRankSize_ * sizeof(u64);
     866            0 :     const u64 infoOffset = infoOffsets_[userRank_];
     867            0 :     DeviceMem infoSrc = DeviceMem::create(infoPtr, infoSize);
     868            0 :     DeviceMem infoDst = outBuffer_.range(infoOffset, infoSize);
     869            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, infoDst, infoSrc, mainStream_));
     870              : 
     871              :     // 将in buffer的flag区域刷0,第[userRank]个u32设为[LocalLoopNum + 1]
     872            0 :     const u64 flagAreaSize = userRankSize_ * sizeof(u32);
     873            0 :     flagAreaRefreshData_[userRank_] = intraLoopNum_ + 1; // +1是应对LocalLoopNum为0的情况
     874            0 :     DeviceMem flagSrc = DeviceMem::create(flagAreaRefreshData_.data(), flagAreaSize);
     875            0 :     DeviceMem flagDst = inBuffer_.range(infoOffsets_[0], flagAreaSize);
     876            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, flagDst, flagSrc, mainStream_));
     877              : 
     878              :     // 在主流上下一个搬1的任务,kernel可以通过轮询dst是否为1,确保flag区域已被刷值,避免flag区域还是随机值时就开始轮询。
     879            0 :     DeviceMem refreshFlagSrc = DeviceMem::create(&flagAreaRefreshValue_, sizeof(flagAreaRefreshValue_));
     880            0 :     DeviceMem refreshFlagDst = DeviceMem::create(&flagAreaRefreshFlag_, sizeof(flagAreaRefreshFlag_));
     881            0 :     CHK_RET(HcclD2DMemcpyAsync(dispatcher_, refreshFlagDst, refreshFlagSrc, mainStream_));
     882              : 
     883            0 :     CHK_RET(LaunchTask(dispatcher_, mainStream_));
     884              : 
     885            0 :     HCCL_INFO(
     886              :         "[AlltoallvContinuousPipeline][DoLocalWriteInfoAndFlagAndInterSync] write counts and flag. userRank[%u], "
     887              :         "infoPtr[%p], infoSize[%llu], infoOffset[%llu]",
     888              :         userRank_, infoPtr, infoSize, infoOffset);
     889            0 :     return HCCL_SUCCESS;
     890            0 : }
     891              : 
     892            0 : HcclResult AlltoallvContinuousPipeline::WaitValueOfRank(const u32 rank, const HcclUs& startTimeUs, u32& value)
     893              : {
     894            0 :     const auto* valuePtr = reinterpret_cast<u32*>(static_cast<u8*>(inBuffer_.ptr()) + infoOffsets_[0]) + rank;
     895            0 :     HcclUs lastUt = startTimeUs;
     896            0 :     constexpr s64 timeout = 1800 * 1000 * 1000;          // 超时时间暂定为1800s
     897            0 :     constexpr s64 printStateInterval = 30 * 1000 * 1000; // 每隔30s打印一次状态
     898            0 :     HCCL_DEBUG(
     899              :         "[AlltoallvContinuousPipeline][WaitValueOfRank] start waiting value of rank[%u], valuePtr[%p].", rank,
     900              :         valuePtr);
     901              : 
     902            0 :     while (flagAreaRefreshFlag_ == 0 || *valuePtr == 0) {
     903            0 :         const HcclUs currentUt = TIME_NOW();
     904              :         // 等待value过程,每隔30秒打印一次状态
     905            0 :         if (DURATION_US(currentUt - lastUt).count() > printStateInterval) {
     906            0 :             lastUt = currentUt;
     907            0 :             if (flagAreaRefreshFlag_ == 0) {
     908            0 :                 HCCL_RUN_INFO(
     909              :                     "[AlltoallvContinuousPipeline][WaitValueOfRank] The Previous task has not been completed."
     910              :                     " userRank[%u]",
     911              :                     userRank_);
     912              :             } else {
     913            0 :                 HCCL_RUN_INFO("[AlltoallvContinuousPipeline][WaitValueOfRank] waiting value of rank[%u]", rank);
     914              :             }
     915              :         }
     916              : 
     917            0 :         CHK_PRT_RET(
     918              :             DURATION_US(currentUt - startTimeUs).count() > timeout,
     919              :             HCCL_ERROR(
     920              :                 "[AlltoallvContinuousPipeline][WaitValueOfRank] Waiting for the value of rank[%u] timed out.", rank),
     921              :             HCCL_E_TIMEOUT);
     922              :     }
     923            0 :     value = *valuePtr;
     924              : 
     925              :     // 每次执行算子开头都有重置flag区域的task,所以此处不需要重置为0
     926              : 
     927            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][WaitValueOfRank] Got value of rank[%u], value[%u].", rank, value);
     928            0 :     return HCCL_SUCCESS;
     929              : }
     930              : 
     931            0 : HcclResult AlltoallvContinuousPipeline::WaitAndCalReceiveInfo()
     932              : {
     933              :     // 计算自己以及module内其他卡的receive count
     934            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][WaitAndCalReceiveInfo] start.");
     935            0 :     const HcclUs startUt = TIME_NOW();
     936              : 
     937            0 :     for (u32 intraRankIdx = 0; intraRankIdx < intraRankSize_; ++intraRankIdx) {
     938            0 :         if (intraRankIdx == intraRankId_) {
     939            0 :             continue;
     940              :         }
     941            0 :         const u32 remoteRank = interRankId_ * intraRankSize_ + intraRankIdx;
     942            0 :         u32 remoteValue = 0;
     943            0 :         CHK_RET(WaitValueOfRank(remoteRank, startUt, remoteValue));
     944              : 
     945            0 :         const auto* countsPtr = reinterpret_cast<u64*>(static_cast<u8*>(outBuffer_.ptr()) + infoOffsets_[remoteRank]);
     946            0 :         HCCL_DEBUG(
     947              :             "[AlltoallvContinuousPipeline][WaitAndCalReceiveInfo] remoteRank[%u], infoOffset[%llu], "
     948              :             "countsPtr[%p]",
     949              :             remoteRank, infoOffsets_[remoteRank], countsPtr);
     950              : 
     951            0 :         for (u32 i = 0; i < userRankSize_; ++i) {
     952            0 :             HCCL_DEBUG("[AlltoallvContinuousPipeline][WaitAndCalReceiveInfo] countsPtr[%u]=[%llu]", i, countsPtr[i]);
     953            0 :             intraRecvCounts_[intraRankIdx][i] = countsPtr[i];
     954              :         }
     955              : 
     956            0 :         const u32 remoteLoopNum = remoteValue - 1; // remoteValue一定大于0
     957            0 :         intraLoopNum_ = std::max(intraLoopNum_, remoteLoopNum);
     958            0 :         HCCL_DEBUG(
     959              :             "[AlltoallvContinuousPipeline][WaitAndCalReceiveInfo] remoteRank[%u], remoteLoopNum[%u], "
     960              :             "intraLoopNum_[%u]",
     961              :             remoteRank, remoteLoopNum, intraLoopNum_);
     962              :     }
     963              : 
     964            0 :     HCCL_DEBUG("[AlltoallvContinuousPipeline][WaitAndCalReceiveInfo] done. loopNum[%u]", intraLoopNum_);
     965            0 :     return HCCL_SUCCESS;
     966              : }
     967              : 
     968            0 : HcclResult AlltoallvContinuousPipeline::RunAsync()
     969              : {
     970              :     // 在开始前,先将counts信息拷贝到info区域,并且刷新一下flag区域
     971            0 :     CHK_RET(DoLocalWriteInfoAndFlagAndInterSync());
     972              : 
     973              :     // 按照机间pairwise的方式计算每轮的步数,等于level1的rank size - 1
     974            0 :     const u32 stepsPerLoop = interRankSize_ - 1;
     975              : 
     976              :     // 需要发给其他module的每块数据都会经历三步:本地拷贝至in buffer、经RDMA链路发送到同号卡、由同号卡用SDMA分发到接收卡
     977            0 :     TaskState localCopyState;
     978            0 :     TaskState interState;
     979            0 :     TaskState intraState;
     980              : 
     981            0 :     localCopyState.stepNumNext = std::min(rdmaConcurrentNum_, stepsPerLoop);
     982              : 
     983              :     // 外层loop,要重复多少轮,默认为0,在获取到全局counts信息后刷新
     984            0 :     u32 repeatLoopNum = 0;
     985              : 
     986              :     // 第一步,需要把counts信息广播给机内其他rank
     987            0 :     bool needDoIntraInfoBroadcast = needCollectInfo_;
     988              : 
     989            0 :     while (localCopyState.stepNum < stepsPerLoop || interState.stepNum < stepsPerLoop
     990            0 :            || intraState.stepNum < stepsPerLoop) {
     991              :         // 每一轮首次做跨module收发的同时,做level0的SDMA写,每张卡从input写到对端的out buffer
     992            0 :         const bool needDoLevel0SdmaWrite = (interState.stepNumNext != 0 && interState.stepNum == 0);
     993              :         // 每一轮首次做机内分发的同时,每张卡从out buffer将level0其他卡发来的数据拷至output
     994            0 :         const bool needDoLevel0LocalCopy = (intraState.stepNumNext != 0 && intraState.stepNum == 0);
     995              : 
     996              :         // intra的stepNum小于stepNumNext,说明本轮需要做intra分发(SDMA)
     997            0 :         const bool needDoIntraTasks = intraState.stepNum < intraState.stepNumNext;
     998              :         // inter的stepNum小于stepNumNext,说明本轮需要做inter收发(RDMA)
     999            0 :         const bool needDoInterTasks = interState.stepNum < interState.stepNumNext;
    1000              : 
    1001            0 :         const bool hasSdmaTask = needDoIntraTasks || needDoLevel0SdmaWrite || needDoIntraInfoBroadcast;
    1002            0 :         const bool hasRdmaTask = needDoInterTasks;
    1003              : 
    1004            0 :         HCCL_DEBUG(
    1005              :             "[AlltoallvContinuousPipeline][RunAsyncLoop][start] localCopy[step:%u, next:%u, loop:%u], "
    1006              :             "inter[step:%u, next:%u, loop:%u], intra[step:%u, next:%u, loop:%u]",
    1007              :             localCopyState.stepNum, localCopyState.stepNumNext, localCopyState.loopNum, interState.stepNum,
    1008              :             interState.stepNumNext, interState.loopNum, intraState.stepNum, intraState.stepNumNext, intraState.loopNum);
    1009              : 
    1010            0 :         HCCL_DEBUG(
    1011              :             "[AlltoallvContinuousPipeline][RunAsyncLoop] needDoLevel0SdmaWrite[%d], needDoLevel0LocalCopy[%d], "
    1012              :             "hasSdmaTask[%d], hasRdmaTask[%d]",
    1013              :             needDoLevel0SdmaWrite, needDoLevel0LocalCopy, hasSdmaTask, hasRdmaTask);
    1014              : 
    1015            0 :         if (hasSdmaTask) {
    1016              :             // 本轮有SDMA任务。主流通知SDMA从流,SDMA从流等待主流,前同步
    1017            0 :             CHK_RET(NotifySdmaSubStreamStart());
    1018            0 :             CHK_RET(DoSdmaSync(SdmaSyncType::PRE_SYNC));
    1019              : 
    1020              :             // 下发一组主从流同步,拉齐SDMA任务,避免任务不同时拉起导致性能下降
    1021            0 :             CHK_RET(WaitSdmaSubStreamFinish());
    1022            0 :             CHK_RET(NotifySdmaSubStreamStart());
    1023              :         }
    1024              : 
    1025            0 :         if (hasRdmaTask) {
    1026              :             // 本轮有RDMA任务。主流通知RDMA从流,RDMA从流等待主流
    1027            0 :             CHK_RET(NotifyRdmaSubStreamStart());
    1028              :         }
    1029              : 
    1030            0 :         if (needDoLevel0SdmaWrite) {
    1031            0 :             CHK_RET(DoLevel0SdmaSend(interState.loopNum));
    1032              : 
    1033            0 :             if (interState.loopNum == 0) {
    1034              :                 // 首轮,本卡input到output的拷贝也在这时做
    1035            0 :                 CHK_RET(LocalCopySelfDataFromInputToOutput(mainStream_));
    1036              :             }
    1037              :         }
    1038              : 
    1039            0 :         if (interState.loopNum == 0 && needDoInterTasks) {
    1040              :             // 第一轮,在做inter分发前,等待、获取receive信息
    1041            0 :             if (needCollectInfo_) {
    1042            0 :                 CHK_RET(WaitAndCalReceiveInfo()); // 阻塞函数
    1043            0 :                 needCollectInfo_ = false;
    1044              :             }
    1045              : 
    1046              :             // 刷新重复轮数:总轮数-1
    1047            0 :             repeatLoopNum = intraLoopNum_ > 0 ? intraLoopNum_ - 1 : 0;
    1048            0 :             if (localCopyState.stepNum == stepsPerLoop && localCopyState.loopNum < repeatLoopNum) {
    1049              :                 // 如果需要做多轮,在此处立即刷新local copy stepNum,让第二轮的任务尽早开始
    1050            0 :                 ++localCopyState.loopNum;
    1051            0 :                 localCopyState.stepNum = 0;
    1052            0 :                 localCopyState.stepNumNext = std::min(rdmaConcurrentNum_, stepsPerLoop);
    1053              :             }
    1054              :         }
    1055              : 
    1056              :         // intraStepNum小于interStepNum,表示需要做机内分发
    1057            0 :         CHK_RET(DoIntraDistribution(intraState.stepNum, intraState.stepNumNext, intraState.loopNum));
    1058              :         // interStepNum小于localCopyStepNum,表示需要做机间收发
    1059            0 :         CHK_RET(DoInterSendReceive(interState.stepNum, interState.stepNumNext, interState.loopNum));
    1060              :         // localCopyStepNum小于stepsPerLoop,根据并发度拷贝需要的数据到in buffer
    1061            0 :         CHK_RET(DoLocalCopy(localCopyState.stepNum, localCopyState.stepNumNext, localCopyState.loopNum));
    1062              : 
    1063            0 :         if (needDoIntraInfoBroadcast) {
    1064              :             // 第一轮第一步,机内广播本卡的counts信息
    1065            0 :             CHK_RET(DoIntraInfoBroadcast());
    1066            0 :             needDoIntraInfoBroadcast = false;
    1067              :         }
    1068              : 
    1069            0 :         if (needDoLevel0LocalCopy) {
    1070            0 :             CHK_RET(DoLevel0LocalCopy(intraState.loopNum));
    1071              :         }
    1072              : 
    1073            0 :         if (hasSdmaTask) {
    1074              :             // SDMA尾同步,主流等待SDMA从流,SDMA从流通知主流
    1075            0 :             CHK_RET(DoSdmaSync(SdmaSyncType::POST_SYNC));
    1076            0 :             CHK_RET(WaitSdmaSubStreamFinish());
    1077              :         }
    1078            0 :         if (hasRdmaTask) {
    1079              :             // 主流等待RDMA从流,RDMA从流通知主流
    1080            0 :             CHK_RET(WaitRdmaSubStreamFinish());
    1081              :         }
    1082              : 
    1083              :         // 下发task
    1084            0 :         CHK_RET(LaunchTaskExtend(dispatcher_, mainStream_, subStreams_));
    1085              : 
    1086              :         // 更新每种任务的当前步数
    1087            0 :         intraState.stepNum = intraState.stepNumNext;
    1088            0 :         interState.stepNum = interState.stepNumNext;
    1089            0 :         localCopyState.stepNum = localCopyState.stepNumNext;
    1090              : 
    1091              :         // 更新每种任务的下一步目标步数
    1092            0 :         intraState.stepNumNext = interState.stepNumNext;
    1093            0 :         interState.stepNumNext = localCopyState.stepNumNext;
    1094            0 :         localCopyState.stepNumNext = std::min(localCopyState.stepNumNext + rdmaConcurrentNum_, stepsPerLoop);
    1095              : 
    1096              :         // 检查是否需要重复执行,若需要,将对应的step num刷回为0
    1097            0 :         if (intraState.stepNum == stepsPerLoop && intraState.loopNum < interState.loopNum) {
    1098            0 :             ++intraState.loopNum;
    1099            0 :             intraState.stepNum = 0;
    1100            0 :             intraState.stepNumNext = std::min(rdmaConcurrentNum_, stepsPerLoop);
    1101              :         }
    1102            0 :         if (interState.stepNum == stepsPerLoop && interState.loopNum < localCopyState.loopNum) {
    1103            0 :             ++interState.loopNum;
    1104            0 :             interState.stepNum = 0;
    1105            0 :             interState.stepNumNext = std::min(rdmaConcurrentNum_, stepsPerLoop);
    1106              :         }
    1107            0 :         if (localCopyState.stepNum == stepsPerLoop && localCopyState.loopNum < repeatLoopNum) {
    1108            0 :             ++localCopyState.loopNum;
    1109            0 :             localCopyState.stepNum = 0;
    1110            0 :             localCopyState.stepNumNext = std::min(rdmaConcurrentNum_, stepsPerLoop);
    1111              :         }
    1112              : 
    1113            0 :         HCCL_DEBUG(
    1114              :             "[AlltoallvContinuousPipeline][RunAsyncLoop][end] localCopy[step:%u, next:%u, loop:%u], "
    1115              :             "inter[step:%u, next:%u, loop:%u], intra[step:%u, next:%u, loop:%u]",
    1116              :             localCopyState.stepNum, localCopyState.stepNumNext, localCopyState.loopNum, interState.stepNum,
    1117              :             interState.stepNumNext, interState.loopNum, intraState.stepNum, intraState.stepNumNext, intraState.loopNum);
    1118              :     }
    1119            0 :     return HCCL_SUCCESS;
    1120              : }
    1121              : 
    1122              : REGISTER_TEMPLATE(TemplateType::TEMPLATE_ALL_2_ALL_V_CONTINUOUS_PIPELINE, AlltoallvContinuousPipeline);
    1123              : } // namespace hccl
        

Generated by: LCOV version 2.0-1