mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
libc: Change malloc's allocator
Use slab allocators for small object sizes, do it the usual way otherwise. This patch is related to #363. Using this optimization may be a viable alternative to switching to the FreeBSD's malloc implementation.
This commit is contained in:
parent
7ca7b4417d
commit
825dc783e6
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Simplistic malloc and free implementation
|
* \brief Simplistic malloc and free implementation
|
||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
|
* \author Sebastian Sumpf
|
||||||
* \date 2006-07-21
|
* \date 2006-07-21
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -14,6 +15,7 @@
|
|||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
|
#include <base/slab.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/misc_math.h>
|
#include <util/misc_math.h>
|
||||||
|
|
||||||
@ -22,25 +24,146 @@
|
|||||||
|
|
||||||
typedef unsigned long Block_header;
|
typedef unsigned long Block_header;
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
class Slab_alloc : public Slab
|
||||||
|
{
|
||||||
|
size_t _calculate_block_size(size_t object_size)
|
||||||
|
{
|
||||||
|
size_t block_size = 8 * (object_size + sizeof(Slab_entry)) + sizeof(Slab_block);
|
||||||
|
return align_addr(block_size, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Slab_alloc(size_t object_size, Allocator *backing_store)
|
||||||
|
: Slab(object_size, _calculate_block_size(object_size), 0, backing_store)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
inline void *alloc()
|
||||||
|
{
|
||||||
|
void *result;
|
||||||
|
return (Slab::alloc(slab_size(), &result) ? result : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocator that uses slabs for small objects sizes
|
||||||
|
*/
|
||||||
|
class Malloc : public Genode::Allocator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
SLAB_START = 2, /* 4 Byte (log2) */
|
||||||
|
SLAB_STOP = 11, /* 2048 Byte (log2) */
|
||||||
|
NUM_SLABS = (SLAB_STOP - SLAB_START) + 1
|
||||||
|
};
|
||||||
|
|
||||||
|
Genode::Allocator *_backing_store; /* back-end allocator */
|
||||||
|
Genode::Slab_alloc *_allocator[NUM_SLABS]; /* slab allocators */
|
||||||
|
Genode::Lock _lock;
|
||||||
|
|
||||||
|
unsigned long _slab_log2(unsigned long size)
|
||||||
|
{
|
||||||
|
unsigned msb = Genode::log2(size);
|
||||||
|
/* size is greater than msb */
|
||||||
|
if (size > (1U << msb))
|
||||||
|
msb++;
|
||||||
|
|
||||||
|
/* use smallest slab */
|
||||||
|
if (size < (1U << SLAB_START))
|
||||||
|
msb = SLAB_START;
|
||||||
|
|
||||||
|
return msb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Malloc(Genode::Allocator *backing_store) : _backing_store(backing_store)
|
||||||
|
{
|
||||||
|
for (unsigned i = SLAB_START; i <= SLAB_STOP; i++) {
|
||||||
|
_allocator[i - SLAB_START] = new (backing_store)
|
||||||
|
Genode::Slab_alloc(1U << i, backing_store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocator interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool alloc(size_t size, void **out_addr)
|
||||||
|
{
|
||||||
|
Genode::Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
|
/* enforce size to be a multiple of 4 bytes */
|
||||||
|
size = (size + 3) & ~3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We store the size of the allocation at the very
|
||||||
|
* beginning of the allocated block and return
|
||||||
|
* the subsequent address. This way, we can retrieve
|
||||||
|
* the size information when freeing the block.
|
||||||
|
*/
|
||||||
|
unsigned long real_size = size + sizeof(Block_header);
|
||||||
|
unsigned long msb = _slab_log2(real_size);
|
||||||
|
void *addr = 0;
|
||||||
|
|
||||||
|
/* use backing store if requested memory is larger than largest slab */
|
||||||
|
if (msb > SLAB_STOP) {
|
||||||
|
|
||||||
|
if (!(_backing_store->alloc(real_size, &addr)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!(addr = _allocator[msb - SLAB_START]->alloc()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*(Block_header *)addr = real_size;
|
||||||
|
*out_addr = (Block_header *)addr + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *ptr, size_t /* size */)
|
||||||
|
{
|
||||||
|
Genode::Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
|
unsigned long *addr = ((unsigned long *)ptr) - 1;
|
||||||
|
unsigned long real_size = *addr;
|
||||||
|
|
||||||
|
if (real_size > (1U << SLAB_STOP))
|
||||||
|
_backing_store->free(addr, real_size);
|
||||||
|
else {
|
||||||
|
unsigned long msb = _slab_log2(real_size);
|
||||||
|
_allocator[msb - SLAB_START]->free(addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t overhead(size_t size)
|
||||||
|
{
|
||||||
|
size += sizeof(Block_header);
|
||||||
|
|
||||||
|
if (size > (1U << SLAB_STOP))
|
||||||
|
return _backing_store->overhead(size);
|
||||||
|
|
||||||
|
return _allocator[_slab_log2(size) - SLAB_START]->overhead(size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Genode::Allocator *allocator()
|
||||||
|
{
|
||||||
|
static Malloc _m(Genode::env()->heap());
|
||||||
|
return &_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" void *malloc(unsigned size)
|
extern "C" void *malloc(unsigned size)
|
||||||
{
|
{
|
||||||
/* enforce size to be a multiple of 4 bytes */
|
void *addr;
|
||||||
size = (size + 3) & ~3;
|
return allocator()->alloc(size, &addr) ? addr : 0;
|
||||||
|
|
||||||
/*
|
|
||||||
* We store the size of the allocation at the very
|
|
||||||
* beginning of the allocated block and return
|
|
||||||
* the subsequent address. This way, we can retrieve
|
|
||||||
* the size information when freeing the block.
|
|
||||||
*/
|
|
||||||
unsigned long real_size = size + sizeof(Block_header);
|
|
||||||
void *addr = 0;
|
|
||||||
if (!Genode::env()->heap()->alloc(real_size, &addr))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*(Block_header *)addr = real_size;
|
|
||||||
return (Block_header *)addr + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -56,8 +179,7 @@ extern "C" void free(void *ptr)
|
|||||||
{
|
{
|
||||||
if (!ptr) return;
|
if (!ptr) return;
|
||||||
|
|
||||||
unsigned long *addr = ((unsigned long *)ptr) - 1;
|
allocator()->free(ptr, 0);
|
||||||
Genode::env()->heap()->free(addr, *addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user