eo: 30% speed improvement in message propagation.

This commit is contained in:
Cedric Bail 2013-06-27 17:58:49 +09:00
parent 383592b444
commit 7849c5de32
4 changed files with 218 additions and 221 deletions

View File

@ -16,15 +16,6 @@
EAPI Eina_Lock _eo_class_creation_lock;
int _eo_log_dom = -1;
/**
* @typedef Eo_Class_Id
* An Id of a class.
* @ingroup Eo_Class
*/
typedef uintptr_t Eo_Class_Id;
typedef struct _Eo_Class _Eo_Class;
static _Eo_Class **_eo_classes;
static Eo_Class_Id _eo_classes_last_id;
static Eina_Bool _eo_init_count = 0;
@ -37,38 +28,9 @@ static void _eo_condtor_reset(_Eo *obj);
static inline void *_eo_data_scope_get(const _Eo *obj, const _Eo_Class *klass);
static inline void *_eo_data_xref_internal(const char *file, int line, _Eo *obj, const _Eo_Class *klass, const _Eo *ref_obj);
static inline void _eo_data_xunref_internal(_Eo *obj, void *data, const _Eo *ref_obj);
static inline _Eo *_eo_ref(_Eo *obj);
static inline void _eo_unref(_Eo *obj);
static const _Eo_Class *_eo_op_class_get(Eo_Op op);
static const Eo_Op_Description *_eo_op_id_desc_get(Eo_Op op);
struct _Eo_Internal {
#ifndef HAVE_EO_ID
EINA_MAGIC
#endif
Eo *parent;
Eina_List *children;
const _Eo_Class *klass;
#ifdef EO_DEBUG
Eina_Inlist *xrefs;
Eina_Inlist *data_xrefs;
#endif
Eina_List *composite_objects;
Eo_Id obj_id;
int refcount;
int datarefcount;
Eina_Bool do_error:1;
Eina_Bool condtor_done:1;
Eina_Bool composite:1;
Eina_Bool del:1;
Eina_Bool manual_free:1;
};
/* Start of Dich */
/* How we search and store the implementations in classes. */
@ -86,50 +48,6 @@ struct _Eo_Internal {
#define EO_ALIGN_SIZE(size) eina_mempool_alignof(size)
typedef struct _Dich_Chain1 Dich_Chain1;
typedef struct
{
eo_op_func_type func;
const _Eo_Class *src;
} op_type_funcs;
struct _Dich_Chain1
{
op_type_funcs *funcs;
};
typedef struct
{
const _Eo_Class *klass;
size_t offset;
} Eo_Extension_Data_Offset;
struct _Eo_Class
{
EINA_MAGIC
Eo_Class_Id class_id;
const _Eo_Class *parent;
const Eo_Class_Description *desc;
Dich_Chain1 *chain; /**< The size is chain size */
const _Eo_Class **extensions;
Eo_Extension_Data_Offset *extn_data_off;
const _Eo_Class **mro;
unsigned int obj_size; /**< size of an object of this class */
unsigned int chain_size;
unsigned int base_id;
unsigned int data_offset; /* < Offset of the data within object data. */
Eina_Bool constructed : 1;
/* [extensions*] + NULL */
/* [mro*] + NULL */
/* [extensions data offset] + NULL */
};
static inline void
_dich_chain_alloc(Dich_Chain1 *chain1)
{
@ -1275,13 +1193,6 @@ eo_xunref(Eo *obj_id, const Eo *ref_obj_id)
_eo_unref(obj);
}
static inline _Eo *
_eo_ref(_Eo *obj)
{
obj->refcount++;
return obj;
}
EAPI Eo *
eo_ref(const Eo *obj_id)
{
@ -1291,110 +1202,6 @@ eo_ref(const Eo *obj_id)
return (Eo *)obj_id;
}
static inline void
_eo_del_internal(const char *file, int line, _Eo *obj)
{
Eina_Bool do_err;
/* We need that for the event callbacks that may ref/unref. */
obj->refcount++;
eo_do((Eo *) obj->obj_id, eo_event_callback_call(EO_EV_DEL, NULL, NULL));
const _Eo_Class *klass = obj->klass;
_eo_condtor_reset(obj);
do_err = eo_do((Eo *)obj->obj_id, eo_destructor());
if (EINA_UNLIKELY(!do_err))
{
ERR("in %s:%d: Object of class '%s' - One of the object destructors have failed.",
file, line, klass->desc->name);
}
if (!obj->condtor_done)
{
ERR("in %s:%d: Object of class '%s' - Not all of the object destructors have been executed.",
file, line, klass->desc->name);
}
/*FIXME: add eo_class_unref(klass) ? - just to clear the caches. */
{
Eina_List *itr, *itr_n;
Eo *emb_obj;
EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
{
eo_composite_detach(emb_obj, (Eo *)obj->obj_id);
}
}
while (obj->children)
{
eo_parent_set(eina_list_data_get(obj->children), NULL); // ZZZ
}
obj->del = EINA_TRUE;
obj->refcount--;
}
static inline void
_eo_free(_Eo *obj)
{
#ifdef EO_DEBUG
if (obj->datarefcount)
{
ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount);
}
#endif
_eo_id_release(obj->obj_id);
free(obj);
}
static inline void
_eo_unref(_Eo *obj)
{
--(obj->refcount);
if (obj->refcount == 0)
{
if (obj->del)
{
ERR("Object %p already deleted.", obj);
return;
}
_eo_del_internal(__FILE__, __LINE__, obj);
#ifdef EO_DEBUG
/* If for some reason it's not empty, clear it. */
while (obj->xrefs)
{
ERR("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
Eina_Inlist *nitr = obj->xrefs->next;
free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node));
obj->xrefs = nitr;
}
while (obj->data_xrefs)
{
Eina_Inlist *nitr = obj->data_xrefs->next;
Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
ERR("Data of object 0x%lx is still referenced by object %p", (unsigned long)obj->obj_id, xref->ref_obj);
free(xref);
obj->data_xrefs = nitr;
}
#endif
if (!obj->manual_free)
_eo_free(obj);
else
_eo_ref(obj); /* If we manual free, we keep a phantom ref. */
}
else if (obj->refcount < 0)
{
ERR("Obj:%p. Refcount (%d) < 0. Too many unrefs.", obj, obj->refcount);
return;
}
}
EAPI void
eo_unref(const Eo *obj_id)
{
@ -1449,12 +1256,6 @@ _eo_condtor_done(Eo *obj_id)
obj->condtor_done = EINA_TRUE;
}
static void
_eo_condtor_reset(_Eo *obj)
{
obj->condtor_done = EINA_FALSE;
}
static inline void *
_eo_data_scope_get(const _Eo *obj, const _Eo_Class *klass)
{

View File

@ -5,6 +5,7 @@
#include <Eina.h>
#include "Eo.h"
#include "eo_ptr_indirection.h"
#include "eo_private.h"
EAPI Eo_Op EO_BASE_BASE_ID = 0;
@ -446,17 +447,17 @@ _ev_cb_array_del(Eo *obj, void *class_data, va_list *list)
}
static void
_ev_cb_call(Eo *obj, void *class_data, va_list *list)
_ev_cb_call(Eo *obj_id, void *class_data, va_list *list)
{
Private_Data *pd = (Private_Data *) class_data;
const Eo_Event_Description *desc = va_arg(*list, const Eo_Event_Description *);
void *event_info = va_arg(*list, void *);
Eina_Bool *ret = va_arg(*list, Eina_Bool *);
EO_OBJ_POINTER_RETURN(obj_id, obj);
if (ret) *ret = EINA_TRUE;
/* FIXME: Change eo_ref to _eo_ref and unref. */
eo_ref(obj);
_eo_ref(obj);
pd->walking_list++;
Eo_Callback_Description *cb;
@ -476,7 +477,7 @@ _ev_cb_call(Eo *obj, void *class_data, va_list *list)
continue;
/* Abort callback calling if the func says so. */
if (!it->func((void *) cb->func_data, obj, desc,
if (!it->func((void *) cb->func_data, obj_id, desc,
(void *) event_info))
{
if (ret) *ret = EINA_FALSE;
@ -494,7 +495,7 @@ _ev_cb_call(Eo *obj, void *class_data, va_list *list)
if (cb->items.item.desc == desc)
{
/* Abort callback calling if the func says so. */
if (!cb->items.item.func((void *) cb->func_data, obj, desc,
if (!cb->items.item.func((void *) cb->func_data, obj_id, desc,
(void *) event_info))
{
if (ret) *ret = EINA_FALSE;
@ -508,7 +509,7 @@ _ev_cb_call(Eo *obj, void *class_data, va_list *list)
end:
pd->walking_list--;
_eo_callbacks_clear(pd);
eo_unref(obj);
_eo_unref(obj);
}
static Eina_Bool

View File

@ -54,8 +54,217 @@ extern int _eo_log_dom;
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_eo_log_dom, __VA_ARGS__)
void _eo_condtor_done(Eo *obj);
typedef size_t Eo_Id;
typedef struct _Eo_Class _Eo_Class;
typedef struct _Eo_Internal _Eo;
/* Retrieves the pointer to the object from the id */
_Eo *_eo_obj_pointer_get(const Eo_Id obj_id);
/* Allocates an entry for the given object */
Eo_Id _eo_id_allocate(const _Eo *obj);
/* Releases an entry by the object id */
void _eo_id_release(const Eo_Id obj_id);
/* Free all the entries and the tables */
void _eo_free_ids_tables();
void _eo_condtor_done(Eo *obj);
struct _Eo_Internal {
#ifndef HAVE_EO_ID
EINA_MAGIC
#endif
Eo *parent;
Eina_List *children;
const _Eo_Class *klass;
#ifdef EO_DEBUG
Eina_Inlist *xrefs;
Eina_Inlist *data_xrefs;
#endif
Eina_List *composite_objects;
Eo_Id obj_id;
int refcount;
int datarefcount;
Eina_Bool do_error:1;
Eina_Bool condtor_done:1;
Eina_Bool composite:1;
Eina_Bool del:1;
Eina_Bool manual_free:1;
};
/**
* @typedef Eo_Class_Id
* An Id of a class.
* @ingroup Eo_Class
*/
typedef uintptr_t Eo_Class_Id;
typedef struct _Dich_Chain1 Dich_Chain1;
typedef struct
{
eo_op_func_type func;
const _Eo_Class *src;
} op_type_funcs;
struct _Dich_Chain1
{
op_type_funcs *funcs;
};
typedef struct
{
const _Eo_Class *klass;
size_t offset;
} Eo_Extension_Data_Offset;
struct _Eo_Class
{
EINA_MAGIC
Eo_Class_Id class_id;
const _Eo_Class *parent;
const Eo_Class_Description *desc;
Dich_Chain1 *chain; /**< The size is chain size */
const _Eo_Class **extensions;
Eo_Extension_Data_Offset *extn_data_off;
const _Eo_Class **mro;
unsigned int obj_size; /**< size of an object of this class */
unsigned int chain_size;
unsigned int base_id;
unsigned int data_offset; /* < Offset of the data within object data. */
Eina_Bool constructed : 1;
/* [extensions*] + NULL */
/* [mro*] + NULL */
/* [extensions data offset] + NULL */
};
static inline void
_eo_condtor_reset(_Eo *obj)
{
obj->condtor_done = EINA_FALSE;
}
static inline void
_eo_del_internal(const char *file, int line, _Eo *obj)
{
Eina_Bool do_err;
/* We need that for the event callbacks that may ref/unref. */
obj->refcount++;
eo_do((Eo *) obj->obj_id, eo_event_callback_call(EO_EV_DEL, NULL, NULL));
const _Eo_Class *klass = obj->klass;
_eo_condtor_reset(obj);
do_err = eo_do((Eo *)obj->obj_id, eo_destructor());
if (EINA_UNLIKELY(!do_err))
{
ERR("in %s:%d: Object of class '%s' - One of the object destructors have failed.",
file, line, klass->desc->name);
}
if (!obj->condtor_done)
{
ERR("in %s:%d: Object of class '%s' - Not all of the object destructors have been executed.",
file, line, klass->desc->name);
}
/*FIXME: add eo_class_unref(klass) ? - just to clear the caches. */
{
Eina_List *itr, *itr_n;
Eo *emb_obj;
EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
{
eo_composite_detach(emb_obj, (Eo *)obj->obj_id);
}
}
while (obj->children)
{
eo_parent_set(eina_list_data_get(obj->children), NULL); // ZZZ
}
obj->del = EINA_TRUE;
obj->refcount--;
}
static inline void
_eo_free(_Eo *obj)
{
#ifdef EO_DEBUG
if (obj->datarefcount)
{
ERR("Object %p data still referenced %d time(s).", obj, obj->datarefcount);
}
#endif
_eo_id_release(obj->obj_id);
free(obj);
}
static inline _Eo *
_eo_ref(_Eo *obj)
{
obj->refcount++;
return obj;
}
static inline void
_eo_unref(_Eo *obj)
{
--(obj->refcount);
if (obj->refcount == 0)
{
if (obj->del)
{
ERR("Object %p already deleted.", obj);
return;
}
_eo_del_internal(__FILE__, __LINE__, obj);
#ifdef EO_DEBUG
/* If for some reason it's not empty, clear it. */
while (obj->xrefs)
{
ERR("obj->xrefs is not empty, possibly a bug, please report. - An error will be reported for each xref in the stack.");
Eina_Inlist *nitr = obj->xrefs->next;
free(EINA_INLIST_CONTAINER_GET(obj->xrefs, Eo_Xref_Node));
obj->xrefs = nitr;
}
while (obj->data_xrefs)
{
Eina_Inlist *nitr = obj->data_xrefs->next;
Eo_Xref_Node *xref = EINA_INLIST_CONTAINER_GET(obj->data_xrefs, Eo_Xref_Node);
ERR("Data of object 0x%lx is still referenced by object %p", (unsigned long)obj->obj_id, xref->ref_obj);
free(xref);
obj->data_xrefs = nitr;
}
#endif
if (!obj->manual_free)
_eo_free(obj);
else
_eo_ref(obj); /* If we manual free, we keep a phantom ref. */
}
else if (obj->refcount < 0)
{
ERR("Obj:%p. Refcount (%d) < 0. Too many unrefs.", obj, obj->refcount);
return;
}
}
#endif

View File

@ -4,20 +4,6 @@
#include "Eo.h"
#include "eo_private.h"
typedef size_t Eo_Id;
/* Retrieves the pointer to the object from the id */
_Eo *_eo_obj_pointer_get(const Eo_Id obj_id);
/* Allocates an entry for the given object */
Eo_Id _eo_id_allocate(const _Eo *obj);
/* Releases an entry by the object id */
void _eo_id_release(const Eo_Id obj_id);
/* Free all the entries and the tables */
void _eo_free_ids_tables();
/* Macro used to obtain the object pointer and return if fails. */
#ifdef HAVE_EO_ID