mirror of
https://github.com/mmueller41/genode.git
synced 2026-01-21 12:32:56 +01:00
ealanos: Rewrote parts of memory allocator to be no longer depending on Bit_alloc, as this proved to consume too much memory per superblock.
This commit is contained in:
@@ -52,34 +52,50 @@ class Ealan::Memory::Core_heap
|
||||
{
|
||||
Tukija::uint8_t mem_regions = 0;
|
||||
_tip = const_cast<Tip *>(Tip::tip());
|
||||
Tip::Memory_region ®ion = _tip->memory_for_domain(domain_id, &mem_regions);
|
||||
Range_allocator::Range range = {.start = reinterpret_cast<addr_t>(region.start), .end = reinterpret_cast<addr_t>(region.end)};
|
||||
try {
|
||||
Tip::Memory_region ®ion = _tip->memory_for_domain(domain_id, &mem_regions);
|
||||
Range_allocator::Range range = {.start = reinterpret_cast<addr_t>(region.start), .end = reinterpret_cast<addr_t>(region.end)};
|
||||
|
||||
Ram_dataspace_capability ds_cap = _pd.try_alloc_from_range(size, Genode::CACHED, range).convert<Ram_dataspace_capability>(
|
||||
[&](Ram_dataspace_capability cap) { return cap; },
|
||||
[&](Ram_allocator::Alloc_error) { return Ram_dataspace_capability(); });
|
||||
Ram_dataspace_capability ds_cap = _pd.try_alloc_from_range(size, Genode::CACHED, range).convert<Ram_dataspace_capability>([&](Ram_dataspace_capability cap)
|
||||
{ return cap; },
|
||||
[&](Ram_allocator::Alloc_error err)
|
||||
{
|
||||
Genode::error("Failed to allocate phyiscal memory in domain ", domain_id, ":", err);
|
||||
return Ram_dataspace_capability(); });
|
||||
|
||||
if (!ds_cap.valid())
|
||||
if (!ds_cap.valid()) {
|
||||
Genode::warning("Failed to allocate physical memory for hyperblock");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Region_map::Attr attr{};
|
||||
attr.writeable = true;
|
||||
void *hb = _rm.attach(ds_cap, attr).convert<void *>(
|
||||
[&](Region_map::Range r) { return reinterpret_cast<void *>(r.start); },
|
||||
[&](Region_map::Attach_error) { return nullptr; });
|
||||
|
||||
if (!hb) {
|
||||
Genode::warning("Failed to obtain regionmap for hyperblock");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Hyperblock *hyperblock = new (hb) Hyperblock();
|
||||
hyperblock->cap = ds_cap;
|
||||
|
||||
return hyperblock;
|
||||
} catch (Tukija::Tip::Domain_has_no_memory_regions) {
|
||||
Genode::error("Domain ", domain_id, " has no memory regions.");
|
||||
return nullptr;
|
||||
|
||||
Region_map::Attr attr{};
|
||||
attr.writeable = true;
|
||||
void *hb = _rm.attach(ds_cap, attr).convert<void *>(
|
||||
[&](Region_map::Range r) { return reinterpret_cast<void *>(r.start); },
|
||||
[&](Region_map::Attach_error) { return nullptr; });
|
||||
|
||||
if (!hb)
|
||||
return nullptr;
|
||||
|
||||
Hyperblock *hyperblock = new (hb) Hyperblock();
|
||||
hyperblock->cap = ds_cap;
|
||||
|
||||
return hyperblock;
|
||||
}
|
||||
}
|
||||
|
||||
Sb *_allocate_superblock(unsigned domain_id, Genode::size_t sz_class)
|
||||
{
|
||||
Hyperblock *hb = _allocate_hyperblock(domain_id, MAX * 2);
|
||||
if (!hb) {
|
||||
Genode::warning("Failed to allocate superblock for size class ", sz_class, " in domain ", domain_id);
|
||||
return nullptr;
|
||||
}
|
||||
return new (static_cast<void *>(hb)) Superblock<MAX * 2, MIN>(sz_class);
|
||||
}
|
||||
|
||||
@@ -87,7 +103,11 @@ class Ealan::Memory::Core_heap
|
||||
Core_heap &operator=(Core_heap &);
|
||||
|
||||
public:
|
||||
Core_heap(Pd_session &pd, Region_map &rm) : _pd(pd), _rm(rm) {}
|
||||
Core_heap(Pd_session &pd, Region_map &rm) : _pd(pd), _rm(rm) {
|
||||
Genode::log("Size of superblock array is ", sizeof(_superblocks));
|
||||
Genode::log("Individual superblock size is: ", sizeof(Sb));
|
||||
Genode::log("Size of individual ist of superblocks: ", sizeof(Ealan::util::MPSCQueue<Sb>));
|
||||
}
|
||||
|
||||
~Core_heap()
|
||||
{
|
||||
@@ -106,7 +126,10 @@ class Ealan::Memory::Core_heap
|
||||
|
||||
void *aligned_alloc(Genode::size_t size, unsigned domain_id, Genode::size_t alignment)
|
||||
{
|
||||
if (size > MAX) {
|
||||
void *ptr = nullptr;
|
||||
|
||||
if (size > MAX)
|
||||
{
|
||||
/* directly allocate a hyperblock */
|
||||
Hyperblock *hb = _allocate_hyperblock(domain_id, size+sizeof(Hyperblock*) + sizeof(Ram_dataspace_capability));
|
||||
hb->_next = reinterpret_cast<Hyperblock*>(magic_num);
|
||||
@@ -118,18 +141,26 @@ class Ealan::Memory::Core_heap
|
||||
|
||||
if (!sb) {
|
||||
sb = _allocate_superblock(domain_id, sz_class);
|
||||
if (!sb)
|
||||
return nullptr;
|
||||
_superblocks[sz_class / MIN - 1][domain_id].push_back(sb);
|
||||
} else if (sb->free_blocks() == 0) {
|
||||
for (; sb && sb->free_blocks() == 0; sb = static_cast<Sb*>(sb->next()))
|
||||
;
|
||||
if (!sb) {
|
||||
Sb *new_sb = _allocate_superblock(domain_id, sz_class);
|
||||
_superblocks[sz_class / MIN - 1][domain_id].push_back(new_sb);
|
||||
sb = new_sb;
|
||||
}
|
||||
}
|
||||
|
||||
for (; sb != nullptr ; sb = static_cast<Sb*>(sb->next())) {
|
||||
ptr = sb->aligned_alloc(alignment);
|
||||
if (ptr)
|
||||
return ptr;
|
||||
}
|
||||
|
||||
if (!sb) {
|
||||
sb = _allocate_superblock(domain_id, sz_class);
|
||||
if (!sb)
|
||||
return nullptr;
|
||||
_superblocks[sz_class / MIN - 1][domain_id].push_back(sb);
|
||||
return sb->aligned_alloc(alignment);
|
||||
}
|
||||
|
||||
return sb->aligned_alloc(alignment);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *aligned_alloc(Genode::size_t size, Genode::size_t alignment)
|
||||
@@ -152,6 +183,10 @@ class Ealan::Memory::Core_heap
|
||||
|
||||
void free(void *ptr, Genode::size_t alignment = 0)
|
||||
{
|
||||
if (!ptr) {
|
||||
Genode::warning("Tried to free nullptr");
|
||||
return;
|
||||
}
|
||||
void *p = reinterpret_cast<void *>((reinterpret_cast<addr_t>(ptr) - sizeof(Hyperblock *) - sizeof(Ram_dataspace_capability)));
|
||||
Hyperblock *hb = reinterpret_cast<Hyperblock *>(p);
|
||||
|
||||
@@ -166,8 +201,16 @@ class Ealan::Memory::Core_heap
|
||||
|
||||
Block *b = Block::metadata(p);
|
||||
|
||||
if (!b) {
|
||||
Genode::warning("Invalid block. Not freeing.");
|
||||
return;
|
||||
}
|
||||
Sb *sb = static_cast<Sb*>(b->_superblock);
|
||||
sb->free(ptr);
|
||||
if (!sb) {
|
||||
Genode::warning("Corrupt or invalid memory block.");
|
||||
return;
|
||||
}
|
||||
sb->free(p);
|
||||
}
|
||||
|
||||
void reserve_superblocks(size_t count, unsigned domain_id, size_t sz_class)
|
||||
|
||||
@@ -43,6 +43,9 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
|
||||
Heap &_location_to_heap(Affinity::Location loc) const
|
||||
{
|
||||
size_t pos = loc.xpos() * loc.height() + loc.ypos();
|
||||
if (!_core_heaps[pos]) {
|
||||
Genode::error("No heap for location ", loc);
|
||||
}
|
||||
return *_core_heaps[pos];
|
||||
}
|
||||
|
||||
@@ -51,12 +54,16 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
|
||||
return Thread::myself()->affinity();
|
||||
}
|
||||
|
||||
Hamstraaja &operator=(Hamstraaja ©);
|
||||
Hamstraaja(Hamstraaja const ©);
|
||||
|
||||
public:
|
||||
Hamstraaja(Genode::Pd_session &pd, Genode::Region_map &rm) : _pd(pd), _rm(rm)
|
||||
{
|
||||
size_t num_cpus = Cip::cip()->habitat_affinity.total();
|
||||
for (size_t cpu = 0; cpu < num_cpus; cpu++) {
|
||||
_core_heaps[cpu] = new (_backend) Core_heap<MIN, MAX>(_pd, _rm);
|
||||
Genode::log("Size of CoreHeap for size ", MAX * 2, " with ", MIN, " blocks is: ", sizeof(Core_heap<MIN, MAX>));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +99,7 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
|
||||
void *alloc(size_t size, unsigned domain_id)
|
||||
{
|
||||
_quota_used += overhead(size) + size;
|
||||
return _location_to_heap(_my_location()).alloc(size, domain_id);
|
||||
return _location_to_heap(_my_location()).aligned_alloc(size, 0, domain_id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,6 +111,7 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
|
||||
void *alloc(size_t size)
|
||||
{
|
||||
_quota_used += overhead(size) + size;
|
||||
//Genode::log("Allocating ", size, " bytes.");
|
||||
return _location_to_heap(_my_location()).alloc(size);
|
||||
}
|
||||
|
||||
@@ -116,6 +124,10 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
|
||||
*/
|
||||
void free(void *ptr, size_t alignment, size_t size)
|
||||
{
|
||||
if (!ptr) {
|
||||
Genode::warning("Tried to free nullptr");
|
||||
return;
|
||||
}
|
||||
_quota_used -= overhead(size) + size;
|
||||
return _location_to_heap(_my_location()).free(ptr, alignment);
|
||||
}
|
||||
@@ -154,7 +166,7 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
|
||||
}
|
||||
}
|
||||
|
||||
void free(void *ptr, size_t size) override { free(ptr, 0, size); }
|
||||
void free(void *ptr, size_t size=0) override { free(ptr, 0, size); }
|
||||
size_t consumed() const override { return _quota_used; }
|
||||
size_t overhead(size_t size) const override
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <ealanos/util/bit_alloc.h>
|
||||
#include <base/stdint.h>
|
||||
#include <base/ram_allocator.h>
|
||||
|
||||
namespace Ealan::Memory {
|
||||
class Block;
|
||||
@@ -44,37 +45,29 @@ class Ealan::Memory::Hyperblock
|
||||
* @brief A block of memory
|
||||
*
|
||||
*/
|
||||
class Ealan::Memory::Block
|
||||
struct Ealan::Memory::Block
|
||||
{
|
||||
public:
|
||||
void *_superblock{nullptr}; /* Pointer to the superblock, this block was allocated from. */
|
||||
Genode::size_t _alignment{0};
|
||||
void *_block_start; /* Placeholder for marking the start of the usable area of this block. */
|
||||
void *_superblock{nullptr}; /* Pointer to the superblock, this block was allocated from. */
|
||||
char _padding[56];
|
||||
|
||||
/**
|
||||
* @brief Construct a new Block object
|
||||
*
|
||||
* @param sb - Pointer to the superblock this block was allocated from
|
||||
*/
|
||||
Block(void *sb, Genode::size_t align) : _superblock(sb), _alignment(align), _block_start{nullptr} {}
|
||||
/**
|
||||
* @brief Return a pointer to the metadata of this block
|
||||
*
|
||||
* @param ptr - application-facing pointer for which to request the metadata
|
||||
* @return Block* - pointer to the Block datastructure containing the metadata
|
||||
*/
|
||||
static Block *metadata(void *ptr) {
|
||||
return reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(ptr) - sizeof(Block));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new block at the address pointed to by p
|
||||
*
|
||||
* @param p - the address at which the block shall be created
|
||||
* @return void* - pointer to the new block
|
||||
*/
|
||||
void *operator new(Genode::size_t, void *p) { return p; }
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the metadata of this block
|
||||
*
|
||||
* @param ptr - application-facing pointer for which to request the metadata
|
||||
* @return Block* - pointer to the Block datastructure containing the metadata
|
||||
*/
|
||||
static Block *metadata(void *ptr) {
|
||||
return reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(ptr) - sizeof(Genode::size_t) - sizeof(void *));
|
||||
}
|
||||
bool reserve(void *sb) {
|
||||
void *expect{nullptr};
|
||||
return __atomic_compare_exchange_n(&_superblock, &expect, sb, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
|
||||
}
|
||||
|
||||
void free() {
|
||||
__atomic_store_n(&_superblock, nullptr, __ATOMIC_RELEASE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -91,13 +84,22 @@ template <int SIZE, unsigned BASE>
|
||||
class Ealan::Memory::Superblock : public Hyperblock
|
||||
{
|
||||
private:
|
||||
Genode::size_t _size_class{0}; /* actual size of the blocks in this superblock */
|
||||
Bit_alloc<0, SIZE/BASE> _alloc; /* Bit allocator to allocate blocks from this superblock */
|
||||
Block _block_start[]; /* Marker for the end of the metadata portion */
|
||||
Genode::size_t _size_class;
|
||||
alignas(64) Genode::addr_t _start{0}; /* Start address of the blocks */
|
||||
|
||||
public:
|
||||
Superblock(Genode::size_t sz) : _size_class(sz), _alloc(SIZE / _size_class)
|
||||
Superblock(Genode::size_t sz) : _size_class(sz)
|
||||
{
|
||||
if (_size_class > SIZE) {
|
||||
Genode::error("Size class ", _size_class, " is bigger than superblock size ", SIZE);
|
||||
}
|
||||
/*Genode::log("Superblock SIZE=", SIZE, " BASE=", BASE, " this at ", this);
|
||||
Genode::log("Block metadata size is ", sizeof(Block));
|
||||
Genode::log("Size class of superblock is ", _size_class);
|
||||
Block *end = reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(this) + SIZE);
|
||||
Genode::log("Superblock ends at ", end);
|
||||
Genode::log("Capacity is ", capacity());
|
||||
Genode::log("-------------------");*/
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,14 +108,19 @@ class Ealan::Memory::Superblock : public Hyperblock
|
||||
* @return void* - pointer to the allocated block
|
||||
*/
|
||||
void *alloc() {
|
||||
long idx = static_cast<long>(_alloc.alloc());
|
||||
|
||||
if (!idx)
|
||||
return nullptr;
|
||||
|
||||
Genode::addr_t block_addr = reinterpret_cast<Genode::addr_t>(_block_start) + idx * _size_class;
|
||||
Block *block = new (reinterpret_cast<void *>(block_addr)) Block(this, 0);
|
||||
return &block->_block_start;
|
||||
Block *block = reinterpret_cast<Block *>(&_start);
|
||||
Block *end = reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(this) + SIZE - 64);
|
||||
while (block < end) {
|
||||
if (block->_superblock == nullptr) {
|
||||
if (block->reserve(this))
|
||||
{
|
||||
return reinterpret_cast<void*>(reinterpret_cast<Genode::addr_t>(block)+64);
|
||||
}
|
||||
}
|
||||
Genode::addr_t next = reinterpret_cast<Genode::addr_t>(block) + sizeof(Block) + _size_class;
|
||||
block = reinterpret_cast<Block *>(next);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,13 +129,17 @@ class Ealan::Memory::Superblock : public Hyperblock
|
||||
* @param alignment - adress alignment to use (must be at least 8)
|
||||
* @return void* - pointer to this block aligned to alignment bytes boundary
|
||||
*/
|
||||
void *aligned_alloc(Genode::size_t alignment = 64) {
|
||||
void *aligned_alloc(Genode::size_t alignment = 0) {
|
||||
void *ptr = alloc();
|
||||
Genode::addr_t base_ptr = reinterpret_cast<Genode::addr_t>(ptr) - sizeof(Genode::size_t) - sizeof(void *);
|
||||
reinterpret_cast<Block *>(base_ptr)->_alignment = alignment;
|
||||
if (!ptr)
|
||||
return nullptr;
|
||||
return reinterpret_cast<void *>(reinterpret_cast<Genode::addr_t>(ptr) + alignment);
|
||||
}
|
||||
|
||||
Genode::size_t capacity() {
|
||||
return (reinterpret_cast<Genode::addr_t>(this) + SIZE - reinterpret_cast<Genode::addr_t>(&_start)) / (sizeof(Block) + _size_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Free the block pointed to by ptr.
|
||||
*
|
||||
@@ -141,23 +152,23 @@ class Ealan::Memory::Superblock : public Hyperblock
|
||||
* @param ptr - Pointer to memory block to free
|
||||
*/
|
||||
void free(void *ptr) {
|
||||
Genode::size_t idx = (reinterpret_cast<Genode::size_t>(ptr) - reinterpret_cast<Genode::size_t>(_block_start)) / _size_class;
|
||||
_alloc.release(idx);
|
||||
}
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
/**
|
||||
* @brief Return number of blocks that can be allocated from this superblock
|
||||
*
|
||||
* @return Genode::size_t - Number of available blocks
|
||||
*/
|
||||
Genode::size_t free_blocks() { return _alloc.left(); }
|
||||
Block *b = reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(ptr) - 64);
|
||||
Block *end = reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(this) + SIZE);
|
||||
if (b > --end)
|
||||
return;
|
||||
|
||||
b->free();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the address of the first memory block in this superblock
|
||||
*
|
||||
* @return Block* - address of the first block
|
||||
*/
|
||||
Block *start() { return _block_start; }
|
||||
Block *start() { return reinterpret_cast<Block*>(&_start); }
|
||||
|
||||
/**
|
||||
* @brief Placement new used to create a superblock at address pointed to by p.
|
||||
|
||||
Reference in New Issue
Block a user