From 1424ac7d4d211fab7d3dcb0faeeb74ca641ca0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Zurcher?= Date: Fri, 4 Jan 2013 08:41:47 +0000 Subject: [PATCH] =?UTF-8?q?From:=20J=C3=A9r=C3=A9my=20Zurcher=20=20Subject:=20[E-devel]=202=20steps=20eina=5Fshare=5Fcom?= =?UTF-8?q?mon=5Fdel=20speed=20up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit builtin node is never unlinked even if empty, always is the last of the queue, so that it can be used to get a pointer to head. cost: never unlink or promote builtin node. benefit: no need to hash and search rbtree to unlink an empty node, only to remove an empty head. store full hash in Eina_Share_Common_Head, so we only hash once use 8 lower bits as node hash, use next 8 bits as bucket index. cost: have to apply 0xFF mask on hash in rbtree callbacks. benefit: no need to hash when removing an empty head. SVN revision: 82161 --- ChangeLog | 4 ++ NEWS | 1 + src/lib/eina/eina_share_common.c | 103 +++++++++++++++++-------------- src/lib/eina/eina_stringshare.c | 25 ++++++-- 4 files changed, 80 insertions(+), 53 deletions(-) diff --git a/ChangeLog b/ChangeLog index cb77d720fc..d78204ca1c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-01-04 Jérémy Zurcher + + * Improve eina_share string del speed by a maybe 5-15%. + 2013-01-03 Gustavo Sverzut Barbieri (k-s) * Add eina_alloc.h to Eina.h to define alloca() diff --git a/NEWS b/NEWS index f46081e356..185c977500 100644 --- a/NEWS +++ b/NEWS @@ -73,6 +73,7 @@ Improvements: * all efl object-freeing functions now take NULL without crashing or erroring * use Eina_File in webp, gif, tiff, png and eet loader * Eina.h includes eina_alloca.h/alloca.h to define alloca() + * Improved eina share del speed. Fixes: * Fix PPC (big endian) image codec bug. diff --git a/src/lib/eina/eina_share_common.c b/src/lib/eina/eina_share_common.c index 29c9f47572..0dbf37d5f9 100644 --- a/src/lib/eina/eina_share_common.c +++ b/src/lib/eina/eina_share_common.c @@ -88,6 +88,8 @@ #define EINA_SHARE_COMMON_BUCKETS 256 #define EINA_SHARE_COMMON_MASK 0xFF +#define EINA_SHARE_COMMON_BUCKET_IDX(h) ((h >> 8) & EINA_SHARE_COMMON_MASK) +#define EINA_SHARE_COMMON_NODE_HASH(h) (h & EINA_SHARE_COMMON_MASK) static const char EINA_MAGIC_SHARE_STR[] = "Eina Share"; static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head"; @@ -113,8 +115,13 @@ static int _eina_share_common_count = 0; } \ } while (0) -#ifdef EINA_SHARE_USAGE +#ifdef EINA_STRINGSHARE_USAGE typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population; +struct _Eina_Share_Common_Population +{ + int count; + int max; +}; #endif typedef struct _Eina_Share_Common Eina_Share_Common; @@ -125,8 +132,9 @@ struct _Eina_Share { Eina_Share_Common *share; Eina_Magic node_magic; -#ifdef EINA_SHARE_COMMON_USAGE +#ifdef EINA_STRINGSHARE_USAGE Eina_Share_Common_Population population; + Eina_Share_Common_Population population_group[4]; int max_node_population; #endif }; @@ -156,7 +164,7 @@ struct _Eina_Share_Common_Head int hash; -#ifdef EINA_SHARE_COMMON_USAGE +#ifdef EINA_STRINGSHARE_USAGE int population; #endif @@ -168,22 +176,7 @@ Eina_Bool _share_common_threads_activated = EINA_FALSE; static Eina_Lock _mutex_big; -#ifdef EINA_SHARE_COMMON_USAGE -struct _Eina_Share_Common_Population -{ - int count; - int max; -}; - -static Eina_Share_Common_Population population = { 0, 0 }; - -static Eina_Share_Common_Population population_group[4] = -{ - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 } -}; +#ifdef EINA_STRINGSHARE_USAGE static void _eina_share_common_population_init(Eina_Share *share) @@ -277,7 +270,7 @@ eina_share_common_population_del(Eina_Share *share, int slen) } static void -_eina_share_common_population_head_init(Eina_Share *share, +_eina_share_common_population_head_init(EINA_UNUSED Eina_Share *share, Eina_Share_Common_Head *head) { head->population = 1; @@ -293,13 +286,13 @@ _eina_share_common_population_head_add(Eina_Share *share, } static void -_eina_share_common_population_head_del(Eina_Share *share, +_eina_share_common_population_head_del(EINA_UNUSED Eina_Share *share, Eina_Share_Common_Head *head) { head->population--; } -#else /* EINA_SHARE_COMMON_USAGE undefined */ +#else /* EINA_STRINGSHARE_USAGE undefined */ static void _eina_share_common_population_init(EINA_UNUSED Eina_Share *share) { } @@ -338,7 +331,7 @@ _eina_share_common_cmp(const Eina_Share_Common_Head *ed, { EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0); - return ed->hash - *hash; + return EINA_SHARE_COMMON_NODE_HASH(ed->hash) - *hash; } static Eina_Rbtree_Direction @@ -349,7 +342,7 @@ _eina_share_common_node(const Eina_Share_Common_Head *left, EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left, , 0); EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0); - if (left->hash - right->hash < 0) + if (EINA_SHARE_COMMON_NODE_HASH(left->hash) - EINA_SHARE_COMMON_NODE_HASH(right->hash) < 0) return EINA_RBTREE_LEFT; return EINA_RBTREE_RIGHT; @@ -473,10 +466,13 @@ _eina_share_common_head_find(Eina_Share_Common_Head *head, for (; node; prev = node, node = node->next) if (_eina_share_common_node_eq(node, str, slen)) { - /* promote node, make hot items be at the beginning */ - prev->next = node->next; - node->next = head->head; - head->head = node; + /* promote node except builtin_node, make hot items be at the beginning */ + if (node->next) + { + prev->next = node->next; + node->next = head->head; + head->head = node; + } return node; } @@ -515,6 +511,20 @@ _eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash) EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL); } +static Eina_Share_Common_Head * +_eina_share_common_head_from_node(Eina_Share_Common_Node *node) +{ + Eina_Share_Common_Head *head; + const size_t offset = offsetof(Eina_Share_Common_Head, builtin_node); + + while (node->next) + node = node->next; + head = (Eina_Share_Common_Head *)((char*)node - offset); + EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(head, , 0); + + return head; +} + static Eina_Share_Common_Node * _eina_share_common_node_alloc(unsigned int slen, unsigned int null_size) { @@ -716,7 +726,7 @@ eina_share_common_add_length(Eina_Share *share, { Eina_Share_Common_Head **p_bucket, *ed; Eina_Share_Common_Node *el; - int hash_num, hash; + int hash; if (!str) return NULL; @@ -727,13 +737,11 @@ eina_share_common_add_length(Eina_Share *share, return NULL; hash = eina_hash_superfast(str, slen); - hash_num = hash & 0xFF; - hash = (hash >> 8) & EINA_SHARE_COMMON_MASK; eina_lock_take(&_mutex_big); - p_bucket = share->share->buckets + hash_num; + p_bucket = share->share->buckets + EINA_SHARE_COMMON_BUCKET_IDX(hash); - ed = _eina_share_common_find_hash(*p_bucket, hash); + ed = _eina_share_common_find_hash(*p_bucket, EINA_SHARE_COMMON_NODE_HASH(hash)); if (!ed) { const char *s = _eina_share_common_add_head(share, @@ -808,7 +816,6 @@ eina_share_common_del(Eina_Share *share, const char *str) Eina_Share_Common_Head *ed; Eina_Share_Common_Head **p_bucket; Eina_Share_Common_Node *node; - int hash_num, hash; if (!str) return EINA_TRUE; @@ -830,25 +837,24 @@ eina_share_common_del(Eina_Share *share, const char *str) node->references = 0; - hash = eina_hash_superfast(str, slen); - hash_num = hash & 0xFF; - hash = (hash >> 8) & EINA_SHARE_COMMON_MASK; - - p_bucket = share->share->buckets + hash_num; - ed = _eina_share_common_find_hash(*p_bucket, hash); + ed = _eina_share_common_head_from_node(node); if (!ed) goto on_error; EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, eina_lock_release(&_mutex_big), EINA_FALSE); - if (!_eina_share_common_head_remove_node(ed, node)) - goto on_error; - if (node != &ed->builtin_node) - MAGIC_FREE(node); + { + if (!_eina_share_common_head_remove_node(ed, node)) + goto on_error; + MAGIC_FREE(node); + } - if (!ed->head) - _eina_share_common_del_head(p_bucket, ed); + if (!ed->head || ed->head->references == 0) + { + p_bucket = share->share->buckets + EINA_SHARE_COMMON_BUCKET_IDX(ed->hash); + _eina_share_common_del_head(p_bucket, ed); + } else _eina_share_common_population_head_del(share, ed); @@ -911,7 +917,7 @@ eina_share_common_dump(Eina_Share *share, void (*additional_dump)( if (additional_dump) additional_dump(&di); -#ifdef EINA_SHARE_COMMON_USAGE +#ifdef EINA_STRINGSHARE_USAGE /* One character strings are not counted in the hash. */ di.saved += share->population_group[0].count * sizeof(char); di.saved += share->population_group[1].count * sizeof(char) * 2; @@ -922,9 +928,10 @@ eina_share_common_dump(Eina_Share *share, void (*additional_dump)( printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n", di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0); -#ifdef EINA_SHARE_COMMON_USAGE +#ifdef EINA_STRINGSHARE_USAGE printf("DDD: Allocated strings: %i\n", share->population.count); printf("DDD: Max allocated strings: %i\n", share->population.max); + printf("DDD: Max shared strings per node : %i\n", share->max_node_population); for (i = 0; i < sizeof (share->population_group) / diff --git a/src/lib/eina/eina_stringshare.c b/src/lib/eina/eina_stringshare.c index 2acb98ca8a..ceae4f3de8 100644 --- a/src/lib/eina/eina_stringshare.c +++ b/src/lib/eina/eina_stringshare.c @@ -578,13 +578,18 @@ eina_stringshare_del(Eina_Stringshare *str) slen = 4; /* handled later */ if (slen < 2) - return; + { + eina_share_common_population_del(stringshare_share, slen); + + return; + } else if (slen < 4) { eina_share_common_population_del(stringshare_share, slen); eina_lock_take(&_mutex_small); _eina_stringshare_small_del(str, slen); eina_lock_release(&_mutex_small); + return; } @@ -598,16 +603,26 @@ eina_stringshare_add_length(const char *str, unsigned int slen) if (!str) return NULL; else if (slen == 0) - return ""; + { + eina_share_common_population_add(stringshare_share, slen); + + return ""; + } else if (slen == 1) - return (Eina_Stringshare *) _eina_stringshare_single + ((*str) << 1); + { + eina_share_common_population_add(stringshare_share, slen); + + return (Eina_Stringshare *) _eina_stringshare_single + ((*str) << 1); + } else if (slen < 4) { const char *s; + eina_share_common_population_add(stringshare_share, slen); eina_lock_take(&_mutex_small); s = _eina_stringshare_small_add(str, slen); eina_lock_release(&_mutex_small); + return s; } @@ -712,7 +727,7 @@ eina_stringshare_ref(Eina_Stringshare *str) int slen; if (!str) - return eina_share_common_ref(stringshare_share, str); + return NULL; /* special cases */ if (str[0] == '\0') @@ -735,8 +750,8 @@ eina_stringshare_ref(Eina_Stringshare *str) else if (slen < 4) { const char *s; - eina_share_common_population_add(stringshare_share, slen); + eina_share_common_population_add(stringshare_share, slen); eina_lock_take(&_mutex_small); s = _eina_stringshare_small_add(str, slen); eina_lock_release(&_mutex_small);