LCOV - code coverage report
Current view: top level - coll_communicator_mgr/resource_mgr/local/my_rank/endpoints - endpoint_mgr.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 89.9 % 119 107
Test Date: 2026-08-25 19:18:03 Functions: 100.0 % 12 12

            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 "endpoint_mgr.h"
      12              : #include <algorithm>
      13              : #include "hcomm_c_adpt.h"
      14              : 
      15              : namespace hcomm {
      16              : 
      17           32 : TaggedMemMap::~TaggedMemMap()
      18              : {
      19           16 :     if (handle_ == nullptr) {
      20            0 :         return;
      21              :     }
      22           43 :     for (const auto& kv : tagToHandle_) {
      23           27 :         HcommResult ret = HcommMemUnreg(handle_, kv.second);
      24           27 :         if (ret != HCCL_SUCCESS) {
      25           12 :             HCCL_ERROR(
      26              :                 "[TaggedMemMap::~TaggedMemMap] HcommMemUnreg failed, handle[%p] tag[%s] ret[%d]", handle_,
      27              :                 kv.first.c_str(), ret);
      28              :         }
      29              :     }
      30           16 : }
      31              : 
      32           24 : MemHandle TaggedMemMap::FindHandle(const std::string& tag) const
      33              : {
      34           24 :     auto it = tagToHandle_.find(tag);
      35           24 :     return it != tagToHandle_.end() ? it->second : nullptr;
      36              : }
      37              : 
      38           33 : bool TaggedMemMap::HasTag(const std::string& tag) const { return tagToHandle_.find(tag) != tagToHandle_.end(); }
      39              : 
      40           31 : void TaggedMemMap::EmplaceHandle(const std::string& tag, MemHandle handle) { tagToHandle_.emplace(tag, handle); }
      41              : 
      42            4 : MemHandle TaggedMemMap::RemoveTag(const std::string& tag)
      43              : {
      44            4 :     auto it = tagToHandle_.find(tag);
      45            4 :     if (it == tagToHandle_.end()) {
      46            0 :         return nullptr;
      47              :     }
      48            4 :     MemHandle handle = it->second;
      49            4 :     tagToHandle_.erase(it);
      50            4 :     return handle;
      51              : }
      52              : 
      53          218 : EndpointMgr::~EndpointMgr()
      54              : {
      55          218 :     endpointTagMemMap_.clear();
      56          230 :     for (const auto& kv : endpointMap_) {
      57           12 :         const EndpointHandle& endpointHandle = kv.second;
      58           12 :         (void)HcommEndpointDestroy(endpointHandle);
      59              :     }
      60              :     // 销毁共享 jetty 场景按 tag 创建的独立 Endpoint
      61          221 :     for (const auto& kv : taggedEndpointMap_) {
      62            3 :         (void)HcommEndpointDestroy(kv.second);
      63              :     }
      64          218 :     taggedEndpointMap_.clear();
      65          218 : }
      66              : 
      67           37 : HcclResult EndpointMgr::Get(EndpointDesc epDesc, EndpointHandle& handle)
      68              : {
      69           37 :     std::lock_guard<std::mutex> lock(mutex_);
      70           37 :     auto iterPtr = endpointMap_.find(epDesc);
      71           37 :     if (iterPtr != endpointMap_.end()) {
      72           23 :         handle = iterPtr->second;
      73           23 :         return HCCL_SUCCESS;
      74              :     }
      75           14 :     HCCL_INFO("[EndpointMgr::Get] create Endpoint");
      76           14 :     CHK_RET(static_cast<HcclResult>(HcommEndpointCreate(&epDesc, &handle)));
      77              : 
      78           12 :     endpointMap_.emplace(epDesc, handle);
      79           12 :     return HCCL_SUCCESS;
      80           37 : }
      81              : 
      82            5 : HcclResult EndpointMgr::GetWithTag(EndpointDesc epDesc, const std::string& sharedQueueTag, EndpointHandle& handle)
      83              : {
      84              :     // tag 为空:退化为默认 Get,兼容非共享路径或无 tag 场景
      85            5 :     if (sharedQueueTag.empty()) {
      86            1 :         return Get(epDesc, handle);
      87              :     }
      88              : 
      89            4 :     EndpointDescTagKey key{epDesc, sharedQueueTag};
      90              : 
      91              :     // 快路径:持锁查缓存,命中直接返回
      92              :     {
      93            4 :         std::lock_guard<std::mutex> lock(mutex_);
      94            4 :         auto iter = taggedEndpointMap_.find(key);
      95            4 :         if (iter != taggedEndpointMap_.end()) {
      96            1 :             handle = iter->second;
      97            1 :             return HCCL_SUCCESS;
      98              :         }
      99            4 :     }
     100              : 
     101              :     // 慢路径:持锁创建 + 二次检查。
     102              :     // 不采用"无锁创建+失败销毁"乐观模式:HcommEndpointCreate 涉及 device context 分配等重操作,
     103              :     // 高并发同 key 多线程重复创建+销毁的代价高于锁内串行等待;且 create/destroy 非严格幂等时可能残留状态。
     104            3 :     std::lock_guard<std::mutex> lock(mutex_);
     105              :     // 二次检查:另一线程可能已在快路径后、本线程拿锁前完成创建
     106            3 :     auto iter = taggedEndpointMap_.find(key);
     107            3 :     if (iter != taggedEndpointMap_.end()) {
     108            0 :         handle = iter->second;
     109            0 :         return HCCL_SUCCESS;
     110              :     }
     111              :     // 锁内创建:同一 key 不会有并发的重复创建
     112            3 :     CHK_RET(static_cast<HcclResult>(HcommEndpointCreate(&epDesc, &handle)));
     113            3 :     taggedEndpointMap_.emplace(std::move(key), handle);
     114            3 :     HCCL_INFO("[EndpointMgr::GetWithTag] create tagged Endpoint, tag[%s], handle[%p].", sharedQueueTag.c_str(), handle);
     115            3 :     return HCCL_SUCCESS;
     116            4 : }
     117              : 
     118           21 : HcclResult EndpointMgr::RegisterMemory(
     119              :     EndpointHandle epHandle, const std::vector<std::string>& memTag, const std::vector<HcclMem>& memVec,
     120              :     uint64_t commMemsVersion)
     121              : {
     122           21 :     std::lock_guard<std::mutex> lock(mutex_);
     123           21 :     auto& taggedMap = endpointTagMemMap_.try_emplace(epHandle, epHandle).first->second;
     124              : 
     125              :     // 版本一致,CommMems 无变更,跳过注册
     126           21 :     if (taggedMap.GetVersion() == commMemsVersion) {
     127            6 :         HCCL_INFO(
     128              :             "[%s]commMemsVersion[%llu] unchanged, skip registration, epHandle[%p]", __FUNCTION__, commMemsVersion,
     129              :             epHandle);
     130            6 :         return HCCL_SUCCESS;
     131              :     }
     132           15 :     CHK_PRT_RET(
     133              :         memTag.size() < memVec.size(),
     134              :         HCCL_ERROR("[%s] memTag.size()[%zu] < memVec.size()[%zu]", __FUNCTION__, memTag.size(), memVec.size()),
     135              :         HCCL_E_PARA);
     136              : 
     137           15 :     size_t index = 0;
     138           48 :     for (const auto& mem : memVec) {
     139           33 :         const std::string& tag = memTag[index];
     140           33 :         index++;
     141              :         // 检查tag是否已注册,避免重复注册
     142           33 :         if (taggedMap.HasTag(tag)) {
     143            2 :             HCCL_INFO("[%s]tag already registered, reuse existing handle, tag=%s", __FUNCTION__, tag.c_str());
     144            2 :             continue;
     145              :         }
     146           31 :         MemHandle memHandle = nullptr;
     147           31 :         CommMem commMem{static_cast<CommMemType>(mem.type), mem.addr, mem.size};
     148           31 :         HcclResult ret = static_cast<HcclResult>(HcommMemReg(epHandle, tag.c_str(), &commMem, &memHandle));
     149           31 :         if (ret != HCCL_SUCCESS && ret != HCCL_E_AGAIN) {
     150            0 :             HCCL_ERROR("[%s]call trace: hcclRet -> %d", __FUNCTION__, ret);
     151            0 :             return ret;
     152              :         }
     153           31 :         CHK_PTR_NULL(memHandle);
     154           31 :         taggedMap.EmplaceHandle(tag, memHandle); // 记录到tag映射,后续相同tag直接命中
     155           31 :         if (ret == HCCL_E_AGAIN) {
     156            0 :             HCCL_WARNING("This mem has already been registered, addr=%p, size=%llu", mem.addr, mem.size);
     157              :         }
     158              :     }
     159              : 
     160           15 :     taggedMap.SetVersion(commMemsVersion);
     161           15 :     return HCCL_SUCCESS;
     162           21 : }
     163              : 
     164           14 : HcclResult EndpointMgr::GetMemHandlesByTags(
     165              :     EndpointHandle epHandle, const std::vector<std::string>& memTags, std::vector<MemHandle>& memHandleVec)
     166              : {
     167           14 :     std::lock_guard<std::mutex> lock(mutex_);
     168           14 :     memHandleVec.clear();
     169           14 :     auto it = endpointTagMemMap_.find(epHandle);
     170           14 :     if (it == endpointTagMemMap_.end()) {
     171            0 :         HCCL_ERROR("[%s] epHandle[%p] not found in endpointTagMemMap_", __FUNCTION__, epHandle);
     172            0 :         return HCCL_E_MEMORY;
     173              :     }
     174           14 :     const auto& taggedMap = it->second;
     175           32 :     for (const auto& tag : memTags) {
     176           19 :         MemHandle handle = taggedMap.FindHandle(tag);
     177           19 :         if (handle == nullptr) {
     178            1 :             HCCL_ERROR(
     179              :                 "[%s] tag[%s] not found in endpoint[%p], registration may have been skipped", __FUNCTION__, tag.c_str(),
     180              :                 epHandle);
     181            1 :             return HCCL_E_NOT_FOUND;
     182              :         }
     183           18 :         memHandleVec.push_back(handle);
     184              :     }
     185           13 :     return HCCL_SUCCESS;
     186           14 : }
     187              : 
     188            3 : HcclResult EndpointMgr::UnregMemByTag(const std::string& tag)
     189              : {
     190            3 :     std::lock_guard<std::mutex> lock(mutex_);
     191            3 :     HcclResult lastErr = HCCL_SUCCESS;
     192            8 :     for (auto& kv : endpointTagMemMap_) {
     193            5 :         MemHandle handle = kv.second.FindHandle(tag);
     194            5 :         if (handle == nullptr) {
     195            1 :             continue;
     196              :         }
     197            4 :         HcommResult ret = HcommMemUnreg(kv.first, handle);
     198            4 :         if (ret != HCCL_SUCCESS) {
     199            0 :             HCCL_ERROR(
     200              :                 "[%s] HcommMemUnreg failed, epHandle[%p] tag[%s] ret[%d]", __FUNCTION__, kv.first, tag.c_str(), ret);
     201            0 :             lastErr = static_cast<HcclResult>(ret);
     202            0 :             continue;
     203              :         }
     204            4 :         kv.second.RemoveTag(tag);
     205              :     }
     206            3 :     return lastErr;
     207            3 : }
     208              : 
     209            1 : bool EndpointMgr::IsDescExist(EndpointDesc epDesc) { return endpointMap_.find(epDesc) != endpointMap_.end(); }
     210              : 
     211              : } // namespace hcomm
        

Generated by: LCOV version 2.0-1