LCOV - code coverage report
Current view: top level - coll_communicator_mgr/communicator/group_schedule_mgr - group_schedule_mgr.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 81.8 % 165 135
Test Date: 2026-08-17 10:19:35 Functions: 100.0 % 15 15

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2026 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              : #include "group_schedule_mgr.h"
      11              : #include "log.h"
      12              : #include "coll_alg_utils.h"
      13              : #include "hccl_comm_pub.h"
      14              : 
      15              : thread_local int32_t hcclP2pTaskNums;
      16              : thread_local std::vector<HcclComm> hcclGroupCommListV2;
      17              : 
      18              : constexpr uint32_t NUM = 1U;
      19              : constexpr uint32_t BIT_MAX = 31U;
      20              : 
      21              : namespace {
      22            1 : uint32_t pow2Up(uint32_t n)
      23              : {
      24            1 :     if (n > (NUM << BIT_MAX)) {
      25            0 :         return 0;
      26              :     }
      27              : 
      28            1 :     uint32_t power = 1;
      29            2 :     while (power < n) {
      30            1 :         power = power << 1U;
      31              :     }
      32            1 :     return power;
      33              : }
      34              : } // namespace
      35              : 
      36              : namespace hccl {
      37              : 
      38            2 : void ClearHcclGroupCommList() { hcclGroupCommListV2.clear(); }
      39              : 
      40           54 : std::vector<HcclComm>& GetHcclGroupCommList() { return hcclGroupCommListV2; }
      41              : 
      42            3 : int32_t GetHcclP2pTaskNums() { return hcclP2pTaskNums; }
      43              : 
      44           54 : void SetHcclP2pTaskNums(int32_t targetP2pTaskNums) { hcclP2pTaskNums = targetP2pTaskNums; }
      45              : 
      46          215 : GroupScheduleMgr::~GroupScheduleMgr() {}
      47              : 
      48            3 : HcclResult GroupScheduleMgr::GetUsrStream(aclrtStream& usrStream)
      49              : {
      50            3 :     CHK_PTR_NULL(this->usrStream_);
      51            2 :     usrStream = this->usrStream_;
      52            2 :     return HCCL_SUCCESS;
      53              : }
      54              : 
      55            4 : HcclResult GroupScheduleMgr::SetUsrStream(const aclrtStream& usrStream)
      56              : {
      57            4 :     CHK_PTR_NULL(usrStream);
      58            3 :     this->usrStream_ = usrStream;
      59            3 :     return HCCL_SUCCESS;
      60              : }
      61              : 
      62            1 : HcclResult GroupScheduleMgr::InitGroupPlanner(HcclComm comm)
      63              : {
      64            1 :     CHK_PTR_NULL(comm);
      65            1 :     hccl::hcclComm* hcclComm = static_cast<hccl::hcclComm*>(comm);
      66            1 :     CHK_PTR_NULL(hcclComm);
      67            1 :     hccl::CollComm* collComm = hcclComm->GetCollComm();
      68            1 :     CHK_PTR_NULL(collComm);
      69            1 :     constexpr uint32_t netLayerServer = 0;
      70            1 :     uint32_t* serverSizeList = nullptr;
      71            1 :     uint32_t serverNum = 0;
      72            1 :     CHK_RET(HcclRankGraphGetInstSizeListByLayer(comm, netLayerServer, &serverSizeList, &serverNum));
      73            1 :     CHK_PTR_NULL(serverSizeList);
      74            1 :     this->userRank_ = collComm->GetMyRankId();
      75            1 :     this->rankSize_ = collComm->GetRankSize();
      76            1 :     this->nTasksP2p_ = 0;
      77            1 :     this->serverNum_ = serverNum;
      78            5 :     for (uint32_t serverIdx = 0, rankIdx = 0; serverIdx < serverNum; serverIdx++) {
      79            4 :         this->serverToRankSize_[serverIdx] = serverSizeList[serverIdx];
      80           12 :         for (uint32_t localIdx = 0; localIdx < serverSizeList[serverIdx]; localIdx++) {
      81            8 :             this->serverToRankList_[serverIdx].emplace_back(rankIdx++);
      82              :         }
      83              :     }
      84            1 :     HCCL_INFO(
      85              :         "[InitGroupPlanner] ranksize:%u, serverNum:%u nTaskP2p:%d", this->rankSize_, this->serverNum_,
      86              :         this->nTasksP2p_);
      87              : 
      88            1 :     return HCCL_SUCCESS;
      89              : }
      90              : 
      91            1 : HcclResult GroupScheduleMgr::GetCurLocalRank(uint32_t& localRank)
      92              : {
      93            1 :     uint32_t curServerIdx = 0;
      94            1 :     for (uint32_t cumulativeRank = 0, serverIdx = 0; serverIdx < this->serverNum_; serverIdx++) {
      95            1 :         cumulativeRank += this->serverToRankSize_.at(serverIdx);
      96            1 :         if (this->userRank_ < cumulativeRank) {
      97            1 :             curServerIdx = serverIdx;
      98            1 :             break;
      99              :         }
     100              :     }
     101              : 
     102            1 :     u32 curLocalRank = 0;
     103            1 :     for (u32 rankIdx : this->serverToRankList_.at(curServerIdx)) {
     104            1 :         if (this->userRank_ == rankIdx) {
     105            1 :             break;
     106              :         }
     107            0 :         curLocalRank++;
     108              :     }
     109              : 
     110            1 :     if (curLocalRank >= this->serverToRankSize_.at(curServerIdx)) {
     111            0 :         HCCL_ERROR("[getCurLocalRank] is invalid:%u", curLocalRank);
     112            0 :         return HCCL_E_INTERNAL;
     113              :     }
     114              : 
     115            1 :     localRank = curLocalRank;
     116            1 :     return HCCL_SUCCESS;
     117              : }
     118              : 
     119            1 : HcclResult GroupScheduleMgr::CalculateGroupSize()
     120              : {
     121            1 :     if (this->serverNum_ == 0) {
     122            0 :         return HCCL_E_INTERNAL;
     123              :     }
     124              : 
     125            1 :     if (this->serverNum_ == 1) {
     126            0 :         this->groupSize_ = this->rankSize_;
     127            0 :         return HCCL_SUCCESS;
     128              :     }
     129              : 
     130            1 :     std::vector<uint32_t> serverRankSizeList;
     131            5 :     for (const auto& pair : this->serverToRankSize_) {
     132            4 :         serverRankSizeList.emplace_back(pair.second);
     133              :     }
     134            1 :     this->groupSize_ = hccl::CalGCD(serverRankSizeList);
     135            1 :     return HCCL_SUCCESS;
     136            1 : }
     137              : 
     138            1 : uint32_t GroupScheduleMgr::GenerateP2pSchedule(
     139              :     const std::vector<uint32_t>& groupToServer, const std::vector<uint32_t>& groupToLocalRankBase, uint32_t curGroupIdx,
     140              :     uint32_t curGroupLocalRankIdx)
     141              : {
     142            1 :     this->p2pSchedule_.resize(this->rankSize_);
     143            1 :     uint32_t round = 0;
     144            1 :     uint32_t groupRound = 0;
     145            1 :     uint32_t groupDelta = 0;
     146            1 :     uint32_t nGroupsPow2 = pow2Up(this->nGroups_);
     147            1 :     if (nGroupsPow2 == 0) {
     148            0 :         return 0;
     149              :     }
     150              : 
     151              :     do {
     152            2 :         if (groupDelta < this->nGroups_) {
     153            2 :             uint32_t sendGroupIdx = (curGroupIdx + groupDelta) % this->nGroups_;
     154            2 :             uint32_t recvGroupIdx = (curGroupIdx - groupDelta + this->nGroups_) % this->nGroups_;
     155            2 :             uint32_t sendServerIdx = groupToServer[sendGroupIdx];
     156            2 :             uint32_t recvServerIdx = groupToServer[recvGroupIdx];
     157              : 
     158            6 :             for (uint32_t delta = 0; delta < this->groupSize_; delta++) {
     159              :                 uint32_t sendLocalIdx
     160            4 :                     = groupToLocalRankBase[sendGroupIdx] + (curGroupLocalRankIdx + delta) % this->groupSize_;
     161            4 :                 uint32_t recvLocalIdx = groupToLocalRankBase[recvGroupIdx]
     162            4 :                                         + (curGroupLocalRankIdx - delta + this->groupSize_) % this->groupSize_;
     163              : 
     164            4 :                 this->p2pSchedule_[round].sendRank = this->serverToRankList_.at(sendServerIdx)[sendLocalIdx];
     165            4 :                 this->p2pSchedule_[round].recvRank = this->serverToRankList_.at(recvServerIdx)[recvLocalIdx];
     166            4 :                 round++;
     167              :             }
     168              :         }
     169            2 :         groupRound++;
     170            2 :         groupDelta = (groupDelta + groupRound) & (nGroupsPow2 - 1);
     171            2 :     } while (groupRound != nGroupsPow2);
     172              : 
     173            1 :     return round;
     174              : }
     175              : 
     176            1 : HcclResult GroupScheduleMgr::HcclP2pSchedulerGenerate()
     177              : {
     178            1 :     uint32_t curLocalRank = 0; // 当前rank所在server的局部排序号
     179            1 :     CHK_RET(GetCurLocalRank(curLocalRank));
     180            1 :     CHK_RET(CalculateGroupSize());
     181            1 :     if (this->groupSize_ == 0) {
     182            0 :         HCCL_ERROR("[HcclP2pSchedulerGenerate] groupSize is zero");
     183            0 :         return HCCL_E_INTERNAL;
     184              :     }
     185              : 
     186            1 :     uint32_t curGroupLocalRankIdx = curLocalRank % this->groupSize_;
     187            1 :     uint32_t curGroupIdx = this->userRank_ / this->groupSize_;
     188            1 :     this->nGroups_ = this->rankSize_ / this->groupSize_;
     189            1 :     HCCL_INFO(
     190              :         "[HcclP2pSchedulerGenerate] userRank:%u, localRank:%u, groupSize:%u, nGroups:%u", this->userRank_, curLocalRank,
     191              :         this->groupSize_, this->nGroups_);
     192              : 
     193            2 :     std::vector<uint32_t> groupToServer(this->nGroups_);
     194            1 :     std::vector<uint32_t> groupToLocalRankBase(this->nGroups_);
     195            1 :     uint32_t groupIdx = 0;
     196            5 :     for (const auto& pair : this->serverToRankList_) {
     197            4 :         uint32_t serverIdx = pair.first;
     198            4 :         uint32_t localRankSize = this->serverToRankSize_.at(serverIdx);
     199            4 :         uint32_t localGroupSize = localRankSize / this->groupSize_;
     200            8 :         for (uint32_t localGroupIdx = 0; localGroupIdx < localGroupSize; localGroupIdx++) {
     201            4 :             groupToServer[groupIdx] = serverIdx;
     202            4 :             groupToLocalRankBase[groupIdx] = localGroupIdx * this->groupSize_;
     203            4 :             groupIdx++;
     204              :         }
     205              :     }
     206              : 
     207            1 :     uint32_t round = GenerateP2pSchedule(groupToServer, groupToLocalRankBase, curGroupIdx, curGroupLocalRankIdx);
     208            1 :     if (this->rankSize_ != round) {
     209            0 :         HCCL_ERROR("[HcclP2pSchedulerGenerate] round:%u is not equal to rankSize:%u", round, this->rankSize_);
     210            0 :         return HCCL_E_INTERNAL;
     211              :     }
     212              : 
     213            1 :     HCCL_INFO("[HcclP2pSchedulerGenerate] schedule generated, round:%u", round);
     214            1 :     return HCCL_SUCCESS;
     215            1 : }
     216              : 
     217            3 : HcclResult GroupScheduleMgr::AppendGroupP2pTask(HcclComm comm, const HcclP2pTask& task, const HcclOpP2pDesc& p2pDesc)
     218              : {
     219            3 :     CHK_PTR_NULL(comm);
     220            2 :     if (hcclP2pTaskNums == MAX_P2P_TASK_NUM) {
     221            1 :         HCCL_ERROR("[hcclGroupAddP2pTask] P2pTaskNums is out of %d", MAX_P2P_TASK_NUM);
     222            1 :         return HCCL_E_INTERNAL;
     223              :     }
     224            1 :     if (this->nTasksP2p_ == -1) {
     225            1 :         CHK_RET(InitGroupPlanner(comm));
     226            1 :         CHK_RET(HcclP2pSchedulerGenerate());
     227            1 :         this->peers_.resize(this->rankSize_);
     228              :     }
     229              : 
     230            1 :     if (p2pDesc.cmdType == HcclCMDType::HCCL_CMD_SEND) {
     231            1 :         this->peers_[p2pDesc.remoteRank].sendQue.emplace_back(task);
     232              :     } else {
     233            0 :         this->peers_[p2pDesc.remoteRank].recvQue.emplace_back(task);
     234              :     }
     235            1 :     this->nTasksP2p_ += 1;
     236            1 :     hcclP2pTaskNums++;
     237            1 :     auto itComm = std::find(hcclGroupCommListV2.begin(), hcclGroupCommListV2.end(), comm);
     238            1 :     if (itComm == hcclGroupCommListV2.end()) {
     239            1 :         hcclGroupCommListV2.emplace_back(comm);
     240              :     }
     241              : 
     242            1 :     return HCCL_SUCCESS;
     243              : }
     244              : 
     245              : HcclResult
     246            1 : GroupScheduleMgr::GetP2pTaskSchedule(std::vector<HcclP2pTask>& sortedSendQue, std::vector<HcclP2pTask>& sortedRecvQue)
     247              : {
     248            1 :     HCCL_INFO("[HcclP2pTaskSchedule] nTaskP2p:%d", this->nTasksP2p_);
     249              : 
     250            1 :     uint32_t epoch = 0;
     251            1 :     uint32_t maxEpochNum = this->nTasksP2p_;
     252            1 :     while (this->nTasksP2p_ > 0) {
     253            0 :         for (uint32_t round = 0; round < this->rankSize_; round++) {
     254            0 :             uint32_t sendRank = this->p2pSchedule_[round].sendRank;
     255            0 :             uint32_t recvRank = this->p2pSchedule_[round].recvRank;
     256              : 
     257            0 :             if (!this->peers_[sendRank].sendQue.empty()) {
     258            0 :                 auto& sendTask = this->peers_[sendRank].sendQue.front();
     259            0 :                 sortedSendQue.emplace_back(sendTask);
     260            0 :                 this->peers_[sendRank].sendQue.pop_front();
     261            0 :                 this->nTasksP2p_--;
     262              :             }
     263              : 
     264            0 :             if (!this->peers_[recvRank].recvQue.empty()) {
     265            0 :                 auto& recvTask = this->peers_[recvRank].recvQue.front();
     266            0 :                 sortedRecvQue.emplace_back(recvTask);
     267            0 :                 this->peers_[recvRank].recvQue.pop_front();
     268            0 :                 this->nTasksP2p_--;
     269              :             }
     270              :         }
     271              : 
     272            0 :         epoch++;
     273            0 :         if (epoch > maxEpochNum) {
     274            0 :             HCCL_ERROR("[GetP2pTaskSchedule] epoch:%u is more than max epoch:%u", epoch, maxEpochNum);
     275            0 :             return HCCL_E_INTERNAL;
     276              :         }
     277              :     }
     278            1 :     HCCL_INFO(
     279              :         "[HcclP2pTaskSchedule] done, use epochs:%u, sendQueSize:%u, recvQueSize:%u ", epoch,
     280              :         static_cast<uint32_t>(sortedSendQue.size()), static_cast<uint32_t>(sortedRecvQue.size()));
     281              : 
     282            1 :     return HCCL_SUCCESS;
     283              : }
     284              : } // namespace hccl
        

Generated by: LCOV version 2.0-1