WIP: pooled allocator, initial version

* creating and allocating, freeing elements
 * live objects will be destructed when a mpool gets destroyed and a
   destructor was set up
This commit is contained in:
Christian Thaeter 2009-05-11 17:08:34 +02:00
parent 062dbfe82f
commit 2a9d59ccd0
7 changed files with 905 additions and 0 deletions

View file

@ -89,6 +89,7 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_dbg, debugging);
NOBUG_CPP_DEFINE_FLAG_PARENT ( gui_dbg, debugging);
/** base if debug logging for the support library */
NOBUG_CPP_DEFINE_FLAG_PARENT ( library_dbg, debugging);
NOBUG_CPP_DEFINE_FLAG_PARENT ( mpool_dbg, library_dbg);
NOBUG_CPP_DEFINE_FLAG_PARENT ( psplay_dbg, library_dbg);
NOBUG_CPP_DEFINE_FLAG_PARENT ( resourcecollector_dbg, library_dbg);
NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_dbg, library_dbg);

View file

@ -23,6 +23,7 @@ liblumiera_la_CXXFLAGS = $(AM_CXXFLAGS) -Wall -Wextra
liblumiera_la_SOURCES = \
$(liblumiera_la_srcdir)/error.c \
$(liblumiera_la_srcdir)/mpool.c \
$(liblumiera_la_srcdir)/exception.cpp \
$(liblumiera_la_srcdir)/mutex.c \
$(liblumiera_la_srcdir)/recmutex.c \
@ -51,6 +52,7 @@ liblumiera_la_SOURCES = \
noinst_HEADERS += \
$(liblumiera_la_srcdir)/error.h \
$(liblumiera_la_srcdir)/error.hpp \
$(liblumiera_la_srcdir)/mpool.h \
$(liblumiera_la_srcdir)/mutex.h \
$(liblumiera_la_srcdir)/recmutex.h \
$(liblumiera_la_srcdir)/rwlock.h \

487
src/lib/mpool.c Normal file
View file

