diff --git a/src/lib/eo/eo_ptr_indirection.c b/src/lib/eo/eo_ptr_indirection.c index cd578a5a2a..e3d6f62b6f 100644 --- a/src/lib/eo/eo_ptr_indirection.c +++ b/src/lib/eo/eo_ptr_indirection.c @@ -94,19 +94,20 @@ _eo_obj_pointer_get(const Eo_Id obj_id, const char *func_name, const char *file, EINA_PREFETCH(&(data->tables[0])); domain = (obj_id >> SHIFT_DOMAIN) & MASK_DOMAIN; tdata = _eo_table_data_table_get(data, domain); - EINA_PREFETCH(&(tdata->cache.id)); if (EINA_UNLIKELY(!tdata)) goto err; - + _eo_cache_prefetch(tdata); if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED)) { - if (obj_id == tdata->cache.id) - return tdata->cache.object; + _Eo_Object *obj; + + obj = _eo_cache_find(tdata, obj_id); + if (obj) return obj; mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; - EINA_PREFETCH_NOCACHE(&(tdata->eo_ids_tables[mid_table_id])); //prefetch for line 119 + EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id])); //prefetch for line 119 table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID; - EINA_PREFETCH_NOCACHE((tdata->eo_ids_tables[mid_table_id] + table_id)); //prefetch for line 121 + EINA_PREFETCH((tdata->eo_ids_tables[mid_table_id] + table_id)); //prefetch for line 121 entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; generation = obj_id & MASK_GENERATIONS; @@ -126,8 +127,7 @@ _eo_obj_pointer_get(const Eo_Id obj_id, const char *func_name, const char *file, if (entry->active && (entry->generation == generation)) { // Cache the result of that lookup - tdata->cache.object = entry->ptr; - tdata->cache.id = obj_id; + _eo_cache_store(tdata, obj_id, entry->ptr); return entry->ptr; } } @@ -136,17 +136,19 @@ _eo_obj_pointer_get(const Eo_Id obj_id, const char *func_name, const char *file, } else { + _Eo_Object *obj; + eina_lock_take(&(_eo_table_data_shared_data->obj_lock)); - if (obj_id == tdata->cache.id) // yes we return keeping the lock locked. that's why // you must call _eo_obj_pointer_done() wrapped // by EO_OBJ_DONE() to release - return tdata->cache.object; + obj = _eo_cache_find(tdata, obj_id); + if (obj) return obj; mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; - EINA_PREFETCH_NOCACHE(&(tdata->eo_ids_tables[mid_table_id])); + EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id])); table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID; - EINA_PREFETCH_NOCACHE((tdata->eo_ids_tables[mid_table_id] + table_id)); + EINA_PREFETCH((tdata->eo_ids_tables[mid_table_id] + table_id)); entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; generation = obj_id & MASK_GENERATIONS; @@ -167,8 +169,7 @@ _eo_obj_pointer_get(const Eo_Id obj_id, const char *func_name, const char *file, if (entry->active && (entry->generation == generation)) { // Cache the result of that lookup - tdata->cache.object = entry->ptr; - tdata->cache.id = obj_id; + _eo_cache_store(tdata, obj_id, entry->ptr); // yes we return keeping the lock locked. that's why // you must call _eo_obj_pointer_done() wrapped // by EO_OBJ_DONE() to release diff --git a/src/lib/eo/eo_ptr_indirection.x b/src/lib/eo/eo_ptr_indirection.x index 64bad07a06..33043b36e6 100644 --- a/src/lib/eo/eo_ptr_indirection.x +++ b/src/lib/eo/eo_ptr_indirection.x @@ -305,13 +305,19 @@ typedef struct typedef struct _Eo_Id_Data Eo_Id_Data; typedef struct _Eo_Id_Table_Data Eo_Id_Table_Data; +#define CACHENUM 2 +#define CACHELINE 64 +#define CACHELRU 1 + struct _Eo_Id_Table_Data { /* Cached eoid lookups */ +#if CACHENUM > 0 + Eo_Id cache_id[CACHENUM]; + _Eo_Object *cache_object[CACHENUM]; +#endif struct { - Eo_Id id; - _Eo_Object *object; const Eo *isa_id; const Efl_Class *klass; Eina_Bool isa; @@ -343,6 +349,100 @@ extern Eina_TLS _eo_table_data; extern Eo_Id_Data *_eo_table_data_shared; extern Eo_Id_Table_Data *_eo_table_data_shared_data; +#ifndef CACHELRU +static inline unsigned int +_eo_cache_slot_get(void) +{ +# if CACHENUM > 0 + static unsigned int num = 0; + + return (++num) % CACHENUM; +# endif +} +#endif + +static inline void +_eo_cache_prefetch(Eo_Id_Table_Data *tdata EINA_UNUSED) +{ +#if CACHENUM > 0 + int i; + + for (i = 0; i < CACHENUM; i += (CACHELINE / sizeof(void *))) + { + EINA_PREFETCH(&(tdata->cache_id[i])); + if ((sizeof(void *) * CACHENUM) >= CACHELINE) + { + EINA_PREFETCH(&(tdata->cache_object[i])); + } + } +#endif +} + +static inline _Eo_Object * +_eo_cache_find(Eo_Id_Table_Data *tdata EINA_UNUSED, Eo_Id obj_id EINA_UNUSED) +{ +#if CACHENUM > 0 + int i; + + for (i = 0; i < CACHENUM; i++) + { + if (obj_id == tdata->cache_id[i]) return tdata->cache_object[i]; + } +#endif + return NULL; +} + +static inline void +_eo_cache_store(Eo_Id_Table_Data *tdata EINA_UNUSED, Eo_Id obj_id EINA_UNUSED, _Eo_Object *obj EINA_UNUSED) +{ +#if CACHENUM > 0 +# ifdef CACHELRU +# if CACHENUM > 1 + memmove(&tdata->cache_id[1], &tdata->cache_id[0], + (CACHENUM - 1) * sizeof(tdata->cache_id[0])); + memmove(&tdata->cache_object[1], &tdata->cache_object[0], + (CACHENUM - 1) * sizeof(tdata->cache_object[0])); +# endif + tdata->cache_id[0] = obj_id; + tdata->cache_object[0] = obj; +# else + int slot = _eo_cache_slot_get(); + tdata->cache_id[slot] = obj_id; + tdata->cache_object[slot] = obj; +# endif +#endif +} + +static inline void +_eo_cache_invalidate(Eo_Id_Table_Data *tdata EINA_UNUSED, Eo_Id obj_id EINA_UNUSED) +{ +#if CACHENUM > 0 + int i; + + for (i = 0; i < CACHENUM; i++) + { + if (obj_id == tdata->cache_id[i]) + { +# ifdef CACHELRU + if (EINA_LIKELY((CACHENUM - 1 - i) > 0)) + { + memmove(&tdata->cache_id[i], &tdata->cache_id[i + 1], + (CACHENUM - 1 - i) * sizeof(tdata->cache_id[0])); + memmove(&tdata->cache_object[i], &tdata->cache_object[i + 1], + (CACHENUM - 1 - i) * sizeof(tdata->cache_object[0])); + } + tdata->cache_id[CACHENUM - 1] = 0; + tdata->cache_object[CACHENUM - 1] = NULL; +# else + tdata->cache_id[i] = 0; + tdata->cache_object[i] = NULL; +# endif + return; + } + } +#endif +} + static inline Eo_Id_Table_Data * _eo_table_data_table_new(Efl_Id_Domain domain) { @@ -672,11 +772,7 @@ _eo_id_release(const Eo_Id obj_id) tdata->current_table = NULL; } // In case an object is destroyed, wipe out the cache - if (tdata->cache.id == obj_id) - { - tdata->cache.id = 0; - tdata->cache.object = NULL; - } + _eo_cache_invalidate(tdata, obj_id); if ((Eo_Id)tdata->cache.isa_id == obj_id) { tdata->cache.isa_id = NULL; @@ -722,11 +818,7 @@ _eo_id_release(const Eo_Id obj_id) tdata->current_table = NULL; } // In case an object is destroyed, wipe out the cache - if (tdata->cache.id == obj_id) - { - tdata->cache.id = 0; - tdata->cache.object = NULL; - } + _eo_cache_invalidate(tdata, obj_id); if ((Eo_Id)tdata->cache.isa_id == obj_id) { tdata->cache.isa_id = NULL;