LCOV - code coverage report
Current view: top level - legacy/ascend950/service/collective/alg/coll_alg_factory/alg_topo_match - topo_match_concurr_mesh_nhr.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 161 0
Test Date: 2026-08-18 17:47:01 Functions: 0.0 % 9 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 "topo_match_concurr_mesh_nhr.h"
      12              : 
      13              : namespace Hccl {
      14            0 : TopoMatchConcurrMeshNHR::TopoMatchConcurrMeshNHR(
      15            0 :     const RankId vRank, const u32 rankSize, const RankGraph* rankGraph, const DevType devType)
      16            0 :     : TopoMatchBase(vRank, rankSize, rankGraph, devType)
      17            0 : {}
      18              : 
      19            0 : TopoMatchConcurrMeshNHR::~TopoMatchConcurrMeshNHR() {}
      20              : 
      21            0 : HcclResult TopoMatchConcurrMeshNHR::MatchTopo(
      22              :     std::vector<std::vector<std::vector<RankId>>>& vTopo, std::vector<std::vector<RankId>>& virtRanks,
      23              :     std::vector<std::map<RankId, u32>>& virtRankMap)
      24              : {
      25              :     // 获取并校验当前通信层数
      26            0 :     std::set<u32> levelSet = rankGraph_->GetLevels(myRank_);
      27            0 :     CHK_PRT_RET(
      28              :         (levelSet.size() < COMM_LEVEL_SIZE_2),
      29              :         HCCL_ERROR(
      30              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Invalid virtual topo. levelSet[%u]", myRank_,
      31              :             levelSet.size()),
      32              :         HcclResult::HCCL_E_PARA);
      33              : 
      34            0 :     rankGraph_->Dump();
      35              : 
      36              :     // 获取 level0 Pod Topo 信息
      37            0 :     const NetInstance* netInstance = rankGraph_->GetNetInstanceByRankId(0, myRank_);
      38            0 :     if (netInstance == nullptr) {
      39            0 :         HCCL_ERROR("TopoMatchConcurrMeshNHR::MatchTopo netInstance is nullptr");
      40            0 :         return HcclResult::HCCL_E_PTR;
      41              :     }
      42            0 :     const u32 rankSizeLevel0 = netInstance->GetRankSize();
      43            0 :     std::set<RankId> rankSetLevel0 = netInstance->GetRankIds();
      44              : 
      45              :     // 校验 level0 Pod Topo 是否符合 m x n 要求
      46            0 :     CHK_RET(CalcRankOnSamePlaneOfR0(rankOnSameBoardVector_, rankOnSameSlotVector_, numRanksPerBoard_));
      47            0 :     const auto minmaxPair = std::minmax_element(numRanksPerBoard_.begin(), numRanksPerBoard_.end());
      48            0 :     u32 minNumRankPerBoard = *minmaxPair.first;
      49            0 :     u32 maxNumRankPerBoard = *minmaxPair.second;
      50            0 :     CHK_PRT_RET(
      51              :         (minNumRankPerBoard != maxNumRankPerBoard),
      52              :         HCCL_ERROR(
      53              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Invalid virtual topo for "
      54              :             "multi-dimensional concurrent mesh, min numRanksPerBoard_[%u], max numRanksPerBoard_[%u].",
      55              :             myRank_, minNumRankPerBoard, maxNumRankPerBoard),
      56              :         HcclResult::HCCL_E_PARA);
      57              : 
      58            0 :     CHK_PRT_RET(
      59              :         ((rankSize_ == 1) || (numRanksPerBoard_[0] * numRanksPerBoard_.size() != rankSizeLevel0)),
      60              :         HCCL_ERROR(
      61              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Invalid virtual topo for "
      62              :             "multi-dimensional concurrent mesh algorithm with rankSize [%u], rankSizeLevel0 [%u], "
      63              :             "ranksPerBoard [%u], ranksPerSlot [%u].",
      64              :             myRank_, rankSize_, rankSizeLevel0, numRanksPerBoard_[0], numRanksPerBoard_.size()),
      65              :         HcclResult::HCCL_E_PARA);
      66              : 
      67              :     // 在全局视角下计算 level0 sub-communicator size
      68            0 :     std::vector<u32> instSizeList;                             // rank num on each pod
      69              :     u32 listSize;                                              // pod num
      70            0 :     rankGraph_->GetNetInstanceList(0, instSizeList, listSize); // global view
      71            0 :     HCCL_DEBUG(
      72              :         "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], instSizeList[%u]=[%s]", myRank_, instSizeList.size(),
      73              :         PrintVector<u32>(instSizeList).c_str());
      74              : 
      75            0 :     if (!CheckSymmetric(instSizeList)) {
      76              :         // 非对称情形
      77            0 :         HCCL_DEBUG("[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Asymmetric MatchTopo.", myRank_);
      78            0 :         u32 gcdInstSize = GcdMultiple(instSizeList);
      79              : 
      80              :         // 计算 level 0 子通信域
      81            0 :         CHK_RET(GenerateLevel0(rankSetLevel0, gcdInstSize, myRank_, vTopo, virtRanks));
      82              : 
      83              :         // 计算 level 1 子通信域
      84            0 :         const NetInstance* netInstanceL1 = rankGraph_->GetNetInstanceByRankId(1, myRank_);
      85            0 :         if (netInstanceL1 == nullptr) {
      86            0 :             HCCL_ERROR("TopoMatchConcurrMeshNHR::MatchTopo netInstanceL1 is nullptr");
      87            0 :             return HcclResult::HCCL_E_PTR;
      88              :         }
      89            0 :         std::set<RankId> rankSetLevel1 = netInstanceL1->GetRankIds();
      90              : 
      91            0 :         CHK_RET(GenerateLevel1(rankSetLevel1, gcdInstSize, myRank_, vTopo, virtRanks));
      92              : 
      93            0 :         HCCL_DEBUG(
      94              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], level0 & level1 virtRanks=[%s] ", myRank_,
      95              :             PrintMatrix<RankId>(virtRanks).c_str());
      96            0 :         HCCL_DEBUG(
      97              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], level0 & level1 vTopo=[%s] ", myRank_,
      98              :             PrintTensor<RankId>(vTopo).c_str());
      99            0 :     } else {
     100              :         // 对称情形
     101            0 :         HCCL_DEBUG("[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Symmetric MatchTopo.", myRank_);
     102              : 
     103            0 :         u32 myLocalId = rankGraph_->GetLocalId(myRank_);
     104            0 :         rankOnSameBoard_ = rankOnSameBoardVector_[myLocalId / RANK_SIZE_EIGHT];
     105            0 :         rankOnSameSlot_ = rankOnSameSlotVector_[myLocalId % RANK_SIZE_EIGHT];
     106            0 :         if ((rankOnSameBoard_.size() == 1) || (rankOnSameSlot_.size() == 1)) {
     107            0 :             HCCL_DEBUG(
     108              :                 "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], virtual topo with rankSize [%u], ranksPerBoard "
     109              :                 "[%u], ranksPerSlot [%u]. 1-D Mesh algorithm should be adopted.",
     110              :                 myRank_, rankSize_, rankOnSameBoard_.size(), rankOnSameSlot_.size());
     111              :         }
     112              : 
     113            0 :         sort(rankOnSameBoard_.begin(), rankOnSameBoard_.end());
     114            0 :         sort(rankOnSameSlot_.begin(), rankOnSameSlot_.end());
     115              : 
     116            0 :         Matrix<RankId> rankOnSamePod;
     117            0 :         rankOnSamePod.push_back(rankOnSameBoard_);
     118            0 :         rankOnSamePod.push_back(rankOnSameSlot_);
     119            0 :         vTopo.push_back(rankOnSamePod);
     120            0 :         virtRanks.push_back({rankSetLevel0.cbegin(), rankSetLevel0.cend()});
     121              : 
     122              :         // 获取 level1 Topo 信息
     123            0 :         const NetInstance* netInstanceL1 = rankGraph_->GetNetInstanceByRankId(1, myRank_);
     124            0 :         if (netInstanceL1 == nullptr) {
     125            0 :             HCCL_ERROR("TopoMatchConcurrMeshNHR::MatchTopo netInstanceL1 is nullptr");
     126            0 :             return HcclResult::HCCL_E_PTR;
     127              :         }
     128            0 :         std::set<RankId> rankSetLevel1 = netInstanceL1->GetRankIds();
     129              : 
     130              :         // 它要求 rankId 是连续的, 每隔 rankSizeLevel0 取一个
     131            0 :         CHK_RET(GenerateLevel1(rankSetLevel1, rankSizeLevel0, myRank_, vTopo, virtRanks));
     132              : 
     133            0 :         HCCL_DEBUG(
     134              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], level0 & level1 virtRanks=[%s] ", myRank_,
     135              :             PrintMatrix<RankId>(virtRanks).c_str());
     136            0 :         HCCL_DEBUG(
     137              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], level0 & level1 vTopo=[%s] ", myRank_,
     138              :             PrintTensor<RankId>(vTopo).c_str());
     139            0 :     }
     140              : 
     141              :     // 子通信域计算完毕, 生成 virtRankMap
     142            0 :     CHK_PRT_RET(
     143              :         GenVirtRankMappingMultiLevel(virtRanks, virtRankMap) != HcclResult::HCCL_SUCCESS,
     144              :         HCCL_ERROR("[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Fail to generate virtRankMapping.", myRank_),
     145              :         HcclResult::HCCL_E_INTERNAL);
     146              : 
     147            0 :     return HcclResult::HCCL_SUCCESS;
     148            0 : }
     149              : 
     150            0 : HcclResult TopoMatchConcurrMeshNHR::GenerateLevel0(
     151              :     const std::set<RankId>& rankSetLevel0, u32 gcdInstSize, RankId rankId,
     152              :     std::vector<std::vector<std::vector<RankId>>>& vTopo, std::vector<std::vector<RankId>>& virtRanks)
     153              : {
     154              :     // 获取 my pod size, 计算 level0 subcommunicator size
     155              :     (void)rankId;
     156            0 :     u32 dim0Size = numRanksPerBoard_.at(0);
     157            0 :     u32 gcdDim0Size = GcdTwo(gcdInstSize, dim0Size);
     158            0 :     u32 gcdDim1Size = gcdInstSize / gcdDim0Size;
     159              : 
     160              :     // 维数校验 (2D)
     161            0 :     CHK_PRT_RET(
     162              :         (gcdDim0Size == 1) || (gcdDim1Size == 1), // 1D case
     163              :         HCCL_ERROR(
     164              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Pod Topo Shape != 2D."
     165              :             "gcdDim0Size [%u], gcdDim1Size [%u]",
     166              :             myRank_, gcdDim0Size, gcdDim1Size),
     167              :         HcclResult::HCCL_E_PARA);
     168              : 
     169              :     // 判断 level 0 topo 是否满足 rankId 连续限制
     170            0 :     bool isRankIdContinue = true;
     171            0 :     if (gcdDim0Size < dim0Size && gcdDim1Size > 1) {
     172            0 :         isRankIdContinue = false;
     173              :     }
     174              : 
     175            0 :     if (!isRankIdContinue) {
     176            0 :         HCCL_ERROR("RankId [%d]. Checker does not support nhr + nhr algorithm validation.", myRank_);
     177            0 :         RankId minRankId = *rankSetLevel0.cbegin();
     178            0 :         RankId relRankId = myRank_ - minRankId;
     179            0 :         u32 groupId = relRankId / gcdInstSize;
     180              : 
     181            0 :         const u32 startOffset = groupId * gcdInstSize;
     182            0 :         const u32 totalSize = rankSetLevel0.size();
     183            0 :         auto startIt = rankSetLevel0.cbegin();
     184              :         std::advance(startIt, startOffset);
     185              : 
     186            0 :         const u32 elementsToTake = std::min(gcdInstSize, totalSize - startOffset);
     187            0 :         auto endIt = startIt;
     188              :         std::advance(endIt, elementsToTake);
     189              : 
     190            0 :         std::vector<RankId> level0Ranks = std::vector<RankId>(startIt, endIt);
     191            0 :         vTopo.push_back({level0Ranks});
     192            0 :         virtRanks.push_back(level0Ranks);
     193            0 :         return HcclResult::HCCL_SUCCESS;
     194            0 :     }
     195              : 
     196            0 :     std::vector<RankId> rankVecLevel0 = std::vector<RankId>(rankSetLevel0.cbegin(), rankSetLevel0.cend());
     197            0 :     Matrix<RankId> rankMatLevel0 = {};
     198            0 :     auto startIt = rankVecLevel0.cbegin();
     199            0 :     auto endIt = rankVecLevel0.cend();
     200            0 :     while (startIt != endIt) {
     201            0 :         auto currentEndIt = startIt;
     202            0 :         std::advance(currentEndIt, std::min(dim0Size, static_cast<u32>(std::distance(startIt, endIt))));
     203            0 :         rankMatLevel0.emplace_back(startIt, currentEndIt);
     204            0 :         startIt = currentEndIt;
     205              :     }
     206              : 
     207            0 :     std::vector<RankId> level0Ranks;
     208            0 :     Matrix<RankId> level0Topo;
     209            0 :     CHK_RET(FindLevel0Block(rankMatLevel0, gcdDim1Size, gcdDim0Size, myRank_, level0Ranks, level0Topo));
     210              : 
     211            0 :     CHK_PRT_RET(
     212              :         (level0Topo[0].size() != gcdDim0Size || level0Topo[1].size() != gcdDim1Size),
     213              :         HCCL_ERROR(
     214              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Invalid level0Topo size[%zu][%zu]", myRank_,
     215              :             level0Topo[0].size(), level0Topo[1].size()),
     216              :         HcclResult::HCCL_E_PARA);
     217            0 :     vTopo.push_back(level0Topo);
     218            0 :     virtRanks.push_back(level0Ranks);
     219              : 
     220            0 :     return HcclResult::HCCL_SUCCESS;
     221            0 : }
     222              : 
     223            0 : HcclResult TopoMatchConcurrMeshNHR::FindLevel0Block(
     224              :     const Matrix<RankId>& podTopo, u32 subDim0Size, u32 subDim1Size, u32 myRank, std::vector<RankId>& subRankList,
     225              :     Matrix<RankId>& subRankTopo) const
     226              : {
     227            0 :     CHK_PRT_RET(
     228              :         (podTopo.empty() || podTopo[0].empty() || subDim0Size == 0 || subDim1Size == 0),
     229              :         HCCL_ERROR("[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], empty podTopo or invalid subDim.", myRank_),
     230              :         HcclResult::HCCL_E_PARA);
     231            0 :     const u32 totalRows = podTopo.size();
     232            0 :     const u32 totalCols = podTopo[0].size();
     233            0 :     CHK_PRT_RET(
     234              :         (totalRows % subDim0Size != 0 || totalCols % subDim1Size != 0),
     235              :         HCCL_ERROR("[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], invalid subDim.", myRank_),
     236              :         HcclResult::HCCL_E_PARA);
     237              : 
     238            0 :     u32 targetRow = -1;
     239            0 :     u32 targetCol = -1;
     240            0 :     CHK_RET(FindMyRankLocation(podTopo, myRank, targetRow, targetCol)); // 查找 myRank 在 podTopo 中坐标
     241              : 
     242              :     // 计算 podTopo 块信息
     243            0 :     const u32 blockRow = targetRow / subDim0Size;
     244            0 :     const u32 blockCol = targetCol / subDim1Size;
     245              : 
     246              :     // 计算目标子块编号和起始索引
     247            0 :     const u32 startRow = blockRow * subDim0Size;
     248            0 :     const u32 startCol = blockCol * subDim1Size;
     249              : 
     250            0 :     CHK_RET(ExtractLevel0Block(
     251              :         podTopo, startRow, startCol, targetRow, targetCol, subDim0Size, subDim1Size, subRankList, subRankTopo));
     252              : 
     253            0 :     return HcclResult::HCCL_SUCCESS;
     254              : }
     255              : 
     256              : HcclResult
     257            0 : TopoMatchConcurrMeshNHR::FindMyRankLocation(const Matrix<RankId>& podTopo, u32 myRank, u32& row, u32& col) const
     258              : {
     259            0 :     row = -1;
     260            0 :     col = -1; // 初始化为非法值
     261            0 :     for (u32 r = 0; r < podTopo.size(); r++) {
     262            0 :         auto it = std::find(podTopo[r].cbegin(), podTopo[r].cend(), myRank);
     263            0 :         if (it != podTopo[r].cend()) {
     264            0 :             row = r;
     265            0 :             col = std::distance(podTopo[r].cbegin(), it);
     266            0 :             return HcclResult::HCCL_SUCCESS;
     267              :         }
     268              :     }
     269            0 :     return HcclResult::HCCL_E_PARA;
     270              : }
     271              : 
     272            0 : HcclResult TopoMatchConcurrMeshNHR::ExtractLevel0Block(
     273              :     const Matrix<RankId>& podTopo, u32 startRow, u32 startCol, u32 targetRow, u32 targetCol, u32 subDim0Size,
     274              :     u32 subDim1Size, std::vector<RankId>& subRankList, Matrix<RankId>& subRankTopo) const
     275              : {
     276            0 :     subRankList.clear();
     277            0 :     subRankList.reserve(subDim0Size * subDim1Size);
     278            0 :     subRankTopo.clear();
     279              : 
     280            0 :     const u32 targetRelRow = targetRow - startRow; // myRank 在子块中的相对行 = 绝对行 - 子块起始行
     281            0 :     const u32 targetRelCol = targetCol - startCol; // myRank 在子块中的相对列 = 绝对列 - 子块起始列
     282              : 
     283              :     // 校验相对行&列在 podTopo 范围内
     284            0 :     const u32 totalRows = podTopo.size();
     285            0 :     const u32 totalCols = podTopo[0].size();
     286            0 :     CHK_PRT_RET(
     287              :         targetRelRow >= totalRows,
     288              :         HCCL_ERROR(
     289              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Invalid targetRelRow[%u], "
     290              :             "totalRows[%u]",
     291              :             myRank_, targetRelRow, totalRows),
     292              :         HcclResult::HCCL_E_PARA);
     293            0 :     CHK_PRT_RET(
     294              :         targetRelCol >= totalCols,
     295              :         HCCL_ERROR(
     296              :             "[CollAlgFactory] [TopoMatchConcurrMeshNHR] Rank [%d], Invalid targetRelCol[%u], "
     297              :             "totalCols[%u]",
     298              :             myRank_, targetRelCol, totalCols),
     299              :         HcclResult::HCCL_E_PARA);
     300              : 
     301            0 :     std::vector<RankId> targetRowVec;
     302            0 :     std::vector<RankId> targetColVec;
     303            0 :     targetRowVec.reserve(subDim1Size);
     304            0 :     targetColVec.reserve(subDim0Size);
     305              : 
     306            0 :     auto matRowStartIt = podTopo.cbegin() + startRow; // 使用迭代器算术获取起始行迭代器
     307              : 
     308              :     // 循环 subDim0Size 次,每次处理一行
     309            0 :     for (u32 r = 0; r < subDim0Size; r++) {
     310            0 :         const auto& sourceRow = *(matRowStartIt + r); // 获取当前行的常量引用
     311              :         // 计算该行的列坐标起始
     312            0 :         auto startIt = sourceRow.cbegin() + startCol;
     313            0 :         auto endIt = sourceRow.cbegin() + startCol + subDim1Size;
     314              : 
     315            0 :         subRankList.insert(subRankList.end(), startIt, endIt);
     316              : 
     317            0 :         if (r == targetRelRow) {
     318            0 :             targetRowVec.insert(targetRowVec.end(), startIt, endIt);
     319              :         }
     320              : 
     321            0 :         auto colIt = sourceRow.cbegin() + startCol + targetRelCol;
     322            0 :         targetColVec.push_back(*colIt);
     323              :     }
     324              : 
     325            0 :     std::sort(targetRowVec.begin(), targetRowVec.end());
     326            0 :     std::sort(targetColVec.begin(), targetColVec.end());
     327              : 
     328            0 :     subRankTopo.emplace_back(std::move(targetRowVec));
     329            0 :     subRankTopo.emplace_back(std::move(targetColVec));
     330              : 
     331            0 :     return HcclResult::HCCL_SUCCESS;
     332            0 : }
     333              : 
     334            0 : bool TopoMatchConcurrMeshNHR::CheckSymmetric(std::vector<u32>& values) const
     335              : {
     336            0 :     const auto minmaxPair = std::minmax_element(values.begin(), values.end());
     337            0 :     u32 minValue = *minmaxPair.first;
     338            0 :     u32 maxValue = *minmaxPair.second;
     339              : 
     340            0 :     return (minValue == maxValue);
     341              : }
     342              : } // namespace Hccl
        

Generated by: LCOV version 2.0-1