@ -0,0 +1,487 @@
/*
mpool.h - memory pool for constant sized objects
Copyright (C) Lumiera.org
2009, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <limits.h>
#include "mpool.h"
/*
Cluster and node structures are private
*/
typedef struct mpoolcluster_struct mpoolcluster;
typedef mpoolcluster* MPoolcluster;
typedef const mpoolcluster* const_MPoolcluster;
struct mpoolcluster_struct
{
llist node; /* all clusters */
void* data[]; /* bitmap and elements */
};
typedef struct mpoolnode_struct mpoolnode;
typedef mpoolnode* MPoolnode;
typedef const mpoolnode* const_MPoolnode;
struct mpoolnode_struct
{
llist node;
};
MPool
mpool_init (MPool self, size_t elem_size, unsigned elements_per_cluster, mpool_destroy_fn dtor)
{
TRACE (mpool_dbg, "%p: elem_size %zd: elem_per_cluster %u", self, elem_size, elements_per_cluster);
if (self)
{
llist_init (&self->freelist);
llist_init (&self->clusters);
self->elem_size = (elem_size+sizeof(void*)-1) / sizeof(void*) * sizeof(void*); /* void* aligned */
/* minimum size is the size of a llist node */
if (self->elem_size < sizeof(llist))
self->elem_size = sizeof(llist);
self->elements_per_cluster = elements_per_cluster;
self->elements_free = 0;
self->destroy = dtor;
self->locality = NULL;
}
return self;
}
#define MPOOL_BITMAP_SIZE(elements_per_cluster) \
(((elements_per_cluster) + sizeof(uintptr_t)*CHAR_BIT - 1) \
/ (sizeof(uintptr_t) * CHAR_BIT) * sizeof (uintptr_t))
static inline void*
cluster_element_get (MPoolcluster cluster, MPool self, unsigned n)
{
return (void*)cluster + /* start address */
sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (self->elements_per_cluster) + /* bitmap */
self->elem_size * n; /* offset*/
}
static inline bool
bitmap_bit_get_nth (MPoolcluster cluster, unsigned index)
{
TRACE (mpool_dbg, "cluster %p: index %u", cluster, index);
ldiv_t div = ldiv(index, sizeof(uintptr_t)*CHAR_BIT);
uintptr_t* bitmap = (uintptr_t*)&cluster->data;
return bitmap[div.quot] & ((uintptr_t)1<<div.rem);
}
MPool
mpool_destroy (MPool self)
{
TRACE (mpool_dbg, "%p", self);
if (self)
{
LLIST_WHILE_TAIL(&self->clusters, cluster)
{
if (self->destroy)
for (unsigned i = 0; i < self->elements_per_cluster; ++i)
{
if (bitmap_bit_get_nth ((MPoolcluster)cluster, i))
{
void* obj = cluster_element_get ((MPoolcluster)cluster, self, i);
TRACE (mpool_dbg, "dtor: cluster %p: obj %p: freelist %p", cluster, obj, self->freelist);
self->destroy (obj);
}
}
llist_unlink_fast_ (cluster);
TRACE (mpool_dbg, "freeing cluster %p" , cluster);
free (cluster);
}
llist_init (&self->freelist);
self->elements_free = 0;
self->locality = NULL;
}
return self;
}
MPool
mpool_cluster_alloc_ (MPool self)
{
MPoolcluster cluster = malloc (sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (self->elements_per_cluster) + /* bitmap */
self->elem_size * self->elements_per_cluster); /* elements */
TRACE (mpool_dbg, "%p", cluster);
if (!cluster)
return NULL;
/* clear the bitmap */
memset (&cluster->data, 0, MPOOL_BITMAP_SIZE (self->elements_per_cluster));
/* initialize freelist */
for (unsigned i = 0; i < self->elements_per_cluster; ++i)
{
MPoolnode node = cluster_element_get (cluster, self, i);
TRACE (mpool_dbg, "node %p", node);
llist_insert_tail (&self->freelist, llist_init (&node->node));
}
/* we insert the cluster at head because its likely be used next */
llist_insert_head (&self->clusters, llist_init (&cluster->node));
self->elements_free += self->elements_per_cluster;
return self;
}
static int
cmp_cluster_contains_element (const_LList cluster, const_LList element, void* self)
{
if (element < cluster)
return -1;
if ((void*)element >
(void*)cluster +
sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster) + /* bitmap */
((MPool)self)->elem_size * ((MPool)self)->elements_per_cluster) /* elements */
return 1;
return 0;
}
static inline MPoolcluster
element_cluster_get (MPool self, void* element)
{
return (MPoolcluster) llist_ufind (&self->clusters, (const_LList) element, cmp_cluster_contains_element, self);
}
static inline unsigned
uintptr_nearestbit (uintptr_t v, unsigned n)
{
unsigned r = 0;
uintptr_t mask = 1ULL<<n;
while (1)
{
if (v&mask)
{
if (v&mask& ~(~0ULL<<n))
return n-r;
else
return n+r;
}
if (mask == ~0ULL)
return ~0U;
++r;
mask |= ((mask<<1)|(mask>>1));
}
}
static inline void*
alloc_near (MPoolcluster cluster, MPool self, void* locality)
{
void* begin_of_elements =
(void*)cluster +
sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
#if UINTPTR_MAX > 4294967295U /* 64 bit */
lldiv_t div = lldiv((locality - begin_of_elements) / self->elem_size, sizeof(uintptr_t)*CHAR_BIT);
#else /* 32 bit */
ldiv_t div = ldiv((locality - begin_of_elements) / self->elem_size, sizeof(uintptr_t)*CHAR_BIT);
#endif
uintptr_t* bitmap = (uintptr_t*)&cluster->data;
unsigned r = ~0U;
TRACE (mpool_dbg, "cluster %p: bitmap %p %p: elements %p: index %d", cluster, bitmap, bitmap[div.quot], begin_of_elements, div.quot);
/* the bitmap word at locality */
if (bitmap[div.quot] < UINTPTR_MAX)
{
r = uintptr_nearestbit (~bitmap[div.quot], div.rem);
}
/* the bitmap word before locality, this gives a slight bias towards the begin, keeping the pool compact */
else if (div.quot && bitmap[div.quot-1] < UINTPTR_MAX)
{
--div.quot;
r = uintptr_nearestbit (~bitmap[div.quot], sizeof(uintptr_t)*CHAR_BIT-1);
}
if (r != ~0U)
{
void* ret = begin_of_elements + ((uintptr_t)(div.quot*sizeof(uintptr_t)*CHAR_BIT+r)*self->elem_size);
return ret;
}
return NULL;
}
static inline void
bitmap_set_element (MPoolcluster cluster, MPool self, void* element)
{
void* begin_of_elements =
(void*)cluster +
sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
#if UINTPTR_MAX > 4294967295U /* 64 bit */
lldiv_t div = lldiv((element - begin_of_elements) / self->elem_size, sizeof(uintptr_t)*CHAR_BIT);
#else /* 32 bit */
ldiv_t div = ldiv((element - begin_of_elements) / self->elem_size, sizeof(uintptr_t)*CHAR_BIT);
#endif
uintptr_t* bitmap = (uintptr_t*)&cluster->data;
bitmap[div.quot] |= ((uintptr_t)1<<div.rem);
TRACE (mpool_dbg, "set bit %d, index %d, of %p is %p", div.rem, div.quot, element, bitmap[div.quot]);
}
static inline void
bitmap_clear_element (MPoolcluster cluster, MPool self, void* element)
{
void* begin_of_elements =
(void*)cluster +
sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
#if UINTPTR_MAX > 4294967295U /* 64 bit */
lldiv_t div = lldiv((element - begin_of_elements) / self->elem_size, sizeof(uintptr_t)*CHAR_BIT);
#else /* 32 bit */
ldiv_t div = ldiv((element - begin_of_elements) / self->elem_size, sizeof(uintptr_t)*CHAR_BIT);
#endif
uintptr_t* bitmap = (uintptr_t*)&cluster->data;
bitmap[div.quot] &= ~((uintptr_t)1<<div.rem);
TRACE (mpool_dbg, "clear bit %d, index %d, of %p is %p", div.rem, div.quot, element, bitmap[div.quot]);
}
void*
mpool_alloc (MPool self)
{
if (!self->elements_free)
{
if (mpool_cluster_alloc_ (self))
{
self->locality = NULL; /* supress alloc_near() */
}
else
{
ERROR (mpool_dbg, "allocation failure");
return NULL;
}
}
void* ret = NULL;
if (self->locality)
{
ret = alloc_near (element_cluster_get (self, self->locality), self, self->locality);
TRACE_IF (ret, mpool_dbg, "near allocation %p", ret);
}
if (!ret)
{
ret = llist_head (&self->freelist);
TRACE_IF (ret, mpool_dbg, "far allocation %p", ret);
}
if (ret)
{
llist_unlink_fast_ ((LList)ret);
bitmap_set_element (element_cluster_get (self, ret), self, ret);
}
TRACE (mpool_dbg, "%p", ret);
self->locality = ret;
--self->elements_free;
return ret;
}
/*
put a element back on the pool
*/
static inline MPoolnode
find_near (MPoolcluster cluster, MPool self, void* element)
{
void* begin_of_elements =
(void*)cluster +
sizeof (*cluster) + /* header */
MPOOL_BITMAP_SIZE (((MPool)self)->elements_per_cluster); /* bitmap */
uintptr_t index = (element - begin_of_elements) / self->elem_size;
#if UINTPTR_MAX > 4294967295U /* 64 bit */
lldiv_t div = lldiv (index, sizeof(uintptr_t)*CHAR_BIT);
#else /* 32 bit */
ldiv_t div = ldiv (index, sizeof(uintptr_t)*CHAR_BIT);
#endif
uintptr_t* bitmap = (uintptr_t*)&cluster->data;
unsigned r = ~0U;
TRACE (mpool_dbg, "cluster %p: bitmap %p %p: elements %p: index %d", cluster, bitmap, bitmap[div.quot], begin_of_elements, div.quot);
/* the bitmap word at locality */
if (bitmap[div.quot] < UINTPTR_MAX)
{
r = uintptr_nearestbit (~bitmap[div.quot], div.rem);
}
/* the bitmap word after element, we assume that elements after the searched element are more likely be free */
else if (index < self->elements_per_cluster && bitmap[div.quot+1] < UINTPTR_MAX)
{
++div.quot;
r = uintptr_nearestbit (~bitmap[div.quot], 0);
}
/* finally the bitmap word before element */
else if (index > 0 && bitmap[div.quot-1] < UINTPTR_MAX)
{
--div.quot;
r = uintptr_nearestbit (~bitmap[div.quot], sizeof(uintptr_t)*CHAR_BIT-1);
}
if (r != ~0U)
return begin_of_elements + ((uintptr_t)(div.quot*sizeof(uintptr_t)*CHAR_BIT+r)*self->elem_size);
return NULL;
}
void
mpool_free (MPool self, void* element)
{
if (self && element)
{
TRACE (mpool_dbg, "mpool %p: element %p", self, element);
MPoolcluster cluster = element_cluster_get (self,element);
bitmap_clear_element (cluster, self, element);
llist_init (&((MPoolnode)element)->node);
MPoolnode near = find_near (cluster, self, element);
TRACE (mpool_dbg, "near %p", near);
if (near)
{
if (near < (MPoolnode)element)
llist_insert_next (&near->node, &((MPoolnode)element)->node);
else
llist_insert_prev (&near->node, &((MPoolnode)element)->node);
}
else
llist_insert_tail (&self->freelist, &((MPoolnode)element)->node);
bitmap_clear_element (cluster, self, element);
++self->elements_free;
}
}
unsigned
mpool_available (MPool self)
{
return self->elements_free;
}
MPool
mpool_reserve (MPool self, unsigned nelements)
{
if (self)
while (self->elements_free < nelements)
if (!mpool_cluster_alloc_ (self))
return NULL;
return self;
}
void
nobug_mpool_dump (const_MPool self,
const int depth,
const char* file,
const int line,
const char* func)
{
if (self && depth)
{
DUMP_LOG ("mpool %p: ", self);
if (depth > 1)
{
DUMP_LOG (" elements_per_cluster %u: ", self->elements_per_cluster);
DUMP_LOG (" elements_free %u: ", self->elements_free);
}
if (depth > 2)
{
DUMP_LOG (" clusters %p: ", self->clusters);
int i = 0;
LLIST_FOREACH (&self->clusters, cluster)
DUMP_LOG (" %p: %u", cluster, ++i);
}
if (depth > 3)
{
DUMP_LOG (" freelist %p: ", self->freelist);
int i = 0;
LLIST_FOREACH (&self->freelist, node)
DUMP_LOG (" %p: %u", node, ++i);
}
}
}

