eina: add eina_mempool_repack.

WARNING: HIGHLY UNTESTED PIECE OF CODE ! USE IT AT YOUR OWN RISK !


SVN revision: 58554
This commit is contained in:
Cedric BAIL 2011-04-11 14:07:42 +00:00
parent 8e68291273
commit 29639eea35
12 changed files with 232 additions and 64 deletions

View File

@ -45,3 +45,4 @@
2011-05-11 Cedric Bail
* Add eina_inlist_sort.
* Add eina_mempool_repack.

View File

@ -36,6 +36,7 @@ struct _Eina_Mempool_Backend
void (*garbage_collect)(void *data);
void (*statistics)(void *data);
void (*shutdown)(void *data);
void (*repack)(void *data, Eina_Mempool_Repack_Cb cb, void *cb_data);
};
struct _Eina_Mempool

View File

@ -84,6 +84,14 @@ typedef struct _Eina_Mempool Eina_Mempool;
*/
typedef struct _Eina_Mempool_Backend Eina_Mempool_Backend;
/**
* @typedef Eina_Mempool_Repack_Cb
* Type for a callback who need to unreference an old object from a mempool
* and reference the new one instead. Memcpy is taken care by the mempool.
*/
typedef void (*Eina_Mempool_Repack_Cb)(void *dst, void *src, void *data);
EAPI extern Eina_Error EINA_ERROR_NOT_MEMPOOL_MODULE;
EAPI Eina_Mempool *eina_mempool_add(const char *module, const char *context, const char *options, ...) EINA_MALLOC EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
@ -93,6 +101,9 @@ static inline void *eina_mempool_realloc(Eina_Mempool *mp, void *element, unsign
static inline void *eina_mempool_malloc(Eina_Mempool *mp, unsigned int size) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
static inline void eina_mempool_free(Eina_Mempool *mp, void *element) EINA_ARG_NONNULL(1);
EAPI void eina_mempool_repack(Eina_Mempool *mp,
Eina_Mempool_Repack_Cb cb,
void *data) EINA_ARG_NONNULL(1, 2);
EAPI void eina_mempool_gc(Eina_Mempool *mp) EINA_ARG_NONNULL(1);
EAPI void eina_mempool_statistics(Eina_Mempool *mp) EINA_ARG_NONNULL(1);

View File

@ -319,6 +319,14 @@ EAPI void eina_mempool_del(Eina_Mempool *mp)
free(mp);
}
EAPI void eina_mempool_repack(Eina_Mempool *mp, Eina_Mempool_Repack_Cb cb, void *data)
{
EINA_SAFETY_ON_NULL_RETURN(mp);
EINA_SAFETY_ON_NULL_RETURN(mp->backend.shutdown);
DBG("mp=%p", mp);
mp->backend.repack(mp->backend_data, cb, data);
}
EAPI void eina_mempool_gc(Eina_Mempool *mp)
{
EINA_SAFETY_ON_NULL_RETURN(mp);

View File

@ -94,6 +94,8 @@
#define EINA_MAGIC_SIMPLE_XML_DATA 0x98761261
#define EINA_MAGIC_SIMPLE_XML_ATTRIBUTE 0x98761262
#define EINA_MAGIC_CLASS 0x9877CB30
/* undef the following, we want out version */
#undef FREE
#define FREE(ptr) \

View File

@ -269,7 +269,8 @@ static Eina_Mempool_Backend _backend = {
NULL, /* realloc */
NULL, /* garbage collect */
&_statistics,
&_shutdown
&_shutdown,
NULL /* repack */
};
Eina_Bool buddy_init(void)

View File

@ -151,6 +151,94 @@ _eina_chained_mp_pool_free(Chained_Pool *p)
free(p);
}
static int
_eina_chained_mempool_usage_cmp(const Eina_Inlist *l1, const Eina_Inlist *l2)
{
const Chained_Pool *p1;
const Chained_Pool *p2;
p1 = EINA_INLIST_CONTAINER_GET(l1, const Chained_Pool);
p2 = EINA_INLIST_CONTAINER_GET(l2, const Chained_Pool);
return p2->usage - p1->usage;
}
static void *
_eina_chained_mempool_alloc_in(Chained_Mempool *pool, Chained_Pool *p)
{
void *mem;
if (p->last)
{
mem = p->last;
p->last += pool->item_alloc;
if (p->last >= p->limit)
p->last = NULL;
}
else
{
#ifndef NVALGRIND
VALGRIND_MAKE_MEM_DEFINED(p->base, pool->item_alloc);
#endif
// Request a free pointer
mem = eina_trash_pop(&p->base);
}
// move to end - it just filled up
if (!p->base && !p->last)
pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
p->usage++;
pool->usage++;
#ifndef NVALGRIND
VALGRIND_MEMPOOL_ALLOC(pool, mem, pool->item_alloc);
#endif
return mem;
}
static Eina_Bool
_eina_chained_mempool_free_in(Chained_Mempool *pool, Chained_Pool *p, void *ptr)
{
void *pmem;
// pool mem base
pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
// is it in pool mem?
if (ptr < pmem)
{
#ifdef DEBUG
INF("%p is inside the private part of %p pool from %p Chained_Mempool (could be the sign of a buffer underrun).", ptr, p, pool);
#endif
return EINA_FALSE;
}
// freed node points to prev free node
eina_trash_push(&p->base, ptr);
// next free node is now the one we freed
p->usage--;
pool->usage--;
if (p->usage == 0)
{
// free bucket
pool->first = eina_inlist_remove(pool->first, EINA_INLIST_GET(p));
pool->root = eina_rbtree_inline_remove(pool->root, EINA_RBTREE_GET(p),
_eina_chained_mp_pool_cmp, NULL);
_eina_chained_mp_pool_free(p);
return EINA_TRUE;
}
else
{
// move to front
pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p));
}
return EINA_FALSE;
}
static void *
eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
{
@ -210,28 +298,7 @@ eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
_eina_chained_mp_pool_cmp, NULL);
}
if (p->last)
{
mem = p->last;
p->last += pool->item_alloc;
if (p->last >= p->limit)
p->last = NULL;
}
else
{
#ifndef NVALGRIND
VALGRIND_MAKE_MEM_DEFINED(p->base, pool->item_alloc);
#endif
// Request a free pointer
mem = eina_trash_pop(&p->base);
}
// move to end - it just filled up
if (!p->base && !p->last)
pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
p->usage++;
pool->usage++;
mem = _eina_chained_mempool_alloc_in(pool, p);
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
@ -244,10 +311,6 @@ eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
}
#endif
#ifndef NVALGRIND
VALGRIND_MEMPOOL_ALLOC(pool, mem, pool->item_alloc);
#endif
return mem;
}
@ -257,7 +320,6 @@ eina_chained_mempool_free(void *data, void *ptr)
Chained_Mempool *pool = data;
Eina_Rbtree *r;
Chained_Pool *p;
void *pmem;
// look 4 pool
@ -290,36 +352,7 @@ eina_chained_mempool_free(void *data, void *ptr)
p = EINA_RBTREE_CONTAINER_GET(r, Chained_Pool);
// pool mem base
pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
// is it in pool mem?
if (ptr < pmem)
{
#ifdef DEBUG
INF("%p is inside the private part of %p pool from %p Chained_Mempool (could be the sign of a buffer underrun).", ptr, p, pool);
#endif
goto on_error;
}
// freed node points to prev free node
eina_trash_push(&p->base, ptr);
// next free node is now the one we freed
p->usage--;
pool->usage--;
if (p->usage == 0)
{
// free bucket
pool->first = eina_inlist_remove(pool->first, EINA_INLIST_GET(p));
pool->root = eina_rbtree_inline_remove(pool->root, EINA_RBTREE_GET(p),
_eina_chained_mp_pool_cmp, NULL);
_eina_chained_mp_pool_free(p);
}
else
{
// move to front
pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p));
}
_eina_chained_mempool_free_in(pool, p, ptr);
on_error:
#ifndef NVALGRIND
@ -342,6 +375,111 @@ eina_chained_mempool_free(void *data, void *ptr)
return;
}
static void
eina_chained_mempool_repack(void *data,
Eina_Mempool_Repack_Cb cb,
void *cb_data)
{
Chained_Mempool *pool = data;
Chained_Pool *start;
Chained_Pool *tail;
/* FIXME: Improvement - per Chained_Pool lock */
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_lock(&pool->mutex);
# else
WaitForSingleObject(pool->mutex, INFINITE);
# endif
}
#ifdef EFL_DEBUG_THREADS
else
assert(pthread_equal(pool->self, pthread_self()));
#endif
#endif
pool->first = eina_inlist_sort(pool->first,
(Eina_Compare_Cb) _eina_chained_mempool_usage_cmp);
/*
idea : remove the almost empty pool at the beginning of the list by
moving data in the last pool with empty slot
*/
tail = EINA_INLIST_CONTAINER_GET(pool->first->last, Chained_Pool);
while (tail && tail->usage == pool->pool_size)
tail = EINA_INLIST_CONTAINER_GET((EINA_INLIST_GET(tail)->prev), Chained_Pool);
while (tail)
{
unsigned char *src;
unsigned char *dst;
start = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool);
if (start == tail || start->usage == pool->pool_size)
break;
for (src = start->limit - pool->group_size;
src != start->limit;
src += pool->item_alloc)
{
Eina_Bool is_free = EINA_FALSE;
Eina_Bool is_dead;
/* Do we have something inside that piece of memory */
if (start->last != NULL && src >= start->last)
{
is_free = EINA_TRUE;
}
else
{
Eina_Trash *over = start->base;
while (over != NULL && (unsigned char*) over != src)
over = over->next;
if (over == NULL)
is_free = EINA_TRUE;
}
if (is_free) continue ;
/* get a new memory pointer from the latest most occuped pool */
dst = _eina_chained_mempool_alloc_in(pool, tail);
/* move data from one to another */
memcpy(dst, src, pool->item_alloc);
/* notify caller */
cb(dst, src, cb_data);
/* destroy old pointer */
is_dead = _eina_chained_mempool_free_in(pool, start, src);
/* search last tail with empty slot */
while (tail && tail->usage == pool->pool_size)
tail = EINA_INLIST_CONTAINER_GET((EINA_INLIST_GET(tail)->prev),
Chained_Pool);
/* no more free space */
if (!tail || tail == start) break;
if (is_dead) break;
}
}
/* FIXME: improvement - reorder pool so that the most used one get in front */
#ifdef EFL_HAVE_THREADS
if (_threads_activated)
{
# ifdef EFL_HAVE_POSIX_THREADS
pthread_mutex_unlock(&pool->mutex);
# else
ReleaseMutex(pool->mutex);
# endif
}
#endif
}
static void *
eina_chained_mempool_realloc(__UNUSED__ void *data,
__UNUSED__ void *element,
@ -451,7 +589,8 @@ static Eina_Mempool_Backend _eina_chained_mp_backend = {
&eina_chained_mempool_realloc,
NULL,
NULL,
&eina_chained_mempool_shutdown
&eina_chained_mempool_shutdown,
&eina_chained_mempool_repack
};
Eina_Bool chained_init(void)

View File

@ -153,7 +153,8 @@ static Eina_Mempool_Backend _eina_ememoa_mp_backend = {
.alloc = &eina_ememoa_fixed_malloc,
.free = &eina_ememoa_fixed_free,
.garbage_collect = &eina_ememoa_fixed_gc,
.statistics = &eina_ememoa_fixed_statistics
.statistics = &eina_ememoa_fixed_statistics,
.repack = NULL
};
Eina_Bool ememoa_fixed_init(void)

View File

@ -160,7 +160,8 @@ static Eina_Mempool_Backend _eina_ememoa_unknown_mp_backend = {
.alloc = &eina_ememoa_unknown_size_malloc,
.free = &eina_ememoa_unknown_size_free,
.garbage_collect = &eina_ememoa_unknown_size_gc,
.statistics = &eina_ememoa_unknown_size_statistics
.statistics = &eina_ememoa_unknown_size_statistics,
.repack = NULL
};
Eina_Bool ememoa_unknown_init(void)

View File

@ -247,7 +247,8 @@ static Eina_Mempool_Backend _eina_fixed_bitmap_mp_backend = {
&eina_fixed_bitmap_realloc,
NULL,
NULL,
&eina_fixed_bitmap_shutdown
&eina_fixed_bitmap_shutdown,
NULL
};
Eina_Bool fixed_bitmap_init(void)

View File

@ -368,7 +368,8 @@ static Eina_Mempool_Backend _eina_one_big_mp_backend = {
&eina_one_big_realloc,
NULL,
NULL,
&eina_one_big_shutdown
&eina_one_big_shutdown,
NULL
};
Eina_Bool one_big_init(void)

View File

@ -67,7 +67,8 @@ static Eina_Mempool_Backend _eina_pass_through_mp_backend = {
&eina_pass_through_realloc,
NULL,
NULL,
&eina_pass_through_shutdown
&eina_pass_through_shutdown,
NULL
};
Eina_Bool pass_through_init(void)