LCOV - code coverage report
Current view: top level - legacy/ascend950/framework/ccu/ccu_manager - ccu_jetty_mgr.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.9 % 155 144
Test Date: 2026-08-04 10:52:23 Functions: 89.5 % 19 17

            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 "ccu_jetty_mgr.h"
      12              : 
      13              : #include <unordered_set>
      14              : 
      15              : #include "ccu_dev_mgr.h"
      16              : #include "internal_exception.h"
      17              : #include "invalid_params_exception.h"
      18              : 
      19              : namespace Hccl {
      20              : 
      21              : constexpr uint32_t CCU_DEFAULT_REQUEST_SQ_SIZE = 128;
      22              : constexpr uint32_t CCU_CLOS_REQUEST_SQ_SIZE = 16;  // CLOS场景的默认SQ大小
      23              : constexpr uint32_t CCU_DEFAULT_REQUEST_CHANNEL_NUM = 1;
      24              : constexpr uint32_t CCU_DEFAULT_REQUEST_JETTY_NUM = 0; // 申请数量为0时,由平台层决定提供数量
      25              : 
      26          270 : CcuJettyMgr::CcuJettyMgr(int32_t devLogicId) : devLogicId_(devLogicId)
      27              : {
      28          270 : }
      29              : 
      30          270 : CcuJettyMgr::~CcuJettyMgr()
      31              : {
      32              :     // 对象析构时清空多个map,batchMap_中元素的jettys清空触发ccuJetty析构释放
      33          270 :     DECTOR_TRY_CATCH("CcuJettyMgr", ReleaseConfirmedChannelRes());
      34          270 : }
      35              : 
      36           14 : HcclResult CcuJettyMgr::PrepareCreate(const std::vector<LinkData> &links)
      37              : {
      38           17 :     CHK_PRT_RET(links.empty(),
      39              :         HCCL_INFO("[CcuJettyMgr][%s] passed, links is empty, devLogicId[%d].",
      40              :             __func__, devLogicId_),
      41              :         HcclResult::HCCL_SUCCESS);
      42              : 
      43          277 :     for (const auto &link : links) {
      44          267 :         auto it = allocatedChannelIdMap_.find(link);
      45          267 :         if (it != allocatedChannelIdMap_.end()) {
      46          144 :             HCCL_INFO("[CcuJettyMgr][%s] passed, link[%s] is already allocated, "
      47              :                 "devLogicId[%d].", __func__, link.Describe().c_str(), devLogicId_);
      48           48 :             continue;
      49           48 :         }
      50              : 
      51          219 :         const auto &locAddr = link.GetLocalAddr();
      52              :         // 根据 LinkData 的 fullmesh 字段选择不同的 sqSize
      53          219 :         uint32_t sqSize = link.GetFullmesh() ? CCU_DEFAULT_REQUEST_SQ_SIZE : CCU_CLOS_REQUEST_SQ_SIZE;
      54          219 :         ResourceBatch *batchPtr = nullptr;
      55              :         // 这里仅使用locAddr作为batchKey,是因为不会存在相同locAddr但不同资源的场景(不同locAddr必然不同资源),如果后续有更复杂的场景再调整key设计
      56          219 :         auto ret = GetAvailableBatch(locAddr, batchPtr, sqSize);
      57          224 :         CHK_PRT_RET(ret == HcclResult::HCCL_E_UNAVAIL,
      58              :             HCCL_WARNING("[CcuJettyMgr][%s] failed to alloc ccu channels, ccu resources "
      59              :                 "are unavaialble, locAddr[%s], devLogicId[%d].",
      60              :                 __func__, locAddr.Describe().c_str(), devLogicId_),
      61              :             ret);
      62          224 :         CHK_RET(ret);
      63              :     
      64          216 :         ChannelIdKey channelIdKey = batchPtr->availableChannelIdKeys.back();
      65          216 :         batchPtr->availableChannelIdKeys.pop_back();
      66          216 :         unconfirmedRecord_.allocations.emplace_back(Allocation{link, channelIdKey, batchPtr});
      67          216 :         allocatedChannelIdMap_[link] = channelIdKey;
      68          216 :         channelRemoteRankIdMap_[channelIdKey] = link.GetRemoteRankId();
      69          216 :         channelIpAddressMap_[channelIdKey] = {link.GetLocalAddr(), link.GetRemoteAddr()};
      70              : 
      71          648 :         HCCL_INFO("[CcuJettyMgr][%s] allocated new channelId[%u] of die[%u] to link[%s], "
      72              :             "devLogicId[%d].", __func__, channelIdKey.second, channelIdKey.first,
      73              :             link.Describe().c_str(), devLogicId_);
      74              :     }
      75              : 
      76           10 :     isReleased = false;
      77           10 :     return HcclResult::HCCL_SUCCESS;
      78              : }
      79              : 
      80              : // 当前以locAddr为粒度调用,根据locAddr可以找到已申请的批次,如果资源充足则复用,不足则按新批次申请资源
      81          219 : HcclResult CcuJettyMgr::GetAvailableBatch(const BatchKey &batchKey, ResourceBatch *&batchPtr, uint32_t sqSize)
      82              : {
      83              :     // 当前以locAddr作为batchKey,不同本端不能复用资源
      84          219 :     if (FindAvailableBatch(batchKey, batchPtr)) {
      85          170 :         return HcclResult::HCCL_SUCCESS;
      86              :     }
      87              :     // 已有的资源不足,需要新增资源,获取的channel数量可能超过申请数量
      88              :     const CcuChannelPara channelPara{batchKey, CCU_DEFAULT_REQUEST_CHANNEL_NUM,
      89           49 :         CCU_DEFAULT_REQUEST_JETTY_NUM, sqSize};
      90          147 :     HCCL_INFO("[CcuJettyMgr][%s] try to alloc ccu channels with channelPara[channelNum=%u, jettyNum=%u, sqSize=%u], "
      91              :         "locAddr[%s], devLogicId[%d].", __func__, channelPara.channelNum, channelPara.jettyNum,
      92              :         channelPara.sqSize, batchKey.Describe().c_str(), devLogicId_);
      93           49 :     std::vector<CcuChannelInfo> channelInfos;
      94           49 :     auto ret = CcuAllocChannels(devLogicId_, channelPara, channelInfos);
      95              :     // 如果资源不足,平台层返回不可用错误,需要上层感知不可用进行降级处理
      96           52 :     CHK_PRT_RET(ret == HcclResult::HCCL_E_UNAVAIL,
      97              :         HCCL_WARNING("[CcuJettyMgr][%s] failed to alloc ccu channels, ccu resources "
      98              :             "are unavaialble, locAddr[%s], sqSize[%u], devLogicId[%d].", __func__,
      99              :             batchKey.Describe().c_str(), sqSize, devLogicId_), ret);
     100              :     // 其他错误直接返回错误码
     101           51 :     CHK_PRT_RET(ret != HCCL_SUCCESS,
     102              :         HCCL_ERROR("[CcuJettyMgr][%s] failed to alloc ccu channels, ccu resources "
     103              :             "are unavaialble, locAddr[%s], sqSize[%u], devLogicId[%d].", __func__,
     104              :             batchKey.Describe().c_str(), sqSize, devLogicId_), ret);
     105              :     // 如果新增资源保存失败,手动释放避免泄露
     106           47 :     ret = CreateAndSaveNewBatch(batchKey, channelInfos, batchPtr);
     107           47 :     if (ret != HcclResult::HCCL_SUCCESS) {
     108            3 :         HCCL_ERROR("[CcuJettyMgr][%s] failed, try to release temp ccu resources, locAddr[%s], "
     109              :             "devLogicId[%d], .", __func__, batchKey.Describe().c_str(), devLogicId_);
     110            9 :         for (const auto &channelInfo : channelInfos) {
     111            8 :             const auto dieId = channelInfo.dieId;
     112            8 :             const auto channelId = channelInfo.channelId;
     113            8 :             CHK_RET(CcuReleaseChannel(devLogicId_, dieId, channelId));
     114              :         }
     115            1 :         return ret;
     116              :     }
     117           46 :     return HcclResult::HCCL_SUCCESS;
     118           49 : }
     119              : 
     120           46 : HcclResult CcuJettyMgr::CreateAndSaveNewBatch(const BatchKey &batchKey,
     121              :     const std::vector<CcuChannelInfo> channelInfos, ResourceBatch *&batchPtr)
     122              : {
     123              :     // 该流程如果抛异常,可能资源还未记录,析构无法释放导致资源泄露,故捕获异常处理
     124         1150 :     TRY_CATCH_RETURN(
     125              :         auto &batches = batchMap_[batchKey];
     126              :         auto newBatch = std::make_unique<ResourceBatch>(batchKey, channelInfos);
     127              :         for (const auto &channelInfo : channelInfos) {
     128              :             const auto dieId = channelInfo.dieId;
     129              :             const auto channelIdKey = std::make_pair(dieId, channelInfo.channelId);
     130              : 
     131              :             std::vector<CcuJetty *> jettys;
     132              :             for (const auto &jettyInfo : channelInfo.jettyInfos) {
     133              :                 const auto jettyIdKey = std::make_pair(dieId, jettyInfo.taJettyId);
     134              :                 jettys.emplace_back(newBatch->jettys[jettyIdKey].get());
     135              :             }
     136              : 
     137              :             channelJettyInfoMap_.emplace(channelIdKey, std::make_pair(channelInfo, jettys));
     138              :             usedChannelCntMap_[dieId] += 1;
     139              :         }
     140              : 
     141              :         batches.push_back(std::move(newBatch));
     142              :         ResourceBatch *rawBatch = batches.back().get();
     143              :         
     144              :         unconfirmedRecord_.newBatchSet.insert(rawBatch);
     145              :         batchPtr = rawBatch;
     146              :     );
     147           46 :     return HcclResult::HCCL_SUCCESS;
     148              : }
     149              : 
     150          219 : bool CcuJettyMgr::FindAvailableBatch(const BatchKey &batchKey, ResourceBatch *&batchPtr) const
     151              : {
     152          219 :     auto it = batchMap_.find(batchKey);
     153          219 :     if (it == batchMap_.end()) {
     154           39 :         return false;
     155              :     }
     156              : 
     157          180 :     auto &batches = it->second;
     158          180 :     if (batches.empty()) {
     159            0 :         return false;
     160              :     }
     161              :     // 当前分配逻辑只有最后一个batch可能还有空闲资源
     162          180 :     auto &lastBatch = batches.back();
     163          180 :     if (lastBatch->availableChannelIdKeys.empty()) {
     164           10 :         return false;
     165              :     }
     166              : 
     167          170 :     batchPtr = lastBatch.get();
     168          170 :     return true;
     169              : }
     170              : 
     171          276 : CcuJettyMgr::CcuChannelJettyInfo CcuJettyMgr::GetChannelJettys(const LinkData &link) const
     172              : {
     173          276 :     const auto &it = allocatedChannelIdMap_.find(link);
     174          276 :     CHK_RET_THROW(InternalException,
     175              :         StringFormat("[CcuJettyMgr][%s] failed to find allocated channelId of link[%s], ",
     176              :             "devLogicId[%d].", __func__, link.Describe().c_str(), devLogicId_),
     177              :         it == allocatedChannelIdMap_.end());
     178              :     // 内部维护数据保证channelJettyInfoMap_记录的资源存在
     179          552 :     return channelJettyInfoMap_.at(it->second);
     180              : }
     181              : 
     182           15 : void CcuJettyMgr::Confirm()
     183              : {
     184           15 :     unconfirmedRecord_.Clear();
     185           15 : }
     186              : 
     187            5 : void CcuJettyMgr::Fallback()
     188              : {
     189            5 :     FallbackAndRemoveBatches();
     190            5 :     FallbackAllocatedChannelJettyInfo();
     191            5 :     Confirm();
     192            5 : }
     193              : 
     194            5 : void CcuJettyMgr::FallbackAndRemoveBatches()
     195              : {
     196              :     using BatchSetKey = std::unordered_map<BatchKey,
     197              :         std::unordered_set<ResourceBatch *>>;
     198            5 :     BatchSetKey batchesToRemoveByKey;
     199           21 :     for (const auto &allocation : unconfirmedRecord_.allocations) {
     200           16 :         ResourceBatch *batchPtr = allocation.batchPtr;
     201           16 :         if (!batchPtr) {
     202            0 :             continue;
     203              :         }
     204              : 
     205           16 :         const auto &newBatchSet = unconfirmedRecord_.newBatchSet;
     206           16 :         bool isNewBatch = newBatchSet.find(batchPtr) != newBatchSet.end();
     207           16 :         if (!isNewBatch) { // 如果是之前申请的资源需要回退到待分配状态
     208            0 :             batchPtr->availableChannelIdKeys.push_back(allocation.channelIdKey);
     209            0 :             continue;
     210              :         }
     211              : 
     212           16 :         batchesToRemoveByKey[batchPtr->key].insert(batchPtr);
     213              :     }
     214              :     // 本轮新申请的资源需要调用接口释放,使用set去重
     215            9 :     for (const auto &keyEntry : batchesToRemoveByKey) {
     216            4 :         const auto &key = keyEntry.first;
     217            4 :         const auto &batchesToRemove = keyEntry.second;
     218              : 
     219            8 :         for (const auto &batchPtr: batchesToRemove) {
     220           36 :             for (const auto &channelIdKey : batchPtr->channelIdKeys) {
     221           32 :                 const auto dieId = channelIdKey.first;
     222           32 :                 const auto channelId = channelIdKey.second;
     223           32 :                 CHK_RET_THROW(InternalException,
     224              :                     StringFormat("[CcuJettyMgr][%s] failed to release channelId[%u] of "
     225              :                         "die[%u], devLogicId[%d].", __func__, channelId, dieId, devLogicId_),
     226              :                     CcuReleaseChannel(devLogicId_, dieId, channelId));
     227              : 
     228           32 :                 channelJettyInfoMap_.erase(channelIdKey); // 清理新增但未分配的资源信息
     229           32 :                 usedChannelCntMap_[dieId] -= 1;
     230              :             }
     231              :         }
     232              :         // 从batchMap_中清理新增的batch
     233            4 :         auto &batches = batchMap_[key];
     234            4 :         batches.erase(std::remove_if(batches.begin(), batches.end(),
     235            4 :             [&batchesToRemove](const auto &batchPtr) {
     236            4 :                 return batchesToRemove.find(batchPtr.get()) != batchesToRemove.end();
     237            4 :             }), batches.end());
     238              : 
     239            4 :         if (batches.empty()) {
     240            4 :             batchMap_.erase(key);
     241              :         }
     242              :     }
     243            5 : }
     244              : 
     245            5 : void CcuJettyMgr::FallbackAllocatedChannelJettyInfo()
     246              : {
     247              :     // 清理非batch粒度记录的需回退的资源
     248           21 :     for (const auto &allocation : unconfirmedRecord_.allocations) {
     249           16 :         allocatedChannelIdMap_.erase(allocation.link);
     250           16 :         channelJettyInfoMap_.erase(allocation.channelIdKey);
     251           16 :         channelRemoteRankIdMap_.erase(allocation.channelIdKey);
     252           16 :         channelIpAddressMap_.erase(allocation.channelIdKey);
     253              :     }
     254            5 : }
     255              : 
     256            1 : void CcuJettyMgr::Clean()
     257              : {
     258            1 :     ReleaseConfirmedChannelRes();
     259              :     // n秒快恢需要记录链路信息,故仅清空channel信息
     260           17 :     for (auto &linkEntry : allocatedChannelIdMap_) {
     261           16 :         linkEntry.second = {0, 0};
     262              :     }
     263              : 
     264            1 :     batchMap_.clear();
     265            1 :     channelJettyInfoMap_.clear();
     266            1 :     channelRemoteRankIdMap_.clear();
     267            1 :     channelIpAddressMap_.clear();
     268            1 :     usedChannelCntMap_.clear();
     269            1 :     Confirm();
     270            1 : }
     271              : 
     272          271 : void CcuJettyMgr::ReleaseConfirmedChannelRes()
     273              : {
     274          619 :     for (const auto &infoEntry : channelJettyInfoMap_) {
     275          348 :         const auto &channelIdKey = infoEntry.first;
     276          348 :         const auto dieId = channelIdKey.first;
     277          348 :         const auto channelId = channelIdKey.second;
     278          348 :         CHK_RET_THROW(InternalException,
     279              :             StringFormat("[CcuJettyMgr][%s] failed to release channelId[%u] of "
     280              :                 "die[%u], devLogicId[%d].", __func__, channelId, dieId, devLogicId_),
     281              :             CcuReleaseChannel(devLogicId_, dieId, channelId));
     282              :     }
     283          271 :     isReleased = true;
     284          271 : }
     285              : 
     286            1 : void CcuJettyMgr::Resume()
     287              : {
     288            1 :     if (!isReleased) {
     289            0 :         THROW<InternalException>("[CcuJettyMgr][%s] failed, the ccu resources "
     290              :             "have not been released yet, devLogicId[%d].", __func__, devLogicId_);
     291              :     }
     292              : 
     293            1 :     std::vector<LinkData> links;
     294            1 :     links.reserve(allocatedChannelIdMap_.size());
     295           17 :     for (const auto &linkEntry : allocatedChannelIdMap_) {
     296           16 :         links.push_back(linkEntry.first);
     297              :     }
     298            1 :     allocatedChannelIdMap_.clear();
     299              : 
     300            1 :     CHK_RET_THROW(InternalException,
     301              :         StringFormat("[CcuJettyMgr][%s] failed to resume ccu jettys, devLogicId[%d].",
     302              :             __func__, devLogicId_),
     303              :         PrepareCreate(links));
     304            1 : }
     305              : 
     306            2 : uint32_t CcuJettyMgr::GetUsedChannelCount(const uint8_t dieId)
     307              : {
     308            2 :     const auto &dieIter = usedChannelCntMap_.find(dieId);
     309            2 :     if (dieIter != usedChannelCntMap_.end()) {
     310            1 :         return dieIter->second;
     311              :     }
     312            1 :     return 0;
     313              : }
     314              : 
     315            1 : RankId CcuJettyMgr::GetRemoteRankIdByChannelId(const uint8_t dieId, const uint32_t channelId)
     316              : {
     317            1 :     const auto &iter = channelRemoteRankIdMap_.find({dieId, channelId});
     318            1 :     if (iter == channelRemoteRankIdMap_.end()) {
     319            0 :         THROW<InvalidParamsException>("[CcuJettyMgr][%s] failed to find remoteRankId by "
     320              :             "dieId[%u] channelId[%u], devLogicId[%d].", __func__, dieId, channelId,
     321              :             devLogicId_);
     322              :     }
     323              : 
     324            2 :     return iter->second;
     325              : }
     326              : 
     327            0 : std::pair<IpAddress, IpAddress> CcuJettyMgr::GetAddrPairByChannelId(const uint8_t dieId, const uint32_t channelId)
     328              : {
     329            0 :     const auto &iter = channelIpAddressMap_.find({dieId, channelId});
     330            0 :     if (iter == channelIpAddressMap_.end()) {
     331            0 :         THROW<InvalidParamsException>("[CcuJettyMgr][%s] failed to find addrPair by "
     332              :             "dieId[%u] channelId[%u], devLogicId[%d].", __func__, dieId, channelId,
     333              :             devLogicId_);
     334              :     }
     335              : 
     336            0 :     return iter->second;
     337              : }
     338              : 
     339              : } // namespace Hccl
        

Generated by: LCOV version 2.0-1