173
src/lib/mpool.h Normal file
View file

@ -0,0 +1,173 @@
/*
mpool.h - memory pool for constant sized objects
Copyright (C) Lumiera.org
2009, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <nobug.h>
#include "lib/llist.h"
#include "include/logging.h"
/*
//mpool Memory Pools
//mpool ------------
//mpool
//mpool This memory pools are implemented as clusters of fixed sized elements. New clusters
//mpool are allocated on demand or manually preallocated with a `reserve()` operation. The pool
//mpool can be optimized by a `optimize()` operation which sorts the freelist by the addresses of
//mpool free elements and optionally moves elements (when a move function is provided) to lower
//mpool to fill up holes and improve cache locality.
//mpool Clusters can be reclaimed with a `collect()` operation. Optimization and Collection are
//mpool optional and are never automatically called.
//mpool
*/
/*
//index.mpool_destroy_fn xref:mpool_destroy_fn[mpool_destroy_fn]:: function prototype for destroying elements
//mpool [[mpool_destroy_fn]]
//mpool .mpool_destroy_fn
//mpool When a memory pool gets destroyed it can call a destructor for any element which is still in the pool.
//mpool This destructor is optional.
//mpool
//mpool typedef void (*mpool_destroy_fn)(void* self)
//mpool
//mpool `self`::
//mpool element to be destroyed
//mpool
*/
typedef void (*mpool_destroy_fn)(void* self);
/*
//index.struct_mpool xref:struct_mpool[mpool (struct)]:: the memory pool management structure
//mpool [[struct_mpool]]
//mpool .mpool
//mpool typedef struct mpool_struct mpool
//mpool typedef mpool* MPool
//mpool typedef const mpool* const_MPool
//mpool
//mpool This structure should be considered opaque except for the documented members
//mpool which may be read.
//mpool
//mpool `unsigned mpool.elements_free`::
//mpool number of free elements in the pool
//mpool
*/
typedef struct mpool_struct mpool;
typedef mpool* MPool;
typedef const mpool* const_MPool;
struct mpool_struct
{
llist freelist;
llist clusters;
size_t elem_size;
unsigned elements_per_cluster;
unsigned elements_free; /* a counter of free elements is the price we pay to support a reserve() operation */
void* locality;
mpool_destroy_fn destroy;
};
/*
//index.mpool_init xref:mpool_init[mpool_init]:: initialize a new memory pool
//mpool [[mpool_init]]
//mpool .mpool_init
//mpool Memory pools must be initialized before being used.
//mpool
//mpool MPool mpool_init (MPool self, size_t elem_size, unsigned elements_per_cluster, mpool_move_fn mv, mpool_destroy_fn dtor)
//mpool
//mpool `self`::
//mpool pointer to the memory pool structure to be initialized
//mpool `elem_size`::
//mpool size for a single element
//mpool `elements_per_cluster`::
//mpool how many elements to put into a cluster
//mpool `dtor`::
//mpool pointer to an optional destructor function or NULL
//mpool return::
//mpool self
//mpool
*/
MPool
mpool_init (MPool self, size_t elem_size, unsigned elements_per_cluster, mpool_destroy_fn dtor);
/*
//index.mpool_destroy xref:mpool_destroy[mpool_destroy]:: destroy a memory pool
//mpool [[mpool_destroy]]
//mpool .mpool_destroy
//mpool A memory pool is not used anymore it should be destroyed. This frees all memory allocated with it.
//mpool When a destructor was provided at construction time, then this destructor is used on all non free elements
//mpool before before the memory is freed. If no destructor was given then the memory is just freed.
//mpool
//mpool MPool mpool_destroy (MPool self)
//mpool
//mpool `self`::
//mpool pointer to an initialized memory pool to be destroyed.
//mpool return::
//mpool self
//mpool
//mpool
*/
MPool
mpool_destroy (MPool self);
/*
query how much free elements are available
*/
unsigned
mpool_available (MPool self);
/*
resize the pool that at least nelements become available without cluster reallocations
*/
MPool
mpool_reserve (MPool self, unsigned nelements);
/*
allocate and initialize a new cluster (internal)
*/
MPool
mpool_cluster_alloc_ (MPool self);
/*
alloc one element from the pool
*/
void* mpool_alloc (MPool self);
/*
put a element back on the pool
*/
void
mpool_free (MPool self, void* element);
void
nobug_mpool_dump (const_MPool self,
const int depth,
const char* file,
const int line,
const char* func);

