diff --git a/legacy/eina/ChangeLog b/legacy/eina/ChangeLog index 304e652047..cad2484b90 100644 --- a/legacy/eina/ChangeLog +++ b/legacy/eina/ChangeLog @@ -1,4 +1,8 @@ 2011-01-29 Carsten Haitzler (The Rasterman) 1.0.0 release - + +2011-02-01 Cedric Bail + + * Improve scalability and raw speed of Chained Mempool. + diff --git a/legacy/eina/src/include/eina_rbtree.h b/legacy/eina/src/include/eina_rbtree.h index 76172365cb..a4b46c2758 100644 --- a/legacy/eina/src/include/eina_rbtree.h +++ b/legacy/eina/src/include/eina_rbtree.h @@ -95,6 +95,12 @@ struct _Eina_Rbtree */ #define EINA_RBTREE_GET(Rbtree) & ((Rbtree)->__rbtree) +/** + * @def EINA_RBTREE_CONTAINER_GET + * find back the container of an red black tree. + */ +#define EINA_RBTREE_CONTAINER_GET(Ptr, Type) ((Type *)((char *)Ptr - offsetof(Type, __rbtree))) + /** * @typedef Eina_Rbtree_Cmp_Node_Cb * Function used compare two nodes and see which direction to navigate. diff --git a/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c b/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c index df9fe85441..0683ff5f5a 100644 --- a/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c +++ b/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c @@ -42,6 +42,7 @@ #include "eina_module.h" #include "eina_mempool.h" #include "eina_trash.h" +#include "eina_rbtree.h" #include "eina_private.h" @@ -50,6 +51,7 @@ #endif #ifdef DEBUG +#include #include "eina_log.h" static int _eina_chained_mp_log_dom = -1; @@ -64,6 +66,7 @@ typedef struct _Chained_Mempool Chained_Mempool; struct _Chained_Mempool { Eina_Inlist *first; + Eina_Rbtree *root; const char *name; int item_alloc; int pool_size; @@ -86,6 +89,7 @@ typedef struct _Chained_Pool Chained_Pool; struct _Chained_Pool { EINA_INLIST; + EINA_RBTREE; Eina_Trash *base; int usage; @@ -93,6 +97,24 @@ struct _Chained_Pool unsigned char *limit; }; +static inline Eina_Rbtree_Direction +_eina_chained_mp_pool_cmp(const Eina_Rbtree *left, const Eina_Rbtree *right, __UNUSED__ void *data) +{ + if (left < right) return EINA_RBTREE_LEFT; + return EINA_RBTREE_RIGHT; +} + +static inline int +_eina_chained_mp_pool_key_cmp(const Eina_Rbtree *node, const void *key, + __UNUSED__ int length, __UNUSED__ void *data) +{ + const Chained_Pool *r = EINA_RBTREE_CONTAINER_GET(node, const Chained_Pool); + + if (key > (void *) r->limit) return -1; + if (key < (void *) r) return 1; + return 0; +} + static inline Chained_Pool * _eina_chained_mp_pool_new(Chained_Mempool *pool) { @@ -151,16 +173,18 @@ eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size) #endif #endif - // look 4 pool from 2nd bucket on - EINA_INLIST_FOREACH(pool->first, p) - { - // base is not NULL - has a free slot - if (p->base || p->last) - { - pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p)); - break; - } - } + // Either we have some free space in the first one, or there is no free space. + p = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool); + + // base is not NULL - has a free slot + if (p && !p->base && !p->last) + p = NULL; + +#ifdef DEBUG + if (p == NULL) + EINA_INLIST_FOREACH(pool->first, p) + assert(!p->base && !p->last); +#endif // we have reached the end of the list - no free pools if (!p) @@ -182,6 +206,8 @@ eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size) } pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(p)); + pool->root = eina_rbtree_inline_insert(pool->root, EINA_RBTREE_GET(p), + _eina_chained_mp_pool_cmp, NULL); } if (p->last) @@ -229,6 +255,7 @@ static void eina_chained_mempool_free(void *data, void *ptr) { Chained_Mempool *pool = data; + Eina_Rbtree *r; Chained_Pool *p; void *pmem; @@ -249,36 +276,52 @@ eina_chained_mempool_free(void *data, void *ptr) #endif #endif - EINA_INLIST_FOREACH(pool->first, p) - { - // Could the pointer be inside that pool - if ((unsigned char*) ptr < p->limit) - { - // pool mem base - pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool)); - // is it in pool mem? - if (ptr >= pmem) - { - // 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)); - _eina_chained_mp_pool_free(p); - } - else - // move to front - pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p)); + // searching for the right mempool + r = eina_rbtree_inline_lookup(pool->root, ptr, 0, _eina_chained_mp_pool_key_cmp, NULL); - break; - } - } - } + // related mempool not found + if (!r) + { +#ifdef DEBUG + INF("%p is not the property of %p Chained_Mempool", ptr, pool); +#endif + goto on_error; + } + 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)); + } + + on_error: #ifndef NVALGRIND if (ptr) { @@ -371,9 +414,16 @@ eina_chained_mempool_shutdown(void *data) #endif mp->first = eina_inlist_remove(mp->first, mp->first); + mp->root = eina_rbtree_inline_remove(mp->root, EINA_RBTREE_GET(p), + _eina_chained_mp_pool_cmp, NULL); _eina_chained_mp_pool_free(p); } +#ifdef DEBUG + if (mp->root) + INF("Bad news, list of pool and rbtree are out of sync for %p !", mp); +#endif + #ifndef NVALGRIND VALGRIND_DESTROY_MEMPOOL(mp); #endif