LCOV - code coverage report
Current view: top level - base_comm/resources/ccu/ccu_device/ccu_comp - ccu_res_allocator.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 92.0 % 175 161
Test Date: 2026-08-18 17:47:01 Functions: 93.3 % 15 14

            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_res_allocator.h"
      12              : 
      13              : #include <algorithm>
      14              : #include <climits>
      15              : 
      16              : #include "ccu_res_specs.h"
      17              : 
      18              : namespace hcomm {
      19              : 
      20         2111 : HcclResult CcuResIdAllocator::Alloc(
      21              :     const uint32_t num, const bool consecutive, std::vector<ResInfo>& allocatedResInfos, const std::string& dfxInfo)
      22              : {
      23         2111 :     CHK_PRT_RET(
      24              :         num == 0, HCCL_ERROR("[CcuResIdAllocator][%s] failed, request num is 0.", __func__), HcclResult::HCCL_E_PARA);
      25              : 
      26         2110 :     std::unique_lock<std::mutex> lock(innerMutex_);
      27              :     // 快速判断是否可以分配
      28         2110 :     const uint32_t freeSize = capacity_ - allocatedSize_;
      29         2110 :     if (num > freeSize) {
      30            2 :         HCCL_WARNING(
      31              :             "[CcuResIdAllocator][%s] failed, resType[%s], requested num[%u] exceeds "
      32              :             "currently free size[%u].",
      33              :             __func__, dfxInfo.c_str(), num, freeSize);
      34            2 :         HCCL_RUN_INFO("Insufficient CCU Resource: %s, requestNum[%u], freeNum[%u].", dfxInfo.c_str(), num, freeSize);
      35            2 :         return HcclResult::HCCL_E_UNAVAIL;
      36              :     }
      37              : 
      38         2108 :     std::vector<ResInfo> newResInfos;
      39         2108 :     uint32_t leftNum = num;
      40         2108 :     uint32_t tryStartId = 0;
      41              :     // 对于要求连续的资源需要提供一个足够大小的空闲块
      42              :     // 对于非连续需要每次不为 0
      43         2108 :     const uint32_t limitSize = consecutive ? num - 1 : 0;
      44              :     // 顺序优先分配,遍历已分配的连续块,寻找当前块与下个块之间是否有足够大小空间
      45         2108 :     resInfos_.emplace_back(capacity_, 0); // 临时添加一个尾资源,简化判断逻辑
      46         2690 :     for (size_t i = 0; i < resInfos_.size(); i++) {
      47         2689 :         const auto& resInfo = resInfos_[i];
      48         2689 :         uint32_t partNum = std::min(resInfo.startId - tryStartId, leftNum);
      49         2689 :         if (partNum > limitSize) {
      50         2107 :             newResInfos.emplace_back(tryStartId, partNum); // 该空闲块足够大,分配
      51         2107 :             leftNum -= partNum;
      52         2107 :             if (leftNum == 0) {
      53         2107 :                 break;
      54              :             }
      55              :         }
      56          582 :         tryStartId = resInfo.startId + resInfo.num; // 更新当前块起始位置
      57              :     }
      58         2108 :     resInfos_.pop_back(); // 删除临时添加的尾资源
      59              :     // 只有连续要求的资源才可能剩余,此时分配失败,新块为空
      60         2108 :     if (leftNum != 0) {
      61            1 :         HCCL_WARNING(
      62              :             "[CcuResIdAllocator][%s] failed, no enough consecutive free "
      63              :             "resource ids for requested num[%u].",
      64              :             __func__, num);
      65            1 :         HCCL_RUN_INFO(
      66              :             "Insufficient CCU Resource: consecutived %s, requestNum[%u], freeNum[%u].", dfxInfo.c_str(), num, freeSize);
      67            1 :         return HcclResult::HCCL_E_UNAVAIL;
      68              :     }
      69              : 
      70         2107 :     allocatedSize_ += num;
      71         2107 :     AllocResInfo(newResInfos); // 将分配的所有资源记录
      72         2107 :     allocatedResInfos = newResInfos;
      73         2107 :     return HcclResult::HCCL_SUCCESS;
      74         2110 : }
      75              : 
      76         2107 : void CcuResIdAllocator::AllocResInfo(std::vector<ResInfo> newResInfos)
      77              : {
      78         2107 :     if (resInfos_.empty()) { // 首次分配直接添加块
      79         1526 :         resInfos_.emplace_back(newResInfos.front());
      80         1526 :         return;
      81              :     }
      82              :     // 内部变量始终维护最简的连续块,对需要合并的块更新
      83          581 :     size_t newIdx = 0;
      84          581 :     size_t idx = 0;
      85         1162 :     while (newIdx < newResInfos.size() && idx < resInfos_.size()) {
      86          581 :         auto& newResInfo = newResInfos[newIdx];
      87          581 :         auto& resInfo = resInfos_[idx];
      88              :         // 跳过无关的资源块,使得resInfo是newResInfo的后续块
      89          581 :         if (newResInfo.startId >= resInfo.startId) {
      90          580 :             idx++;
      91          580 :             continue;
      92              :         }
      93              :         // 检查当前块是否与后续块连续,如果连续则合并
      94            1 :         if (newResInfo.startId == resInfo.startId - newResInfo.num) {
      95            1 :             newResInfo.num += resInfo.num;
      96            1 :             resInfos_.erase(resInfos_.begin() + idx);
      97              :         }
      98              :         // 如果当前块是首块则插入首块
      99            1 :         if (idx == 0) {
     100            1 :             resInfos_.insert(resInfos_.begin(), newResInfo);
     101            1 :             newIdx++;
     102            1 :             continue;
     103              :         }
     104              :         // 分配保证如果当前块不是首块则一定与前一个块连续,更新前一个块
     105            0 :         resInfos_[idx - 1].num += newResInfo.num;
     106            0 :         newIdx++;
     107              :     }
     108              :     // 如果有剩余块一定与最后一个块连续,更新最后一个块
     109          581 :     if (newIdx < newResInfos.size()) {
     110          580 :         resInfos_.back().num += newResInfos.back().num;
     111              :     }
     112              : }
     113              : 
     114          115 : static HcclResult CheckReleasePara(const uint32_t startId, const uint32_t num, const uint32_t capacity)
     115              : {
     116          115 :     CHK_PRT_RET(
     117              :         num == 0, HCCL_ERROR("[CcuResIdAllocator][%s] failed, resource num is 0.", __func__), HcclResult::HCCL_E_PARA);
     118              : 
     119          114 :     CHK_PRT_RET(
     120              :         num > capacity,
     121              :         HCCL_ERROR(
     122              :             "[CcuResIdAllocator][%s] failed, resource num[%u] "
     123              :             "is greater than capacity[%u]",
     124              :             __func__, num, capacity),
     125              :         HcclResult::HCCL_E_PARA);
     126              : 
     127          113 :     CHK_PRT_RET(
     128              :         startId > capacity - num,
     129              :         HCCL_ERROR(
     130              :             "[CcuResIdAllocator][%s] failed, resource startId[%u] "
     131              :             "num[%u] capacity[%u]",
     132              :             __func__, startId, num, capacity),
     133              :         HcclResult::HCCL_E_PARA);
     134              : 
     135          112 :     return HcclResult::HCCL_SUCCESS;
     136              : }
     137              : 
     138          115 : HcclResult CcuResIdAllocator::Release(const uint32_t startId, const uint32_t num)
     139              : {
     140          115 :     CHK_RET(CheckReleasePara(startId, num, capacity_));
     141              : 
     142          112 :     std::unique_lock<std::mutex> lock(innerMutex_);
     143              : 
     144              :     // 找到需要释放的资源块
     145          112 :     const size_t resIndex = FindReleaseResIndex(startId);
     146          112 :     CHK_PRT_RET(
     147              :         resIndex >= resInfos_.size(),
     148              :         HCCL_ERROR(
     149              :             "[CcuResIdAllocator][%s] failed, resource startId[%u] num[%u] "
     150              :             "has not been allocated yet. ",
     151              :             __func__, startId, num),
     152              :         HcclResult::HCCL_E_PARA);
     153              : 
     154              :     // 判断申请释放的资源是否越界
     155          111 :     const auto& resInfo = resInfos_[resIndex];
     156          111 :     uint32_t allocatedNum = resInfo.startId + resInfo.num - startId;
     157          111 :     CHK_PRT_RET(
     158              :         num > allocatedNum,
     159              :         HCCL_ERROR(
     160              :             "[CcuResIdAllocator][%s] failed, resource num[%u] is greater "
     161              :             "than the allocated num[%u].",
     162              :             __func__, num, allocatedNum),
     163              :         HcclResult::HCCL_E_PARA);
     164              : 
     165              :     // 将资源块释放并更新
     166          110 :     ReleaseResInfo(resIndex, startId, num);
     167          110 :     return HcclResult::HCCL_SUCCESS;
     168          112 : }
     169              : 
     170          112 : size_t CcuResIdAllocator::FindReleaseResIndex(const uint32_t startId) const
     171              : {
     172          112 :     size_t resIndex = 0;
     173          112 :     const size_t maxIndex = resInfos_.size();
     174          112 :     while (resIndex < maxIndex) {
     175          111 :         const auto& resInfo = resInfos_[resIndex];
     176          111 :         if (startId >= resInfo.startId + resInfo.num) {
     177            0 :             resIndex++;
     178            0 :             continue;
     179              :         }
     180          111 :         if (startId >= resInfo.startId) {
     181          111 :             break; // 资源id属于该资源块
     182              :         }
     183            0 :         return maxIndex; // 无法找到已分配资源块,返回错误索引
     184              :     }
     185          112 :     return resIndex;
     186              : }
     187              : 
     188          110 : void CcuResIdAllocator::ReleaseResInfo(const size_t resIndex, const uint32_t startId, const uint32_t num)
     189              : {
     190          110 :     allocatedSize_ -= num;
     191              : 
     192          110 :     auto& resInfo = resInfos_[resIndex];
     193              :     // 释放的资源在资源块起始部分
     194          110 :     if (startId == resInfo.startId) {
     195              :         // 恰好是整块资源,则全部释放
     196           52 :         if (num == resInfo.num) {
     197           49 :             resInfos_.erase(resInfos_.begin() + resIndex);
     198          109 :             return;
     199              :         }
     200              :         // 非整块资源则更新资源块起始位置和大小
     201            3 :         resInfo.startId += num;
     202            3 :         resInfo.num -= num;
     203            3 :         return;
     204              :     }
     205              : 
     206           58 :     uint32_t leftNum = startId - resInfo.startId;
     207           58 :     uint32_t rightNum = resInfo.num - leftNum - num;
     208              :     // 释放的资源在资源块末尾,更新资源块大小
     209           58 :     if (rightNum == 0) {
     210           57 :         resInfo.num -= num;
     211           57 :         return;
     212              :     }
     213              :     // 释放的资源在资源块中间,拆分为两个资源块
     214            1 :     resInfo.num = leftNum; // 左部分块更新数据
     215              :     // 右部分块需要新增
     216            1 :     resInfos_.emplace(resInfos_.begin() + resIndex + 1, startId + num, rightNum);
     217              : }
     218              : 
     219          210 : HcclResult CcuResAllocator::Init()
     220              : {
     221          210 :     auto& ccuResSpecs = CcuResSpecifications::GetInstance(devLogicId_);
     222              :     // 获取静态定义的资源规格查询函数列表,遍历构造
     223          210 :     uint32_t capacity = 0;
     224         1890 :     for (const auto& pair : CcuResSpecifications::GET_RES_SPEC_FUNC_ARRAY) {
     225         1680 :         const ResType resType = pair.first;
     226         1680 :         const CcuResSpecifications::GetResSpecFunc getFunc = pair.second;
     227         1680 :         (void)(ccuResSpecs.*getFunc)(dieId_, capacity); // 获取失败时容量为 0,后续分配按资源不足处理
     228         1680 :         std::unique_ptr<CcuResIdAllocator> allocatorPtr = nullptr;
     229         1680 :         HCCL_RUN_INFO(
     230              :             "[CcuResAllocator][%s] resType[%s], capacity[%u]", __func__, resType.Describe().c_str(), capacity);
     231         1680 :         allocatorPtr.reset((new (std::nothrow) CcuResIdAllocator(capacity)));
     232         1680 :         CHK_PTR_NULL(allocatorPtr);
     233         1680 :         idAllocatorMap_[static_cast<uint8_t>(resType)] = std::move(allocatorPtr);
     234         1680 :     }
     235              : 
     236          210 :     (void)ccuResSpecs.GetXnNum(dieId_, xnSpecNum_);
     237          210 :     (void)ccuResSpecs.GetCountXnNum(dieId_, countXnSpecNum_);
     238          210 :     return HcclResult::HCCL_SUCCESS;
     239              : }
     240              : 
     241         1724 : HcclResult CcuResAllocator::Alloc(
     242              :     const ResType resType, const uint32_t num, const bool consecutive, std::vector<ResInfo>& resInfos)
     243              : {
     244         1724 :     auto resTypeIter = idAllocatorMap_.find(static_cast<uint8_t>(resType));
     245         1724 :     if (resTypeIter == idAllocatorMap_.end()) {
     246            1 :         HCCL_ERROR("[CcuResAllocator][%s] failed, invalid resource type[%s].", __func__, resType.Describe().c_str());
     247            1 :         return HcclResult::HCCL_E_PARA;
     248              :     }
     249         1723 :     return resTypeIter->second->Alloc(num, consecutive, resInfos, resType.Describe());
     250              : }
     251              : 
     252           77 : HcclResult CcuResAllocator::Release(const ResType resType, const uint32_t startId, const uint32_t num)
     253              : {
     254           77 :     auto resTypeIter = idAllocatorMap_.find(static_cast<uint8_t>(resType));
     255           77 :     if (resTypeIter == idAllocatorMap_.end()) {
     256            1 :         HCCL_ERROR("[CcuResAllocator][%s] failed, invalid resource type[%s].", __func__, resType.Describe().c_str());
     257            1 :         return HcclResult::HCCL_E_PARA;
     258              :     }
     259           76 :     return resTypeIter->second->Release(startId, num);
     260              : }
     261              : 
     262            2 : uint32_t CcuResIdAllocator::GetConsecutiveRemainSize() const
     263              : {
     264              :     // 扫描 resInfos_ 找最大连续空闲区 (类似 QueryRemainRes 的 gap scan)
     265            2 :     uint32_t cursor = 0;
     266            2 :     uint32_t maxGap = 0;
     267            5 :     for (const auto& r : resInfos_) {
     268            3 :         if (r.startId > cursor) {
     269            1 :             maxGap = std::max(maxGap, r.startId - cursor);
     270              :         }
     271            3 :         cursor = r.startId + r.num;
     272              :     }
     273            2 :     if (capacity_ > cursor) {
     274            1 :         maxGap = std::max(maxGap, capacity_ - cursor);
     275              :     }
     276            2 :     return maxGap;
     277              : }
     278              : 
     279            1 : std::string CcuResIdAllocator::Describe() const
     280              : {
     281              :     return Hccl::StringFormat(
     282              :         "CcuResIdAllocator[capacity=%u, allocatedSize=%u, "
     283              :         "resInfos_size=%u]",
     284            1 :         capacity_, allocatedSize_, resInfos_.size());
     285              : }
     286              : 
     287            0 : uint32_t CcuResAllocator::GetConsecutiveRemainSize(const ResType resType) const
     288              : {
     289            0 :     auto it = idAllocatorMap_.find(static_cast<uint8_t>(resType));
     290            0 :     if (it == idAllocatorMap_.end())
     291            0 :         return 0;
     292            0 :     return it->second->GetConsecutiveRemainSize();
     293              : }
     294              : 
     295            1 : std::string CcuResAllocator::Describe() const
     296              : {
     297              :     return Hccl::StringFormat(
     298              :         "CcuResAllocator[devLogicId=%u, dieId=%u, "
     299              :         "idAllocatorSize=[%u]]",
     300            1 :         devLogicId_, dieId_, idAllocatorMap_.size());
     301              : }
     302              : 
     303            3 : HcclResult CcuResAllocator::AllocCountXn(const uint32_t num, ResInfo& resInfo)
     304              : {
     305            3 :     constexpr ResType resType = ResType::COUNT_XN;
     306            3 :     auto resTypeIter = idAllocatorMap_.find(static_cast<uint8_t>(resType));
     307            3 :     if (resTypeIter == idAllocatorMap_.end()) {
     308            0 :         HCCL_ERROR("[CcuResAllocator][%s] failed, invalid resource type[%s].", __func__, resType.Describe().c_str());
     309            0 :         return HcclResult::HCCL_E_PARA;
     310              :     }
     311              : 
     312            3 :     std::vector<ResInfo> resInfos;
     313            6 :     auto ret = resTypeIter->second->Alloc(num, true, resInfos);
     314            3 :     if (ret == HcclResult::HCCL_E_UNAVAIL) {
     315            1 :         HCCL_WARNING(
     316              :             "[CcuResAllocator][%s] failed, count xn resources are unavailable, ",
     317              :             "retry to allocate with normal xn resources, num[%u], devLogicId[%d].", __func__, num, devLogicId_);
     318            1 :         ret = Alloc(ResType::XN, num, true, resInfos);
     319            1 :         if (ret == HcclResult::HCCL_SUCCESS) {
     320            1 :             resInfo = resInfos[0]; // 连续分配成功时,一定只有一个元素
     321              :         }
     322            1 :         return ret;
     323              :     }
     324            2 :     CHK_RET(ret);
     325              :     // CountXn编号切换为全局Xn编号
     326            2 :     resInfo.startId = resInfos[0].startId + xnSpecNum_;
     327            2 :     resInfo.num = resInfos[0].num;
     328            2 :     return HcclResult::HCCL_SUCCESS;
     329            3 : }
     330              : 
     331            2 : HcclResult CcuResAllocator::ReleaseCountXn(const uint32_t startId, const uint32_t num)
     332              : {
     333            2 :     if (startId < xnSpecNum_) { // 未超过Xn规格则为普通Xn
     334            1 :         return Release(ResType::XN, startId, num);
     335              :     }
     336              : 
     337            1 :     constexpr ResType resType = ResType::COUNT_XN;
     338            1 :     auto resTypeIter = idAllocatorMap_.find(static_cast<uint8_t>(resType));
     339            1 :     if (resTypeIter == idAllocatorMap_.end()) {
     340            0 :         HCCL_ERROR("[CcuResAllocator][%s] failed, invalid resource type[%s].", __func__, resType.Describe().c_str());
     341            0 :         return HcclResult::HCCL_E_PARA;
     342              :     }
     343            1 :     return resTypeIter->second->Release(startId - xnSpecNum_, num);
     344              : }
     345              : } // namespace hcomm
        

Generated by: LCOV version 2.0-1