46
tests/15mpool.tests Normal file
View file

@ -0,0 +1,46 @@
TESTING "Memory pool tests" ./test-mpool
TEST "init/destroy" basic <<END
err: initialized
err: allocated
err: freed
err: destroyed
return: 0
END
TEST "auto destruction" destroy <<END
return: !0
END
TEST "cluster allocation" clusters <<END
return: !0
END
TEST "random usage" random <<END
return: !0
END
TEST "stats" statscheck <<END
return: !0
END
TEST "optimizer" optimize <<END
return: !0
END
TEST "collector" collect <<END
return: !0
END
TEST "reserve" reserve <<END
return: !0
END

View file

@ -34,6 +34,11 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c
test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_llist_LDADD = $(NOBUGMT_LUMIERA_LIBS) liblumiera.la -lboost_program_options-mt -lboost_regex-mt
check_PROGRAMS += test-mpool
test_mpool_SOURCES = $(tests_srcdir)/library/test-mpool.c
test_mpool_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_mpool_LDADD = liblumiera.la $(NOBUGMT_LUMIERA_LIBS) liblumieracommon.la liblumieraproc.la -ldl -lboost_program_options-mt -lboost_regex-mt
check_PROGRAMS += test-psplay
test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c
test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/

191
tests/library/test-mpool.c Normal file
View file

