eo: make eo ptr indirection caches flexible

This commit is contained in:
Carsten Haitzler 2024-04-09 10:30:47 +01:00
parent 49976ca388
commit cdd3c35bb3
2 changed files with 119 additions and 26 deletions

View File

@ -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

View File

@ -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;