1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-30 00:00:11 +01:00
VILLASnode/fpga/lib/memory.cpp
Daniel Krebs 5242b87e4c lib/memory: rework allocators to make them extensible and more abstract
This is change renders memory allocators only dependend on an address
space id that they are managing, allowing easy implementation of other
algorithms and instantiation in memory IP blocks.
2018-04-13 15:35:41 +02:00

139 lines
3.7 KiB
C++

#include <sys/mman.h>
#include <unistd.h>
#include "memory.hpp"
namespace villas {
std::unique_ptr<MemoryBlock, MemoryBlock::deallocator_fn>
HostRam::HostRamAllocator::allocateBlock(size_t size)
{
/* Align to next bigger page size chunk */
if (size & size_t(0xFFF)) {
size += size_t(0x1000);
size &= size_t(~0xFFF);
}
const int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT;
const int mmap_protection = PROT_READ | PROT_WRITE;
const void* addr = mmap(nullptr, size, mmap_protection, mmap_flags, 0, 0);
if(addr == nullptr) {
throw std::bad_alloc();
}
auto& mm = MemoryManager::get();
// assemble name for this block
std::stringstream name;
name << std::showbase << std::hex << reinterpret_cast<uintptr_t>(addr);
auto blockAddrSpaceId = mm.getProcessAddressSpaceMemoryBlock(name.str());
const auto localAddr = reinterpret_cast<uintptr_t>(addr);
std::unique_ptr<MemoryBlock, MemoryBlock::deallocator_fn>
mem(new MemoryBlock(localAddr, size, blockAddrSpaceId), this->free);
insertMemoryBlock(*mem);
return mem;
}
LinearAllocator::LinearAllocator(MemoryManager::AddressSpaceId memoryAddrSpaceId,
size_t memorySize,
size_t internalOffset) :
BaseAllocator(memoryAddrSpaceId),
nextFreeAddress(0),
memorySize(memorySize),
internalOffset(internalOffset)
{
// make sure to start at aligned offset, reduce size in case we need padding
if(const size_t paddingBytes = getAlignmentPadding(internalOffset)) {
assert(paddingBytes < memorySize);
internalOffset += paddingBytes;
memorySize -= paddingBytes;
}
// deallocation callback
free = [&](MemoryBlock* mem) {
logger->debug("freeing {:#x} bytes at local addr {:#x} (addr space {})",
mem->getSize(), mem->getOffset(), mem->getAddrSpaceId());
logger->warn("free() not implemented");
logger->debug("available memory: {:#x} bytes", getAvailableMemory());
};
}
std::string
LinearAllocator::getName() const
{
std::stringstream name;
name << "LinearAlloc" << getAddrSpaceId()
<< "@0x" << std::hex << internalOffset;
return name.str();
}
std::unique_ptr<MemoryBlock, MemoryBlock::deallocator_fn>
LinearAllocator::allocateBlock(size_t size)
{
if(size > getAvailableMemory()) {
throw std::bad_alloc();
}
// assign address
const uintptr_t localAddr = nextFreeAddress + internalOffset;
// reserve memory
nextFreeAddress += size;
// make sure it is aligned
if(const size_t paddingBytes = getAlignmentPadding(nextFreeAddress)) {
nextFreeAddress += paddingBytes;
// if next free address is outside this block due to padding, cap it
nextFreeAddress = std::min(nextFreeAddress, memorySize);
}
auto& mm = MemoryManager::get();
// assemble name for this block
std::stringstream blockName;
blockName << std::showbase << std::hex << localAddr;
// create address space
auto addrSpaceName = mm.getSlaveAddrSpaceName(getName(), blockName.str());
auto addrSpaceId = mm.getOrCreateAddressSpace(addrSpaceName);
logger->debug("Allocated {:#x} bytes for {}, {:#x} bytes remaining",
size, addrSpaceId, getAvailableMemory());
std::unique_ptr<MemoryBlock, MemoryBlock::deallocator_fn>
mem(new MemoryBlock(localAddr, size, addrSpaceId), this->free);
// mount block into the memory graph
insertMemoryBlock(*mem);
return mem;
}
HostRam::HostRamAllocator
HostRam::allocator;
HostRam::HostRamAllocator::HostRamAllocator() :
BaseAllocator(MemoryManager::get().getProcessAddressSpace())
{
free = [&](MemoryBlock* mem) {
if(::munmap(reinterpret_cast<void*>(mem->getOffset()), mem->getSize()) != 0) {
logger->warn("munmap() failed for {:#x} of size {:#x}",
mem->getOffset(), mem->getSize());
}
};
}
} // namespace villas