@ -0,0 +1,191 @@
/*
test-mpool.c - memory pool for constant sized objects
Copyright (C) Lumiera.org
2009, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "tests/test.h"
#include "lib/mpool.h"
static void
dtor (void* o)
{
ECHO("%x @%p", *(int*)o, o);
}
static void
move (void* a, void* b)
{
ECHO ("%p (%x) to %p ", b, *(int*)b, a);
*(int*)a = *(int*)b;
*(void**)b = NULL;
}
TESTS_BEGIN
TEST ("basic")
{
mpool mypool;
mpool_init (&mypool, sizeof(void*), 10, move, dtor);
ECHO ("initialized");
void* element;
element = mpool_alloc (&mypool);
ECHO ("allocated %p", element);
*(int*)element = 0xdeadbabe;
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_free (&mypool, element);
ECHO ("freed");
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_destroy (&mypool);
ECHO ("destroyed");
}
TEST ("destroy")
{
mpool mypool;
mpool_init (&mypool, sizeof(void*), 10, move, dtor);
ECHO ("initialized");
void* element;
element = mpool_alloc (&mypool);
ECHO ("allocated %p", element);
*(int*)element = 0xbabeface;
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_destroy (&mypool);
ECHO ("destroyed");
}
TEST ("clusters")
{
mpool mypool;
mpool_init (&mypool, sizeof(void*), 2, move, dtor);
ECHO ("initialized");
for (int i = 1; i <= 5; ++i)
{
void* element;
element = mpool_alloc (&mypool);
ECHO ("allocated %p", element);
*(int*)element = i;
}
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_destroy (&mypool);
ECHO ("destroyed");
}
TEST ("clusters_big")
{
mpool mypool;
mpool_init (&mypool, sizeof(void*), 200, move, dtor);
ECHO ("initialized");
for (int i = 1; i <= 700; ++i)
{
void* element;
element = mpool_alloc (&mypool);
ECHO ("allocated %p", element);
*(int*)element = i;
}
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_destroy (&mypool);
ECHO ("destroyed");
}
TEST ("collect")
{
mpool mypool;
mpool_init (&mypool, 24, 4, move, dtor);
ECHO ("initialized");
void* elem[32];
for (int i = 1; i <= 15; ++i)
{
elem[i] = mpool_alloc (&mypool);
*(int*)(elem[i]) = i;
}
ECHO ("allocated");
for (int i = 1; i <= 15; i+=3)
{
mpool_free (&mypool, elem[i]);
}
ECHO ("freed some");
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_collect (&mypool, 0);
ECHO ("collected");
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_destroy (&mypool);
ECHO ("destroyed");
}
TEST ("collect_no_move")
{
mpool mypool;
mpool_init (&mypool, 24, 4, NULL, dtor);
ECHO ("initialized");
void* elem[32];
for (int i = 1; i <= 15; ++i)
{
elem[i] = mpool_alloc (&mypool);
*(int*)(elem[i]) = i;
}
ECHO ("allocated");
for (int i = 1; i <= 15; i+=3)
{
mpool_free (&mypool, elem[i]);
}
ECHO ("freed some");
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_collect (&mypool, 0);
ECHO ("collected");
DUMP(NOBUG_ON, mpool, &mypool, 4);
mpool_destroy (&mypool);
ECHO ("destroyed");
}
TEST ("reserve")
{
}
TESTS_END