MNN/source/core/BufferAllocator.cpp

212 lines
5.5 KiB
C++
Raw Normal View History

2019-04-17 10:49:11 +08:00
//
// BufferAllocator.cpp
// MNN
//
// Created by MNN on 2018/12/30.
// Copyright © 2018, Alibaba Group Holding Limited
//
2019-12-27 22:16:57 +08:00
#include "core/BufferAllocator.hpp"
#include "core/Macro.h"
2019-04-17 10:49:11 +08:00
//#define DUMP_USAGE
2020-11-05 16:41:56 +08:00
//#define MNN_DEBUG_MEMORY
2019-04-17 10:49:11 +08:00
namespace MNN {
BufferAllocator::Node::~Node() {
if (nullptr == parent) {
MNNMemoryFreeAlign(pointer);
}
}
void* BufferAllocator::alloc(size_t size, bool seperate) {
#ifdef DUMP_USAGE
auto memoryUsed = size / 1024.0f / 1024.0f;
MNN_PRINT("Alloc: %f\n", memoryUsed);
#endif
void* pointer = nullptr;
// reuse if possible
if (!seperate) {
2020-10-25 11:01:04 +08:00
if (nullptr != mCurrentFreeList) {
pointer = getFromFreeList(mCurrentFreeList, size, false);
2019-04-17 10:49:11 +08:00
}
if (nullptr != pointer) {
return pointer;
}
pointer = getFromFreeList(&mFreeList, size);
if (nullptr != pointer) {
return pointer;
}
}
// alloc otherwise
pointer = MNNMemoryAllocAlign(size, mAlign);
if (nullptr == pointer) {
return nullptr;
}
mTotalSize += size;
// save node
2020-11-05 16:41:56 +08:00
auto node = new Node;
2019-04-17 10:49:11 +08:00
node->size = size;
node->pointer = pointer;
mUsedList[pointer] = node;
#ifdef DUMP_USAGE
MNN_PRINT("mTotalSize: %f\n", mTotalSize / 1024.0f / 1024.0f);
#endif
return pointer;
}
2020-11-05 16:41:56 +08:00
void BufferAllocator::returnMemory(FREELIST* listP, Node* node, bool permitMerge) {
2019-04-17 10:49:11 +08:00
auto& list = *listP;
list.insert(std::make_pair(node->size, node));
// update parent use count
if (nullptr != node->parent && permitMerge) {
auto parent = node->parent;
parent->useCount -= 1;
// merge if all subnodes were freed
auto needMerge = parent->useCount == 0;
while (needMerge) {
// collect all subnodes
for (auto iter = list.begin(); iter != list.end();) {
2020-11-05 16:41:56 +08:00
if (iter->second->parent == parent) {
delete iter->second;
2019-04-17 10:49:11 +08:00
iter = list.erase(iter);
continue;
}
iter++;
}
// do merge downside up
list.insert(std::make_pair(parent->size, parent));
needMerge = false;
2020-11-05 16:41:56 +08:00
if (parent->parent != nullptr) {
2019-04-17 10:49:11 +08:00
parent = parent->parent;
parent->useCount -= 1;
needMerge = parent->useCount == 0;
}
}
}
}
bool BufferAllocator::free(void* pointer, bool needRelease) {
// get node
auto x = mUsedList.find(pointer);
if (x == mUsedList.end()) {
MNN_ASSERT(false);
return false;
}
if (needRelease) {
MNN_ASSERT(x->second->parent == nullptr);
2020-11-05 16:41:56 +08:00
MNN_ASSERT(mTotalSize >= x->second->size);
2019-04-17 10:49:11 +08:00
mTotalSize -= x->second->size;
2020-11-05 16:41:56 +08:00
delete x->second;
2019-04-17 10:49:11 +08:00
mUsedList.erase(x);
return true;
}
// mark as reusable
auto node = x->second;
mUsedList.erase(x);
2020-10-25 11:01:04 +08:00
if (nullptr != mCurrentFreeList) {
returnMemory(mCurrentFreeList, node, false);
2019-04-17 10:49:11 +08:00
} else {
returnMemory(&mFreeList, node);
}
#ifdef DUMP_USAGE
auto memoryUsed = x->second->size / 1024.0f / 1024.0f;
MNN_PRINT("Free: %f\n", memoryUsed);
#endif
return true;
}
void BufferAllocator::release(bool allRelease) {
if (allRelease) {
2020-11-05 16:41:56 +08:00
for (auto& u : mUsedList) {
delete u.second;
}
mUsedList.clear();
2020-11-05 16:41:56 +08:00
for (auto& u : mFreeList) {
delete u.second;
}
mFreeList.clear();
mTotalSize = 0;
return;
}
for (auto f : mFreeList) {
2020-11-05 16:41:56 +08:00
if (f.second->parent == nullptr) {
MNN_ASSERT(mTotalSize >= f.first);
mTotalSize -= f.first;
}
delete f.second;
}
2019-04-17 10:49:11 +08:00
mFreeList.clear();
}
void BufferAllocator::barrierBegin() {
MNN_ASSERT(mGroups.empty());
}
void BufferAllocator::barrierEnd() {
for (auto& freeGroup : mGroups) {
auto freeList = *freeGroup;
for (auto& iter : freeList) {
returnMemory(&mFreeList, iter.second);
}
}
mGroups.clear();
}
void BufferAllocator::beginGroup() {
std::shared_ptr<FREELIST> newFreeList(new FREELIST);
2020-10-25 11:01:04 +08:00
mCurrentFreeList = newFreeList.get();
2019-04-17 10:49:11 +08:00
mGroups.emplace_back(newFreeList);
}
void BufferAllocator::endGroup() {
2020-10-25 11:01:04 +08:00
mCurrentFreeList = nullptr;
2019-04-17 10:49:11 +08:00
}
void* BufferAllocator::getFromFreeList(FREELIST* list, size_t size, bool permiteSplit) {
#ifdef MNN_DEBUG_MEMORY
return nullptr;
#endif
// get node larger than size
auto x = list->lower_bound(size);
if (x == list->end()) {
return nullptr;
}
// update parent use count
void* pointer = x->second->pointer;
if (permiteSplit && nullptr != x->second->parent) {
2019-04-17 10:49:11 +08:00
x->second->parent->useCount += 1;
}
// uses up all aligned space
auto sizeAlign = UP_DIV(size, mAlign) * mAlign;
if (sizeAlign >= x->first || (!permiteSplit)) {
mUsedList.insert(std::make_pair(pointer, x->second));
list->erase(x);
return pointer;
}
// split otherwise
2020-11-05 16:41:56 +08:00
auto first = new Node;
2019-04-17 10:49:11 +08:00
first->parent = x->second;
first->size = sizeAlign;
first->pointer = x->second->pointer;
mUsedList.insert(std::make_pair(pointer, first));
x->second->useCount += 1;
2020-11-05 16:41:56 +08:00
auto second = new Node;
2019-04-17 10:49:11 +08:00
second->parent = x->second;
second->size = x->second->size - sizeAlign;
second->pointer = ((uint8_t*)x->second->pointer) + sizeAlign;
list->insert(std::make_pair(second->size, second));
list->erase(x);
return pointer;
}
} // namespace MNN