Tweak slab allocators to use whole pages

Most slab allocators in core use a sliced heap as backing store. Since
sliced-heap allocations are performed at page-granularity, it is
sensible to dimension the slab blocks to fill whole pages.
This commit is contained in:
Norman Feske 2016-04-28 17:29:37 +02:00 committed by Christian Helmuth
parent ba0545de07
commit b8cd56cb90
6 changed files with 69 additions and 33 deletions

View File

@ -24,7 +24,14 @@ namespace Genode {
class Allocator_avl_base;
template <typename, unsigned SLAB_BLOCK_SIZE = 256*sizeof(addr_t)>
/*
* The default slab block size is dimensioned such that slab-block
* allocations make effective use of entire memory pages. To account for
* the common pattern of using a 'Sliced_heap' as backing store for the
* 'Allocator_avl'. We remove 8 words from the slab-block size to take the
* meta-data overhead of each sliced-heap block into account.
*/
template <typename, unsigned SLAB_BLOCK_SIZE = (1024 - 8)*sizeof(addr_t)>
class Allocator_avl_tpl;
/**
@ -338,6 +345,11 @@ class Genode::Allocator_avl_tpl : public Allocator_avl_base
~Allocator_avl_tpl() { _revert_allocations_and_ranges(); }
/**
* Return size of slab blocks used for meta data
*/
static constexpr size_t slab_block_size() { return SLAB_BLOCK_SIZE; }
/**
* Assign custom meta data to block at specified address
*/

View File

@ -38,23 +38,6 @@ class Genode::Heap : public Allocator
{
private:
enum {
MIN_CHUNK_SIZE = 4*1024, /* in machine words */
MAX_CHUNK_SIZE = 256*1024,
/*
* Meta data includes the Dataspace structure and meta data of
* the AVL allocator.
*/
META_DATA_SIZE = 1024, /* in bytes */
/*
* Allocation sizes >= this value are considered as big
* allocations, which get their own dataspace. In contrast
* to smaller allocations, this memory is released to
* the RAM session when 'free()' is called.
*/
BIG_ALLOCATION_THRESHOLD = 64*1024 /* in bytes */
};
class Dataspace : public List<Dataspace>::Element
{
public:
@ -127,16 +110,7 @@ class Genode::Heap : public Allocator
Region_map *region_map,
size_t quota_limit = UNLIMITED,
void *static_addr = 0,
size_t static_size = 0)
:
_alloc(nullptr),
_ds_pool(ram_session, region_map),
_quota_limit(quota_limit), _quota_used(0),
_chunk_size(MIN_CHUNK_SIZE)
{
if (static_addr)
_alloc->add_range((addr_t)static_addr, static_size);
}
size_t static_size = 0);
~Heap();

View File

@ -20,6 +20,22 @@
using namespace Genode;
namespace {
enum {
MIN_CHUNK_SIZE = 4*1024, /* in machine words */
MAX_CHUNK_SIZE = 256*1024,
/*
* Allocation sizes >= this value are considered as big
* allocations, which get their own dataspace. In contrast
* to smaller allocations, this memory is released to
* the RAM session when 'free()' is called.
*/
BIG_ALLOCATION_THRESHOLD = 64*1024 /* in bytes */
};
}
Heap::Dataspace_pool::~Dataspace_pool()
{
/* free all ram_dataspaces */
@ -154,10 +170,10 @@ bool Heap::_unsynchronized_alloc(size_t size, void **out_addr)
/*
* Calculate block size of needed backing store. The block must hold the
* requested 'size' and we add some space for meta data
* ('Dataspace' structures, AVL nodes).
* ('Dataspace' structures, AVL-node slab blocks).
* Finally, we align the size to a 4K page.
*/
dataspace_size = size + META_DATA_SIZE;
dataspace_size = size + Allocator_avl::slab_block_size() + sizeof(Heap::Dataspace);
/*
* '_chunk_size' is a multiple of 4K, so 'dataspace_size' becomes
@ -234,6 +250,22 @@ void Heap::free(void *addr, size_t size)
}
Heap::Heap(Ram_session *ram_session,
Region_map *region_map,
size_t quota_limit,
void *static_addr,
size_t static_size)
:
_alloc(nullptr),
_ds_pool(ram_session, region_map),
_quota_limit(quota_limit), _quota_used(0),
_chunk_size(MIN_CHUNK_SIZE)
{
if (static_addr)
_alloc->add_range((addr_t)static_addr, static_size);
}
Heap::~Heap()
{
/*

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <base/tslab.h>
#include <base/heap.h>
/* base-internal includes */
#include <base/internal/page_size.h>
@ -26,8 +27,12 @@ namespace Genode
/**
* Allocator to manage CPU threads associated with a CPU session
*
* We take the knowledge about the used backing-store allocator (sliced
* heap) into account to make sure that slab blocks fill whole pages.
*/
typedef Tslab<Cpu_thread_component, get_page_size()> Cpu_thread_allocator;
typedef Tslab<Cpu_thread_component, get_page_size() - Sliced_heap::meta_data_size()>
Cpu_thread_allocator;
}
#endif /* _CORE__INCLUDE__CPU_THREAD_ALLOCATOR_H_ */

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <util/list.h>
#include <base/heap.h>
#include <base/tslab.h>
#include <base/rpc_server.h>
#include <base/allocator_guard.h>
@ -38,7 +39,11 @@ namespace Genode {
class Invalid_dataspace : public Exception { };
static constexpr size_t SBS = get_page_size();
/*
* Dimension 'Ds_slab' such that slab blocks (including the
* meta-data overhead of the sliced-heap blocks) are page sized.
*/
static constexpr size_t SBS = get_page_size() - Sliced_heap::meta_data_size();
using Ds_slab = Synced_allocator<Tslab<Dataspace_component, SBS> >;

View File

@ -24,6 +24,7 @@
#include <base/synced_allocator.h>
#include <base/signal.h>
#include <base/rpc_server.h>
#include <base/heap.h>
#include <util/list.h>
#include <util/fifo.h>
@ -273,7 +274,14 @@ class Genode::Region_map_component : public Rpc_object<Region_map>,
void sub_rm(Native_capability cap) { _rm_cap = cap; }
};
Tslab<Rm_region_ref, 1024> _ref_slab; /* backing store for
/*
* Dimension slab allocator for regions such that backing store is
* allocated at the granularity of pages.
*/
typedef Tslab<Rm_region_ref, get_page_size() - Sliced_heap::meta_data_size()>
Ref_slab;
Ref_slab _ref_slab; /* backing store for
region list */
Allocator_avl_tpl<Rm_region> _map; /* region map for attach,
detach, pagefaults */