LCOV - code coverage report
Current view: top level - legacy/ascend950/unified_platform/ccu/ccu_device/ccu_component - ccu_res_allocator.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 83.1 % 142 118
Test Date: 2026-08-04 10:52:23 Functions: 76.9 % 13 10

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

Generated by: LCOV version 2.0-1