ealanos: Made hamstraaja more efficient.

This commit is contained in:
Michael Mueller
2025-06-03 15:24:28 +02:00
parent 6c7283b711
commit 2c2c7a2120
4 changed files with 131 additions and 50 deletions

View File

@@ -12,7 +12,7 @@
#define __INCLUDE__EALANOS__MEMORY__COREHEAP_H_
#include <ealanos/memory/superblock.h>
#include <ealanos/util/mpsc_queue.h>
#include <ealanos/util/lifo_queue.h>
#include <tukija/syscall-generic.h>
#include <base/attached_ram_dataspace.h>
#include <pd_session/pd_session.h>
@@ -37,7 +37,7 @@ class Ealan::Memory::Core_heap
static constexpr const Genode::size_t num_size_classes = MAX / MIN;
static constexpr const unsigned num_numa_domains = 64;
static constexpr const unsigned long magic_num = 0xdeadbeefUL;
Ealan::util::MPSCQueue<Sb> _superblocks[num_size_classes][num_numa_domains];
alignas(64) Ealan::util::Lifo_queue<Sb> _superblocks[num_size_classes][num_numa_domains];
Pd_session &_pd;
Region_map &_rm;
Tip *_tip{const_cast<Tip *>(Tip::tip())};
@@ -91,7 +91,8 @@ class Ealan::Memory::Core_heap
Sb *_allocate_superblock(unsigned domain_id, Genode::size_t sz_class)
{
Hyperblock *hb = _allocate_hyperblock(domain_id, MAX * 2);
Hyperblock *hb = _allocate_hyperblock(domain_id, MAX * 2);
Genode::log("Need new superblock for sizeclass ", sz_class, " in domain ", domain_id);
if (!hb) {
Genode::warning("Failed to allocate superblock for size class ", sz_class, " in domain ", domain_id);
return nullptr;
@@ -111,7 +112,7 @@ class Ealan::Memory::Core_heap
for (size_t sz_class = 0; sz_class < num_size_classes; sz_class++) {
for (unsigned domain_id = 0; domain_id < num_numa_domains; domain_id++) {
Sb *sb;
while ((sb = _superblocks[sz_class][domain_id].pop_front()) != nullptr)
while ((sb = _superblocks[sz_class][domain_id].dequeue()) != nullptr)
{
Ram_dataspace_capability cap = sb->cap;
_rm.detach(reinterpret_cast<addr_t>(sb));
@@ -141,11 +142,14 @@ class Ealan::Memory::Core_heap
Genode::size_t sz_class = _calculate_size_class(size+alignment);
Sb *sb = _superblocks[sz_class / MIN - 1][domain_id].head();
if (!sb) {
//if (size == 128)
// Genode::log("Allocating task object from superblock ", sb, " sz_class=", sz_class, " node_id = ", domain_id);
if (!sb) {
sb = _allocate_superblock(domain_id, sz_class);
if (!sb)
return nullptr;
_superblocks[sz_class / MIN - 1][domain_id].push_back(sb);
_superblocks[sz_class / MIN - 1][domain_id].enqueue(sb);
}
for (; sb != nullptr ; sb = static_cast<Sb*>(sb->next())) {
@@ -158,7 +162,7 @@ class Ealan::Memory::Core_heap
sb = _allocate_superblock(domain_id, sz_class);
if (!sb)
return nullptr;
_superblocks[sz_class / MIN - 1][domain_id].push_back(sb);
_superblocks[sz_class / MIN - 1][domain_id].enqueue(sb);
return sb->aligned_alloc(alignment);
}
@@ -209,7 +213,7 @@ class Ealan::Memory::Core_heap
}
Sb *sb = static_cast<Sb*>(b->_superblock);
if (!sb) {
Genode::warning("Corrupt or invalid memory block.");
Genode::warning("Corrupt or invalid memory block: ", p);
return;
}
sb->free(p);
@@ -219,7 +223,7 @@ class Ealan::Memory::Core_heap
{
for (size_t i = 0; i < count; i++) {
Sb *sb = _allocate_superblock(domain_id, sz_class);
_superblocks[sz_class / MIN - 1][domain_id].push_back(sb);
_superblocks[sz_class / MIN - 1][domain_id].enqueue(sb);
}
}
};

View File

@@ -11,6 +11,7 @@
#ifndef __INCLUDE__EALANOS__MEMORY__HAMSTRAAJA_H_
#define __INCLUDE__EALANOS__MEMORY__HAMSTRAAJA_H_
#include "base/log.h"
#include <ealanos/memory/coreheap.h>
#include <tukija/syscall-generic.h>
#include <base/affinity.h>
@@ -41,7 +42,7 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
size_t _quota_used{0};
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);
@@ -61,10 +62,11 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
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++) {
for (size_t cpu = 0; cpu < num_cpus; cpu++) {
_core_heaps[cpu] = new (_backend) Core_heap<MIN, MAX>(_pd, _rm);
}
Genode::log("Hamstraaja initialized");
Genode::log("Size of CoreHeap is ", sizeof(Heap));
}
~Hamstraaja()
@@ -87,9 +89,14 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
{
_quota_used += overhead(size) + size;
return _location_to_heap(_my_location()).aligned_alloc(size, domain_id, alignment);
}
}
/**
void *aligned_alloc(size_t size, size_t alignment)
{
return _location_to_heap(_my_location()).aligned_alloc(size, alignment);
}
/**
* @brief Allocate a chunk of memory from a NUMA domain without alignment
*
* @param size - amount of memory to allocate
@@ -99,6 +106,8 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
void *alloc(size_t size, unsigned domain_id)
{
_quota_used += overhead(size) + size;
//if (size == 128)
// Genode::log("Allocate task on core ", _my_location(), " for Node ", domain_id);
return _location_to_heap(_my_location()).aligned_alloc(size, domain_id, 0);
}
@@ -111,8 +120,13 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
void *alloc(size_t size)
{
_quota_used += overhead(size) + size;
return _location_to_heap(_my_location()).alloc(size);
}
void *ptr = _location_to_heap(_my_location()).aligned_alloc(size, 0);
if (ptr >= reinterpret_cast<void *>(0x7FFF80000000UL)) {
Genode::error("Hamstraaja returned non-canonical address");
return nullptr;
}
return ptr;
}
/**
* @brief Free a chunk of memory
@@ -147,6 +161,12 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
{
_location_to_heap(loc).reserve_superblocks(count, domain_id, sz_class);
}
Genode::size_t size_class(Genode::size_t size) const
{
return (size / MIN + 1) * MIN;
}
/*************************
** Allocator interface **
@@ -154,13 +174,10 @@ class Ealan::Memory::Hamstraaja : public Genode::Allocator
Alloc_result try_alloc(size_t size) override
{
void *ptr = nullptr;
if ((ptr = alloc(size)) != nullptr)
{
void *ptr = nullptr;
if ((ptr = alloc(size)) != nullptr) {
return Alloc_result(ptr);
}
else
{
} else {
return Alloc_result(Alloc_error::OUT_OF_RAM);
}
}

View File

@@ -12,7 +12,7 @@
#ifndef __INCLUDE__EALANOS__MEMORY__SUPERBLOCK_H_
#define __INCLUDE__EALANOS__MEMORY__SUPERBLOCK_H_
#include <ealanos/util/bit_alloc.h>
#include <ealanos/util/lifo_queue.h>
#include <base/stdint.h>
#include <base/ram_allocator.h>
@@ -45,10 +45,11 @@ class Ealan::Memory::Hyperblock
* @brief A block of memory
*
*/
struct Ealan::Memory::Block
{
void *_superblock{nullptr}; /* Pointer to the superblock, this block was allocated from. */
char _padding[56];
struct Ealan::Memory::Block {
Block *_next{nullptr};
void *_superblock{nullptr};/* Pointer to the superblock, this block was allocated from. */
char _padding[48];
/**
* @brief Return a pointer to the metadata of this block
@@ -65,9 +66,10 @@ struct Ealan::Memory::Block
return __atomic_compare_exchange_n(&_superblock, &expect, sb, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
}
void free() {
__atomic_store_n(&_superblock, nullptr, __ATOMIC_RELEASE);
}
void free() { __atomic_store_n(&_superblock, nullptr, __ATOMIC_RELEASE); }
void next(Block *ptr) { _next = ptr; }
Block* next() { return _next; }
};
/**
@@ -84,42 +86,62 @@ template <int SIZE, unsigned BASE>
class Ealan::Memory::Superblock : public Hyperblock
{
private:
Genode::size_t _size_class;
alignas(64) Genode::addr_t _start{0}; /* Start address of the blocks */
Genode::size_t _size_class;
alignas(64) Ealan::util::Lifo_queue<Block> _blocks{};
alignas(64) Genode::addr_t _start{0}; /* Start address of the blocks */
public:
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("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("Superblock ends at ", reinterpret_cast<void*>(_end));
Genode::log("Capacity is ", capacity());
Genode::log("-------------------");
}
Genode::log("-------------------");*/
Genode::addr_t end = reinterpret_cast<Genode::addr_t>(this) + SIZE - sizeof(Block) - _size_class;
for (Genode::addr_t block = reinterpret_cast<Genode::addr_t>(&_start); block < end; block += sizeof(Block) + _size_class) {
Block *b = reinterpret_cast<Block *>(block);
b->_superblock = this;
_blocks.enqueue(b);
}
}
/**
* @brief Allocate a block of SIZE-8 bytes from this superblock
*
* @return void* - pointer to the allocated block
*/
void *alloc() {
Block *block = reinterpret_cast<Block *>(&_start);
void *alloc()
{
Block *block = _blocks.dequeue();
if (block)
return reinterpret_cast<Block*>(reinterpret_cast<Genode::addr_t>(block)+64);
/*if (block != nullptr) {
if (block->reserve(this)) {
__atomic_compare_exchange_n(&last_freed_block, &block, nullptr, false,
__ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
return reinterpret_cast<void*>(reinterpret_cast<Genode::addr_t>(block)+64);
}
}
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);
}
if (block->_superblock == nullptr) {
if (block->reserve(this)) {
return reinterpret_cast<void *>(reinterpret_cast<Genode::addr_t>(block) +
64);
}
}
block = reinterpret_cast<Block *>(next);
}*/
return nullptr;
}
@@ -159,9 +181,8 @@ class Ealan::Memory::Superblock : public Hyperblock
Block *end = reinterpret_cast<Block *>(reinterpret_cast<Genode::addr_t>(this) + SIZE);
if (b > --end)
return;
b->free();
}
_blocks.enqueue(b);
}
/**
* @brief Return the address of the first memory block in this superblock

View File

@@ -0,0 +1,39 @@
#ifndef __INCLUDE__EALANOS__UTIL_LIFO_QUEUE_H_
#define __INCLUDE__EALANOS__UTIL_LIFO_QUEUE_H_
namespace Ealan::util
{
template <class T>
class Lifo_queue;
}
template <class T>
class Ealan::util::Lifo_queue
{
private:
alignas(64) T *_head{nullptr};
public:
void enqueue(T *elem)
{
T *next = __atomic_exchange_n(&_head, elem, __ATOMIC_RELAXED);
elem->next(next);
}
T *dequeue()
{
if (_head) {
T *elem = __atomic_exchange_n(&_head, _head->next(), __ATOMIC_RELAXED);
return elem;
}
return nullptr;
}
T *head()
{
return _head;
}
};
#endif