LCOV - code coverage report
Current view: top level - coll_communicator_mgr/team/hccl - hccl_team_mgr.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.9 % 279 237
Test Date: 2026-08-18 17:47:01 Functions: 100.0 % 25 25

            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              : 
      11              : #include "hccl_team_mgr.h"
      12              : 
      13              : #include <algorithm>
      14              : #include <cstdint>
      15              : #include <memory>
      16              : #include <mutex>
      17              : #include <utility>
      18              : 
      19              : #include "adapter_rts_common.h"
      20              : #include "log.h"
      21              : 
      22              : namespace hccl {
      23              : 
      24          682 : HcclTeamMgr& HcclTeamMgr::GetInstance()
      25              : {
      26              :     static std::once_flag instanceFlag;
      27              :     static HcclTeamMgr* instance = nullptr;
      28          682 :     std::call_once(instanceFlag, [&] {
      29            6 :         instance = new HcclTeamMgr();
      30            6 :     });
      31          682 :     return *instance;
      32              : }
      33              : 
      34           30 : HcclResult HcclTeamMgr::RegisterWorldTeam(
      35              :     HcommTeamHandle worldTeam, CollComm* collComm, void* syncMemPtr, uint64_t syncMemSize, const uint32_t* rankIds,
      36              :     uint32_t rankNum)
      37              : {
      38           30 :     if (worldTeam == nullptr || collComm == nullptr || rankIds == nullptr) {
      39            0 :         HCCL_ERROR(
      40              :             "[HcclTeamMgr][%s] invalid param, worldTeam[%p] collComm[%p] rankIds[%p]", __func__, worldTeam, collComm,
      41              :             rankIds);
      42            0 :         return HCCL_E_PTR;
      43              :     }
      44           30 :     std::unique_lock<std::shared_mutex> lock(mutex_);
      45           30 :     auto worldIt = teamMap_.find(worldTeam);
      46           30 :     if (worldIt != teamMap_.end()) {
      47            0 :         HCCL_ERROR("[HcclTeamMgr][%s] worldTeam[%p] already registered", __func__, worldTeam);
      48            0 :         return HCCL_E_PARA;
      49              :     }
      50           30 :     TeamEntry& entry = teamMap_[worldTeam];
      51           30 :     entry.collComm = collComm;
      52           30 :     entry.worldTeam = nullptr;
      53           30 :     entry.syncMemPtr = syncMemPtr;
      54           30 :     entry.syncMemSize = syncMemSize;
      55           30 :     entry.syncMemHandle = nullptr;
      56           30 :     entry.syncMemTag.clear();
      57           30 :     entry.windows.clear();
      58           30 :     entry.rankIds.assign(rankIds, rankIds + rankNum);
      59           30 :     return HCCL_SUCCESS;
      60           30 : }
      61              : 
      62            3 : HcclResult HcclTeamMgr::RegisterSubTeam(
      63              :     HcommTeamHandle worldTeam, HcommTeamHandle subTeam, void* syncMemPtr, uint64_t syncMemSize, const uint32_t* rankIds,
      64              :     uint32_t rankNum)
      65              : {
      66            3 :     if (worldTeam == nullptr || subTeam == nullptr || rankIds == nullptr) {
      67            0 :         HCCL_ERROR(
      68              :             "[HcclTeamMgr][%s] invalid param, worldTeam[%p] subTeam[%p] rankIds[%p]", __func__, worldTeam, subTeam,
      69              :             rankIds);
      70            0 :         return HCCL_E_PTR;
      71              :     }
      72            3 :     std::unique_lock<std::shared_mutex> lock(mutex_);
      73            3 :     auto worldIt = teamMap_.find(worldTeam);
      74            3 :     if (worldIt == teamMap_.end()) {
      75            0 :         HCCL_ERROR("[HcclTeamMgr][%s] worldTeam[%p] not registered", __func__, worldTeam);
      76            0 :         return HCCL_E_PARA;
      77              :     }
      78            3 :     if (teamMap_.find(subTeam) != teamMap_.end()) {
      79            0 :         HCCL_ERROR("[HcclTeamMgr][%s] subTeam[%p] already registered", __func__, subTeam);
      80            0 :         return HCCL_E_PARA;
      81              :     }
      82            3 :     CollComm* collComm = worldIt->second.collComm;
      83            3 :     TeamEntry& entry = teamMap_[subTeam];
      84            3 :     entry.collComm = collComm;
      85            3 :     entry.worldTeam = worldTeam;
      86            3 :     entry.syncMemPtr = syncMemPtr;
      87            3 :     entry.syncMemSize = syncMemSize;
      88            3 :     entry.syncMemHandle = nullptr;
      89            3 :     entry.syncMemTag.clear();
      90            3 :     entry.windows.clear();
      91            3 :     entry.rankIds.assign(rankIds, rankIds + rankNum);
      92            3 :     return HCCL_SUCCESS;
      93            3 : }
      94              : 
      95          129 : void HcclTeamMgr::UnregisterTeam(HcommTeamHandle team)
      96              : {
      97          129 :     if (team == nullptr) {
      98            0 :         return;
      99              :     }
     100          129 :     void* syncMemPtr = nullptr;
     101              :     {
     102          129 :         std::unique_lock<std::shared_mutex> lock(mutex_);
     103          129 :         auto it = teamMap_.find(team);
     104          129 :         if (it == teamMap_.end()) {
     105           97 :             return;
     106              :         }
     107           32 :         syncMemPtr = it->second.syncMemPtr;
     108           32 :         teamMap_.erase(it);
     109          129 :     }
     110           32 :     if (syncMemPtr != nullptr) {
     111           32 :         (void)hrtFree(syncMemPtr);
     112              :     }
     113              : }
     114              : 
     115           33 : CollComm* HcclTeamMgr::FindCollComm(HcommTeamHandle team)
     116              : {
     117           33 :     CHK_PRT_RET(team == nullptr, HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team), nullptr);
     118           33 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     119           33 :     auto it = teamMap_.find(team);
     120           33 :     if (it == teamMap_.end()) {
     121            3 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     122            3 :         return nullptr;
     123              :     }
     124           30 :     return it->second.collComm;
     125           33 : }
     126              : 
     127           76 : HcommTeamHandle HcclTeamMgr::FindWorldTeam(HcommTeamHandle team)
     128              : {
     129           76 :     CHK_PRT_RET(team == nullptr, HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team), nullptr);
     130           76 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     131           76 :     auto it = teamMap_.find(team);
     132           76 :     if (it == teamMap_.end()) {
     133            5 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     134            5 :         return nullptr;
     135              :     }
     136              :     // world team 自身 worldTeam 字段为 nullptr,返回自身
     137           71 :     return (it->second.worldTeam != nullptr) ? it->second.worldTeam : team;
     138           76 : }
     139              : 
     140           28 : std::vector<uint32_t> HcclTeamMgr::GetRankIds(HcommTeamHandle team)
     141              : {
     142           28 :     std::vector<uint32_t> result;
     143           28 :     if (team == nullptr) {
     144            0 :         return result;
     145              :     }
     146           28 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     147           28 :     auto it = teamMap_.find(team);
     148           28 :     if (it == teamMap_.end()) {
     149            0 :         return result;
     150              :     }
     151           28 :     result = it->second.rankIds;
     152           28 :     return result;
     153           28 : }
     154              : 
     155           18 : void* HcclTeamMgr::GetSyncMemPtr(HcommTeamHandle team)
     156              : {
     157           18 :     CHK_PRT_RET(team == nullptr, HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team), nullptr);
     158           18 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     159           18 :     auto it = teamMap_.find(team);
     160           18 :     if (it == teamMap_.end()) {
     161            0 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     162            0 :         return nullptr;
     163              :     }
     164           18 :     return it->second.syncMemPtr;
     165           18 : }
     166              : 
     167           18 : uint64_t HcclTeamMgr::GetSyncMemSize(HcommTeamHandle team)
     168              : {
     169           18 :     CHK_PRT_RET(team == nullptr, HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team), 0);
     170           18 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     171           18 :     auto it = teamMap_.find(team);
     172           18 :     if (it == teamMap_.end()) {
     173            0 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     174            0 :         return 0;
     175              :     }
     176           18 :     return it->second.syncMemSize;
     177           18 : }
     178              : 
     179           11 : void HcclTeamMgr::SetTeamSyncMemHandle(HcommTeamHandle team, HcclMemHandle handle, const std::string& tag)
     180              : {
     181           11 :     if (team == nullptr) {
     182            0 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team);
     183            0 :         return;
     184              :     }
     185           11 :     std::unique_lock<std::shared_mutex> lock(mutex_);
     186           11 :     auto it = teamMap_.find(team);
     187           11 :     if (it == teamMap_.end()) {
     188            0 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     189            0 :         return;
     190              :     }
     191           11 :     it->second.syncMemHandle = handle;
     192           11 :     it->second.syncMemTag = tag;
     193           11 : }
     194              : 
     195           11 : HcclMemHandle HcclTeamMgr::GetTeamSyncMemHandle(HcommTeamHandle team)
     196              : {
     197           11 :     CHK_PRT_RET(team == nullptr, HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team), nullptr);
     198           11 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     199           11 :     auto it = teamMap_.find(team);
     200           11 :     if (it == teamMap_.end()) {
     201            0 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     202            0 :         return nullptr;
     203              :     }
     204           11 :     return it->second.syncMemHandle;
     205           11 : }
     206              : 
     207           11 : std::string HcclTeamMgr::GetTeamSyncMemTag(HcommTeamHandle team)
     208              : {
     209           11 :     CHK_PRT_RET(team == nullptr, HCCL_ERROR("[HcclTeamMgr][%s] team[%p] is invalid", __func__, team), std::string());
     210           11 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     211           11 :     auto it = teamMap_.find(team);
     212           11 :     if (it == teamMap_.end()) {
     213            0 :         HCCL_ERROR("[HcclTeamMgr][%s] team[%p] not registered", __func__, team);
     214            0 :         return std::string();
     215              :     }
     216           11 :     return it->second.syncMemTag;
     217           11 : }
     218              : 
     219           21 : bool HcclTeamMgr::FindReusableWindow(HcommTeamHandle worldTeam, const CommMem& localMem, HcommWindowHandle& window)
     220              : {
     221           21 :     if (worldTeam == nullptr) {
     222            0 :         return false;
     223              :     }
     224           21 :     std::unique_lock<std::shared_mutex> lock(mutex_);
     225           21 :     auto it = teamMap_.find(worldTeam);
     226           21 :     if (it == teamMap_.end()) {
     227            0 :         return false;
     228              :     }
     229              :     // windows 按 registeredLocalMem.addr 升序
     230              :     // upper_bound 找第一个 start > requestStart 的,反向遍历找包含请求区间的 window(请求是已注册 window 的子集)。
     231           21 :     const uintptr_t requestStart = reinterpret_cast<uintptr_t>(localMem.addr);
     232           21 :     const uintptr_t requestEnd = requestStart + localMem.size;
     233           21 :     auto& windows = it->second.windows;
     234              :     auto upper
     235           21 :         = std::upper_bound(windows.begin(), windows.end(), requestStart, [](uintptr_t addr, const WindowInfo& win) {
     236           12 :               return addr < reinterpret_cast<uintptr_t>(win.registeredLocalMem.addr);
     237              :           });
     238           30 :     for (auto wIt = upper; wIt != windows.begin();) {
     239           14 :         --wIt;
     240           14 :         if (wIt->handle == nullptr) {
     241            0 :             continue;
     242              :         }
     243           14 :         const uintptr_t winStart = reinterpret_cast<uintptr_t>(wIt->registeredLocalMem.addr);
     244           14 :         const uintptr_t winEnd = winStart + wIt->registeredLocalMem.size;
     245              :         // 请求区间是已注册 window 的子集(含精确匹配)→ 复用
     246           14 :         if (requestStart >= winStart && requestEnd <= winEnd) {
     247            5 :             window = wIt->handle;
     248              :             // 精确匹配(addr+size 完全相同)→ 已有记录,无需新增
     249            5 :             if (requestStart == winStart && requestEnd == winEnd) {
     250            2 :                 return true;
     251              :             }
     252              :             // 子集包含但非精确匹配 → 复用 parent handle,为请求的 localMem 新增一条 WindowInfo,
     253              :             // 使后续 BindWindowsAndSyncMem 的 self 槽填入请求的实际地址(而非 parent 的地址范围)。
     254            3 :             WindowInfo info;
     255            3 :             info.handle = window;
     256            3 :             info.registeredLocalMem = localMem;
     257            3 :             auto insertIt = std::upper_bound(
     258            6 :                 windows.begin(), windows.end(), requestStart, [](uintptr_t addr, const WindowInfo& win) {
     259            6 :                     return addr < reinterpret_cast<uintptr_t>(win.registeredLocalMem.addr);
     260              :                 });
     261            3 :             windows.insert(insertIt, std::move(info));
     262            3 :             return true;
     263            3 :         }
     264              :     }
     265           16 :     return false;
     266           21 : }
     267              : 
     268           19 : void HcclTeamMgr::AddWorldTeamWindow(
     269              :     HcommTeamHandle worldTeam, HcommWindowHandle window, const CommMem& localMem, HcclMemHandle localMemHandle,
     270              :     const std::string& localMemTag)
     271              : {
     272           19 :     if (worldTeam == nullptr || window == nullptr) {
     273            0 :         HCCL_ERROR("[HcclTeamMgr][%s] worldTeam[%p] or window[%p] is invalid", __func__, worldTeam, window);
     274            0 :         return;
     275              :     }
     276           19 :     std::unique_lock<std::shared_mutex> lock(mutex_);
     277           19 :     auto it = teamMap_.find(worldTeam);
     278           19 :     if (it == teamMap_.end()) {
     279            0 :         HCCL_ERROR("[HcclTeamMgr][%s] worldTeam[%p] not registered", __func__, worldTeam);
     280            0 :         return;
     281              :     }
     282           19 :     WindowInfo info;
     283           19 :     info.handle = window;
     284           19 :     info.registeredLocalMem = localMem;
     285           19 :     info.localMemHandle = localMemHandle;
     286           19 :     info.localMemTag = localMemTag;
     287              :     // 按 registeredLocalMem.addr 升序插入,维护 windows 有序性,供 FindReusableWindow 二分查找
     288           19 :     const uintptr_t newStart = reinterpret_cast<uintptr_t>(localMem.addr);
     289           38 :     auto insertIt = std::upper_bound(
     290           38 :         it->second.windows.begin(), it->second.windows.end(), newStart, [](uintptr_t addr, const WindowInfo& win) {
     291            4 :             return addr < reinterpret_cast<uintptr_t>(win.registeredLocalMem.addr);
     292              :         });
     293           19 :     it->second.windows.insert(insertIt, std::move(info));
     294           19 : }
     295              : 
     296           43 : std::vector<WindowInfo> HcclTeamMgr::GetWorldTeamWindows(HcommTeamHandle worldTeam)
     297              : {
     298           43 :     std::vector<WindowInfo> result;
     299           43 :     if (worldTeam == nullptr) {
     300            0 :         return result;
     301              :     }
     302           43 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     303           43 :     auto it = teamMap_.find(worldTeam);
     304           43 :     if (it == teamMap_.end()) {
     305            0 :         return result;
     306              :     }
     307           43 :     result = it->second.windows;
     308           43 :     return result;
     309           43 : }
     310              : 
     311           11 : std::vector<HcclMemHandle> HcclTeamMgr::CollectPendingMemHandles(HcommTeamHandle worldTeam, HcommTeamHandle team)
     312              : {
     313           11 :     std::vector<HcclMemHandle> result;
     314           11 :     if (worldTeam == nullptr || team == nullptr) {
     315            0 :         return result;
     316              :     }
     317           11 :     std::unique_lock<std::shared_mutex> lock(mutex_);
     318           11 :     auto itTeam = teamMap_.find(team);
     319           11 :     if (itTeam == teamMap_.end()) {
     320            0 :         return result;
     321              :     }
     322           11 :     auto itWorldTeam = teamMap_.find(worldTeam);
     323           11 :     if (itWorldTeam == teamMap_.end()) {
     324            0 :         return result;
     325              :     }
     326              :     // syncMemHandle:首次注册且未交换时收集
     327           11 :     if (!itTeam->second.syncMemExchanged && itTeam->second.syncMemHandle != nullptr) {
     328           11 :         result.push_back(itTeam->second.syncMemHandle);
     329           11 :         itTeam->second.syncMemExchanged = true;
     330              :     }
     331              :     // window localMemHandle:未交换的收集并标记
     332           19 :     for (auto& win : itWorldTeam->second.windows) {
     333            8 :         if (!win.exchanged && win.localMemHandle != nullptr) {
     334            8 :             result.push_back(win.localMemHandle);
     335            8 :             win.exchanged = true;
     336              :         }
     337              :     }
     338           11 :     return result;
     339           11 : }
     340              : 
     341            3 : void HcclTeamMgr::RemoveWorldTeamWindow(HcommTeamHandle worldTeam, HcommWindowHandle window)
     342              : {
     343            3 :     if (worldTeam == nullptr || window == nullptr) {
     344            2 :         return;
     345              :     }
     346            3 :     std::unique_lock<std::shared_mutex> lock(mutex_);
     347            3 :     auto it = teamMap_.find(worldTeam);
     348            3 :     if (it == teamMap_.end()) {
     349            0 :         return;
     350              :     }
     351            3 :     auto& wins = it->second.windows;
     352            3 :     for (auto wIt = wins.begin(); wIt != wins.end(); ++wIt) {
     353            2 :         if (wIt->handle == window) {
     354            2 :             wins.erase(wIt);
     355            2 :             return;
     356              :         }
     357              :     }
     358            3 : }
     359              : 
     360           29 : std::vector<HcommTeamHandle> HcclTeamMgr::GetSubTeams(HcommTeamHandle worldTeam)
     361              : {
     362           29 :     std::vector<HcommTeamHandle> result;
     363           29 :     if (worldTeam == nullptr) {
     364            0 :         return result;
     365              :     }
     366           29 :     std::shared_lock<std::shared_mutex> lock(mutex_);
     367              :     // subTeam 的 worldTeam 字段指向其父 worldTeam;worldTeam 自身该字段为 nullptr。
     368           59 :     for (const auto& pair : teamMap_) {
     369           30 :         if (pair.second.worldTeam == worldTeam) {
     370            1 :             result.push_back(pair.first);
     371              :         }
     372              :     }
     373           29 :     return result;
     374           29 : }
     375              : 
     376          188 : void HcclTeamMgr::ClearByCollComm(CollComm* collComm)
     377              : {
     378          188 :     if (collComm == nullptr) {
     379            0 :         return;
     380              :     }
     381              :     // 锁内收集并 erase,锁外销毁,避免持 L2 锁调 L3 接口(锁嵌套/死锁风险)
     382          188 :     std::vector<TeamCleanupInfo> cleanupInfos = CollectTeamCleanupInfo(collComm);
     383          188 :     ExecuteTeamCleanup(cleanupInfos);
     384          188 : }
     385              : 
     386          188 : std::vector<HcclTeamMgr::TeamCleanupInfo> HcclTeamMgr::CollectTeamCleanupInfo(CollComm* collComm)
     387              : {
     388          188 :     std::vector<TeamCleanupInfo> cleanupInfos;
     389          188 :     std::unique_lock<std::shared_mutex> lock(mutex_);
     390          189 :     for (auto it = teamMap_.begin(); it != teamMap_.end();) {
     391            1 :         if (it->second.collComm != collComm) {
     392            0 :             ++it;
     393            0 :             continue;
     394              :         }
     395            1 :         TeamCleanupInfo info;
     396            1 :         info.handle = it->first;
     397            1 :         info.syncMemPtr = it->second.syncMemPtr;
     398              :         // window 归 worldTeam 所有(entry.worldTeam==nullptr 表示自身是 worldTeam)
     399            1 :         if (it->second.worldTeam == nullptr) {
     400            2 :             for (const auto& win : it->second.windows) {
     401            1 :                 if (win.handle != nullptr) {
     402            1 :                     info.windows.push_back(win.handle);
     403              :                 }
     404              :             }
     405              :         }
     406            1 :         cleanupInfos.push_back(std::move(info));
     407            1 :         it = teamMap_.erase(it);
     408            1 :     }
     409          188 :     return cleanupInfos;
     410          188 : }
     411              : 
     412          188 : void HcclTeamMgr::ExecuteTeamCleanup(const std::vector<TeamCleanupInfo>& cleanupInfos)
     413              : {
     414              :     // 锁外依次销毁:window(L3 devWindow/devMems)→ team(L3 device 资源)→ syncMem(L2 本地内存)
     415          189 :     for (const auto& info : cleanupInfos) {
     416            2 :         for (HcommWindowHandle win : info.windows) {
     417            1 :             (void)HcommTeamWindowDeregister(info.handle, win);
     418              :         }
     419            1 :         (void)HcommTeamDestroy(info.handle);
     420            1 :         if (info.syncMemPtr != nullptr) {
     421            1 :             (void)hrtFree(info.syncMemPtr);
     422              :         }
     423              :     }
     424          188 : }
     425              : 
     426              : } // namespace hccl
        

Generated by: LCOV version 2.0-1