memorypool.cpp

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#include <atb/types.h>
#include <acl/acl.h>
#include "memorypool.h"
#include "utils/log.h"
#include "utils/utils.h"

constexpr size_t POOL_SIZE = 104857600;  // 预分配内存大小 100 MiB,大小可按实际需求决定

MemoryPool::MemoryPool(size_t poolSize = POOL_SIZE)
{
    // 调用acl接口预分配内存
    CHECK_RET(aclrtMalloc(&baseMemPtr_, poolSize, ACL_MEM_MALLOC_HUGE_FIRST),
        "malloc huge size memrory " + std::to_string(poolSize) + " bytes fail");
    curMemPtr_ = baseMemPtr_;
    remainSize_ = poolSize;
}

MemoryPool::~MemoryPool()
{
    // 销毁时通过acl接口释放内存
    if (baseMemPtr_ != nullptr) {
        CHECK_RET(aclrtFree(baseMemPtr_), "free huge memory fail");
    }
    LOG_INFO("release MemoryPool success");
}

uint64_t MemoryPool::GenerateBlocksId()
{
    return static_cast<uint64_t>(id_.fetch_add(1, std::memory_order_relaxed));
}

void MemoryPool::AllocateBlock(uint32_t size, int &blockId)
{
    std::unique_lock<std::mutex> lock(blockMutex_);

    size_t alignSize = ((size + 31) & ~31) + 32;  // 分配的空间需要32字节对齐后再加32字节

    // 寻找是否有足够大小的空闲内存块
    for (auto it = freeBlocks_.begin(); it != freeBlocks_.end(); it++) {
        if (it->second.blockSize >= alignSize) {
            blockId = it->second.blockId;
            usedBlocks_.insert(*it);
            freeBlocks_.erase(it);
            LOG_INFO("find free block id " + std::to_string(blockId) + " to allocate");
            return;
        }
    }

    // 没有找到符合的内存块,需要从剩余的内存空间中创建新内存块
    if (remainSize_ > alignSize) {
        blockId = GenerateBlocksId();
        uint64_t curMemPtrAlign = (reinterpret_cast<uint64_t>(curMemPtr_) + 63) & ~63;  // 内存地址需要64字节对齐
        remainSize_ -= (curMemPtrAlign - reinterpret_cast<uint64_t>(curMemPtr_));
        curMemPtr_ = reinterpret_cast<void *>(curMemPtrAlign);

        MemoryBlock block = {blockId, alignSize, curMemPtr_};
        usedBlocks_.insert({blockId, block});
        remainSize_ -= alignSize;
        curMemPtr_ = reinterpret_cast<uint8_t *>(curMemPtr_) + alignSize;
        LOG_INFO("allocate block id " + std::to_string(blockId) + " for size " + std::to_string(alignSize));
        return;
    }

    // 剩余的内存空间不足,无法分配内存块
    LOG_ERROR("allocate block fail");
}

void MemoryPool::FreeBlock(int blockId)
{
    std::unique_lock<std::mutex> lock(blockMutex_);

    // 内存块索引合法性校验
    if (blockId < 0) {
        LOG_INFO("skip over the invalid block id " + std::to_string(blockId));
        return;
    }

    // 将需要释放的内存块标记为空闲
    auto it = usedBlocks_.find(blockId);
    if (it != usedBlocks_.end()) {
        freeBlocks_.insert(*it);
        usedBlocks_.erase(it);
    } else {
        LOG_ERROR("Double free block id " + std::to_string(blockId));
    }
}

void MemoryPool::GetBlockPtr(int blockId, void *&addr)
{
    std::unique_lock<std::mutex> lock(blockMutex_);

    if (blockId < 0) {
        LOG_INFO("Invalid block id " + std::to_string(blockId) + "to get ptr");
        return;
    }

    // 寻找内存块,返回物理内存地址
    auto it = usedBlocks_.find(blockId);
    if (it != usedBlocks_.end()) {
        addr = it->second.address;
    } else {
        LOG_ERROR("Get block address error, block id " + std::to_string(blockId));
    }
}