godot_voxel/storage/voxel_memory_pool.cpp

166 lines
4.3 KiB
C++
Raw Normal View History

#include "voxel_memory_pool.h"
#include "../util/macros.h"
#include "../util/profiling.h"
#include <core/os/os.h>
#include <core/string/print_string.h>
#include <core/variant/variant.h>
namespace {
VoxelMemoryPool *g_memory_pool = nullptr;
} // namespace
void VoxelMemoryPool::create_singleton() {
CRASH_COND(g_memory_pool != nullptr);
g_memory_pool = memnew(VoxelMemoryPool);
}
void VoxelMemoryPool::destroy_singleton() {
CRASH_COND(g_memory_pool == nullptr);
VoxelMemoryPool *pool = g_memory_pool;
g_memory_pool = nullptr;
memdelete(pool);
}
VoxelMemoryPool *VoxelMemoryPool::get_singleton() {
CRASH_COND(g_memory_pool == nullptr);
return g_memory_pool;
}
VoxelMemoryPool::VoxelMemoryPool() {}
VoxelMemoryPool::~VoxelMemoryPool() {
2020-01-25 17:59:53 -08:00
#ifdef TOOLS_ENABLED
if (OS::get_singleton()->is_stdout_verbose()) {
debug_print();
}
2020-01-25 17:59:53 -08:00
#endif
clear();
}
uint8_t *VoxelMemoryPool::allocate(size_t size) {
2020-08-30 10:51:45 -07:00
VOXEL_PROFILE_SCOPE();
CRASH_COND(size == 0);
uint8_t *block = nullptr;
// Not calculating `pot` immediately because the function we use to calculate it uses 32 bits,
// while `size_t` can be larger than that.
if (size > get_highest_supported_size()) {
// Sorry, memory is not pooled past this size
block = (uint8_t *)memalloc(size * sizeof(uint8_t));
2021-11-14 10:40:50 -08:00
#ifdef DEBUG_ENABLED
if (block != nullptr) {
_debug_nonpooled_used_blocks.add(block);
}
#endif
} else {
const unsigned int pot = get_pool_index_from_size(size);
Pool &pool = _pot_pools[pot];
pool.mutex.lock();
if (pool.blocks.size() > 0) {
block = pool.blocks.back();
pool.blocks.pop_back();
pool.mutex.unlock();
} else {
pool.mutex.unlock();
2021-11-14 11:22:13 -08:00
// All allocations done in this pool have the same size,
// which must be greater or equal to `size`
const size_t capacity = get_size_from_pool_index(pot);
#ifdef DEBUG_ENABLED
CRASH_COND(capacity < size);
#endif
block = (uint8_t *)memalloc(capacity * sizeof(uint8_t));
}
#ifdef DEBUG_ENABLED
2021-11-14 10:40:50 -08:00
if (block != nullptr) {
pool.debug_used_blocks.add(block);
}
#endif
2021-11-14 10:40:50 -08:00
}
if (block == nullptr) {
ERR_PRINT("Out of memory");
} else {
++_used_blocks;
_used_memory += size;
}
return block;
}
void VoxelMemoryPool::recycle(uint8_t *block, size_t size) {
CRASH_COND(size == 0);
CRASH_COND(block == nullptr);
// Not calculating `pot` immediately because the function we use to calculate it uses 32 bits,
// while `size_t` can be larger than that.
if (size > get_highest_supported_size()) {
2021-11-14 10:40:50 -08:00
#ifdef DEBUG_ENABLED
// Make sure this allocation was done by this pool in this scenario
_debug_nonpooled_used_blocks.remove(block);
#endif
memfree(block);
} else {
const unsigned int pot = get_pool_index_from_size(size);
Pool &pool = _pot_pools[pot];
2021-11-14 10:40:50 -08:00
#ifdef DEBUG_ENABLED
// Make sure this allocation was done by this pool in this scenario
pool.debug_used_blocks.remove(block);
#endif
MutexLock lock(pool.mutex);
pool.blocks.push_back(block);
}
2020-01-25 17:59:53 -08:00
--_used_blocks;
_used_memory -= size;
}
void VoxelMemoryPool::clear_unused_blocks() {
for (unsigned int pot = 0; pot < _pot_pools.size(); ++pot) {
Pool &pool = _pot_pools[pot];
MutexLock lock(pool.mutex);
for (unsigned int i = 0; i < pool.blocks.size(); ++i) {
void *block = pool.blocks[i];
memfree(block);
}
_total_memory -= get_size_from_pool_index(pot) * pool.blocks.size();
pool.blocks.clear();
}
}
void VoxelMemoryPool::clear() {
for (unsigned int pot = 0; pot < _pot_pools.size(); ++pot) {
Pool &pool = _pot_pools[pot];
MutexLock lock(pool.mutex);
for (unsigned int i = 0; i < pool.blocks.size(); ++i) {
void *block = pool.blocks[i];
memfree(block);
}
pool.blocks.clear();
}
_used_memory = 0;
_total_memory = 0;
2021-10-03 17:33:32 -07:00
_used_blocks = 0;
}
void VoxelMemoryPool::debug_print() {
print_line("-------- VoxelMemoryPool ----------");
for (unsigned int pot = 0; pot < _pot_pools.size(); ++pot) {
Pool &pool = _pot_pools[pot];
MutexLock lock(pool.mutex);
print_line(String("Pool {0}: {1} blocks (capacity {2})")
.format(varray(pot, SIZE_T_TO_VARIANT(pool.blocks.size()),
SIZE_T_TO_VARIANT(pool.blocks.capacity()))));
}
}
2020-01-25 17:59:53 -08:00
unsigned int VoxelMemoryPool::debug_get_used_blocks() const {
//MutexLock lock(_mutex);
2020-01-25 17:59:53 -08:00
return _used_blocks;
}
size_t VoxelMemoryPool::debug_get_used_memory() const {
//MutexLock lock(_mutex);
return _used_memory;
}
size_t VoxelMemoryPool::debug_get_total_memory() const {
//MutexLock lock(_mutex);
return _total_memory;
}