LCOV - code coverage report
Current view: top level - legacy/ascend910/pub_inc - memory_alloc_ring.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 151 0
Test Date: 2026-08-04 10:52:23 Functions: 0.0 % 21 0

            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              : #ifndef MEMORY_ALLOC_RING_H
      12              : #define MEMORY_ALLOC_RING_H
      13              : #include <atomic>
      14              : #include <mutex>
      15              : #include <semaphore.h>
      16              : #include "log.h"
      17              : #include "hccl/base.h"
      18              : 
      19              : namespace hccl {
      20              : constexpr u32 EXPANSION_MULTIPLES = 2;
      21              : constexpr u32 RING_MEMORY_CAPACITY = 4096;
      22              : 
      23              : template <typename T> class LocklessRingMemoryAllocate {
      24              : public:
      25              :     enum class OperateState {
      26              :         MEMORY_NULL = 0, // 未申请内存
      27              :         MEMORY_PUTTING = 1,  // 正在归还内存块
      28              :         MEMORY_VALID = 2,    // 可用的内存块
      29              :         MEMORY_TAKING = 3    // 正在取出内存块
      30              :     };
      31              : 
      32            0 :     explicit LocklessRingMemoryAllocate(size_t maxCapacity) : capacity_(maxCapacity),
      33            0 :         ringQueue_(nullptr), recordQueue_(nullptr), status_(nullptr), head_(0), tail_(0) {}
      34              : 
      35            0 :     void ResourseClear()
      36              :     {
      37              :         // 之前未加锁 多线程访问可能存在double free 另外本类内存管理过于复杂 后续考虑重构
      38            0 :         std::unique_lock<std::mutex> lock(initDesMutex_);
      39            0 :         if (recordQueue_ != nullptr) {
      40            0 :             for (size_t i = 0; i < capacity_; i++) {
      41            0 :                 if (recordQueue_[i] != nullptr) {
      42            0 :                     delete reinterpret_cast<T *>(recordQueue_[i]);
      43            0 :                     recordQueue_[i] = nullptr;
      44              :                 }
      45              :             }
      46            0 :             delete[] recordQueue_;
      47            0 :             recordQueue_ = nullptr;
      48              :         }
      49              : 
      50            0 :         if (ringQueue_ != nullptr) {
      51            0 :             delete[] ringQueue_;
      52            0 :             ringQueue_ = nullptr;
      53              :         }
      54            0 :         if (status_ != nullptr) {
      55            0 :             delete[] status_;
      56            0 :             status_ = nullptr;
      57              :         }
      58            0 :     }
      59              : 
      60            0 :     ~LocklessRingMemoryAllocate()
      61              :     {
      62            0 :         ResourseClear();
      63            0 :         sem_destroy(&allocAvailable_);
      64            0 :         sem_destroy(&freeAvailable_);
      65            0 :     }
      66              : 
      67            0 :     HcclResult Init()
      68              :     {
      69            0 :         std::unique_lock<std::mutex> lock(initDesMutex_);
      70            0 :         if (recordQueue_ != nullptr) {
      71            0 :             return HCCL_SUCCESS;
      72              :         }
      73            0 :         if (capacity_ > 0) {
      74            0 :             ringQueue_ = new (std::nothrow) T *[capacity_];
      75            0 :             recordQueue_ = new (std::nothrow) T *[capacity_];
      76            0 :             CHK_PTR_NULL(ringQueue_);
      77            0 :             CHK_PTR_NULL(recordQueue_);
      78            0 :             status_ = new (std::nothrow) std::atomic<OperateState>[capacity_];
      79            0 :             CHK_PTR_NULL(status_);
      80            0 :             for (size_t i = 0; i < capacity_; i++) {
      81            0 :                 ringQueue_[i] = new (std::nothrow) T;
      82            0 :                 CHK_PTR_NULL(ringQueue_[i]);
      83            0 :                 status_[i] = OperateState::MEMORY_VALID;
      84            0 :                 tail_++;
      85            0 :                 recordQueue_[i] = ringQueue_[i];
      86              :             }
      87              :         } else {
      88            0 :             HCCL_ERROR("[LocklessRingMemoryAllocate]Capacity incorrect setting [%u]", capacity_);
      89            0 :             return HCCL_E_PARA;
      90              :         }
      91              : 
      92            0 :         auto allocRet = sem_init(&allocAvailable_, 0, capacity_);
      93            0 :         auto freerRet = sem_init(&freeAvailable_, 0, 0);
      94            0 :         if ((allocRet != 0) || (freerRet != 0)) {
      95            0 :             HCCL_ERROR("[LocklessRingMemoryAllocate] sem_init fail! allocRet[%u] freerRet[%u] ", allocRet, freerRet);
      96            0 :             ResourseClear();
      97            0 :             return HCCL_E_PARA;
      98              :         }
      99            0 :         return HCCL_SUCCESS;
     100            0 :     }
     101              : 
     102            0 :     T *Alloc()
     103              :     {
     104            0 :         if (Init() != HCCL_SUCCESS) {
     105            0 :             HCCL_ERROR("Init fail.");
     106            0 :             return nullptr;
     107              :         }
     108            0 :         HCCL_DEBUG("LocklessRingMemoryAllocate::Alloc Start");
     109            0 :         while (sem_trywait(&allocAvailable_) != 0) {
     110            0 :             HCCL_INFO("Alloc limited! head_[%u] tail_[%u]", head_ - 0, tail_ - 0);
     111            0 :             std::unique_lock<std::mutex> lock(expansionMutex_);
     112              :             int value;
     113            0 :             sem_getvalue(&freeAvailable_, &value);
     114            0 :             if ((head_ == tail_) && (static_cast<size_t>(value) == capacity_)) {
     115            0 :                 CapacityExpansion();
     116              :             }
     117            0 :             lock.unlock();
     118              :         }
     119            0 :         T **position = nullptr;
     120            0 :         std::atomic<OperateState> *state = nullptr;
     121            0 :         while (true) {
     122            0 :             size_t index = (head_++) % capacity_;
     123            0 :             position = ringQueue_ + index;
     124            0 :             state = status_ + index;
     125            0 :             OperateState memoryValid = OperateState::MEMORY_VALID;
     126            0 :             if (!(state->compare_exchange_strong(memoryValid, OperateState::MEMORY_TAKING))) {
     127            0 :                 HCCL_WARNING("[LocklessRingMemoryAllocate] Alloc fail!");
     128            0 :                 continue;
     129              :             }
     130            0 :             break;
     131              :         }
     132            0 :         T *memoryBlock = *position;
     133            0 :         *position = nullptr;
     134            0 :         *state = OperateState::MEMORY_NULL;
     135            0 :         sem_post(&freeAvailable_);
     136            0 :         return memoryBlock;
     137              :     }
     138              : 
     139            0 :     HcclResult Free(T *memoryBlock)
     140              :     {
     141              :         {
     142            0 :             std::unique_lock<std::mutex> lock(expansionMutex_);
     143            0 :             while (sem_trywait(&freeAvailable_) != 0) {
     144              :                 int value;
     145            0 :                 sem_getvalue(&allocAvailable_, &value);
     146            0 :                 if (static_cast<size_t>(value) == capacity_) {
     147            0 :                     HCCL_WARNING("[LocklessRingMemoryAllocate] Free limited!");
     148            0 :                     return HCCL_SUCCESS;
     149              :                 }
     150              :             }
     151            0 :         }
     152            0 :         T **position = nullptr;
     153            0 :         std::atomic<OperateState> *state = nullptr;
     154            0 :         while (true) {
     155            0 :             size_t index = (tail_++) % capacity_;
     156            0 :             position = ringQueue_ + index;
     157            0 :             state = status_ + index;
     158            0 :             OperateState memoryNull = OperateState::MEMORY_NULL;
     159            0 :             if (!(state->compare_exchange_strong(memoryNull, OperateState::MEMORY_PUTTING))) {
     160            0 :                 HCCL_WARNING("[LocklessRingMemoryAllocate] Free fail!");
     161            0 :                 continue;
     162              :             }
     163            0 :             break;
     164              :         }
     165            0 :         *position = memoryBlock;
     166            0 :         *state = OperateState::MEMORY_VALID;
     167            0 :         sem_post(&allocAvailable_);
     168            0 :         return HCCL_SUCCESS;
     169              :     }
     170              : 
     171              : private:
     172              :     size_t Length() const
     173              :     {
     174              :         size_t headPos = head_.load();
     175              :         size_t tailPos = tail_.load();
     176              :         if (headPos < tailPos) {
     177              :             return tailPos - headPos;
     178              :         } else {
     179              :             return 0;
     180              :         }
     181              :     }
     182              : 
     183            0 :     HcclResult CapacityExpansion()
     184              :     {
     185            0 :         size_t newCapacity = capacity_ * EXPANSION_MULTIPLES;
     186            0 :         size_t newHead = 0;
     187            0 :         T **newRingQueue = new (std::nothrow) T *[newCapacity];
     188            0 :         if (newRingQueue == nullptr) {
     189            0 :             ResourseClear();
     190            0 :             return HCCL_E_MEMORY;
     191              :         }
     192              : 
     193            0 :         T **newRecordQueue = new (std::nothrow) T *[newCapacity];
     194            0 :         if (newRecordQueue == nullptr) {
     195            0 :             delete[] newRingQueue;
     196            0 :             ResourseClear();
     197            0 :             return HCCL_E_MEMORY;
     198              :         }
     199              : 
     200            0 :         std::atomic<OperateState> *newStatus = new (std::nothrow) std::atomic<OperateState>[newCapacity];
     201            0 :         if (newStatus == nullptr) {
     202            0 :             delete[] newRingQueue;
     203            0 :             delete[] newRecordQueue;
     204            0 :             ResourseClear();
     205            0 :             return HCCL_E_MEMORY;
     206              :         }
     207              : 
     208            0 :         for (size_t i = tail_ - capacity_; i < tail_; i++) {
     209            0 :             newRingQueue[newHead] = nullptr;
     210            0 :             newStatus[newHead].store(status_[i % capacity_]);
     211            0 :             newRecordQueue[newHead] = recordQueue_[i % capacity_];
     212            0 :             newHead++;
     213              :         }
     214              : 
     215            0 :         for (size_t i = newHead; i < newCapacity; i++) {
     216            0 :             newRingQueue[i] = new (std::nothrow) T;
     217            0 :             if (newRingQueue[i] == nullptr) {
     218            0 :                 for (size_t j = newHead; j < i; j++) {
     219            0 :                     delete newRingQueue[j];
     220              :                 }
     221            0 :                 delete[] newStatus;
     222            0 :                 delete[] newRingQueue;
     223            0 :                 delete[] newRecordQueue;
     224            0 :                 ResourseClear();
     225            0 :                 return HCCL_E_MEMORY;
     226              :             }
     227            0 :             newRecordQueue[i] = newRingQueue[i];
     228            0 :             newStatus[i] = OperateState::MEMORY_VALID;
     229              :         }
     230              : 
     231            0 :         if (ringQueue_ != nullptr) {
     232            0 :             delete[] ringQueue_;
     233              :         }
     234            0 :         if (recordQueue_ != nullptr) {
     235            0 :             delete[] recordQueue_;
     236              :         }
     237            0 :         if (status_ != nullptr) {
     238            0 :             delete[] status_;
     239              :         }
     240              : 
     241            0 :         ringQueue_ = newRingQueue;
     242            0 :         recordQueue_ = newRecordQueue;
     243            0 :         status_ = newStatus;
     244            0 :         head_ = newHead;
     245            0 :         tail_ = newCapacity;
     246            0 :         capacity_ = newCapacity;
     247              : 
     248            0 :         for (size_t i = 0; i < newCapacity - newHead; i++) {
     249            0 :             sem_post(&allocAvailable_);
     250              :         }
     251            0 :         return HCCL_SUCCESS;
     252              :     }
     253              : 
     254              :     size_t capacity_ = 0;                              // 容量
     255              :     T **ringQueue_ = nullptr;                          // 内存块数组
     256              :     T **recordQueue_ = nullptr;                        // 内存记录
     257              :     std::atomic<OperateState> *status_ = nullptr;      // 每一个内存块的状态
     258              :     std::atomic<size_t> head_;                         // 逻辑上的头
     259              :     std::atomic<size_t> tail_;                         // 逻辑上的尾
     260              :     sem_t allocAvailable_;                             // 可以申请的内存块个数
     261              :     sem_t freeAvailable_;                              // 可以释放的内存块个数
     262              :     std::mutex expansionMutex_;                        // 扩容锁
     263              :     std::mutex initDesMutex_;                          // 初始化析构锁
     264              : };
     265              : }
     266              : #endif
        

Generated by: LCOV version 2.0-1