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: 94.4 % 160 151
Test Date: 2026-07-28 12:11:00 Functions: 100.0 % 13 13

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

Generated by: LCOV version 2.0-1