raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=34d9f2070696027199a56cb621c0526ea1430e8f

commit 34d9f2070696027199a56cb621c0526ea1430e8f
Author: Jean Guyomarc'h <j...@guyomarch.bzh>
Date:   Tue Jan 16 14:58:38 2018 +0900

    eina: remove usless newline
    
    Summary:
    ecore_evas: remove debug
    
    eina: unregister log level when done with
    
    Fixes a constant memory leak.
    
    eina: introduce EINA_HOT and EINA_COLD
    
    These attributes respectivelly expand to __attribute__ ((hot)) and
    __attribute__ ((cold)) when available. They allow to mark functions are
    being hot/cold (frequently used or not) as well as to qualify labels
    within a function (likely/unlikely branches).
    
    eo: speed-up generated calls by removing call cache
    
    The call cache needed to by thread-local, to avoid concurrency issues.
    Problem with TLS is that is adds an extra overhead, which appears to be
    greater than the optimization the cache provides.
    
    Op is naturally atomic, because it is an unsigned integer. As such, it
    cannot be tempered with while another thread is reading it. When
    entering the generated function, the first operation done is reading
    'op'. If we have concurrency, we will have access sequences returning
    either EFL_NOOP or a VALID op, because 'op' is not set until the very
    end of the function, when everything has been computed. As such, we now
    use the 'op' atomic integer to instore a lock-free/wait-free mechanism,
    which allows to drop the TLS nature of the cache, speeding up the access
    to the cache, and therefore making functions execute faster.
    
    We don't test anymore the generation count. This can be put as a
    limitation. If means that if you call efl_object_shutdown() and
    re-initialize it later with different data, opcodes will be invalid.
    I am not sure there is any usecase for this to ever happen.
    We could move all the caches in a dedicated section, that can be
    overwritten after a call to efl_object_shutdown(), but I am not sure it
    will be very portable.
    
    Benchmark: mean over 3 executions of
       ELM_TEST_AUTOBOUNCE=100 time elementary_test -to genlist
    
    ```
                         BEFORE               AFTER
    ------------------------------------------------------------
    time (ns)            11114111647.0        9147676220.0
    frames               2872.3333333333335   2904.6666666666665
    time per frame (ns)  3869364.6666666665   3149535.3333333335
    user time (s)        11.096666666666666   9.22
    cpu (%)              22.666666666666668   18.333333333333332
    ```
    
    Ref T6580
    
    Reviewers: raster, cedric
    
    Subscribers: cedric, jpeg
    
    Maniphest Tasks: T6580
    
    Differential Revision: https://phab.enlightenment.org/D5738
---
 src/lib/ecore_evas/ecore_evas_private.h |  2 +-
 src/lib/eina/eina_cow.c                 |  1 +
 src/lib/eina/eina_safepointer.c         |  2 +-
 src/lib/eina/eina_types.h               |  8 +++++
 src/lib/eo/Eo.h                         | 56 +++++++----------------------
 src/lib/eo/eo.c                         | 64 ++++++---------------------------
 6 files changed, 33 insertions(+), 100 deletions(-)

diff --git a/src/lib/ecore_evas/ecore_evas_private.h 
b/src/lib/ecore_evas/ecore_evas_private.h
index 7b83589347..13002402a4 100644
--- a/src/lib/ecore_evas/ecore_evas_private.h
+++ b/src/lib/ecore_evas/ecore_evas_private.h
@@ -347,7 +347,7 @@ struct _Ecore_Evas
    } delayed;
 
    int refcount;
-#define ECORE_EVAS_ASYNC_RENDER_DEBUG 1 /* TODO: remove me */
+//#define ECORE_EVAS_ASYNC_RENDER_DEBUG 1 /* TODO: remove me */
 #ifdef ECORE_EVAS_ASYNC_RENDER_DEBUG
    double async_render_start;
 #endif
diff --git a/src/lib/eina/eina_cow.c b/src/lib/eina/eina_cow.c
index 73a65e5f30..8ec86cfd79 100644
--- a/src/lib/eina/eina_cow.c
+++ b/src/lib/eina/eina_cow.c
@@ -320,6 +320,7 @@ eina_cow_init(void)
 Eina_Bool
 eina_cow_shutdown(void)
 {
+   eina_log_domain_unregister(_eina_cow_log_dom);
    eina_mempool_del(gc_pool);
    return EINA_TRUE;
 }
diff --git a/src/lib/eina/eina_safepointer.c b/src/lib/eina/eina_safepointer.c
index 1a19f851c7..8f9d4b62a9 100644
--- a/src/lib/eina/eina_safepointer.c
+++ b/src/lib/eina/eina_safepointer.c
@@ -370,7 +370,7 @@ eina_safepointer_init(void)
 
    DBG("entry[Size, Align] = { %zu, %u }",
        sizeof (Eina_Memory_Entry), eina_mempool_alignof(sizeof 
(Eina_Memory_Entry)));
-   DBG("table[Size, Align] = { %zu, %u }\n",
+   DBG("table[Size, Align] = { %zu, %u }",
        sizeof (Eina_Memory_Table), eina_mempool_alignof(sizeof 
(Eina_Memory_Table)));
 
    return EINA_TRUE;
diff --git a/src/lib/eina/eina_types.h b/src/lib/eina/eina_types.h
index 94e6ebc6f3..3d15a3f42d 100644
--- a/src/lib/eina/eina_types.h
+++ b/src/lib/eina/eina_types.h
@@ -184,6 +184,14 @@
 #  define EINA_PURE
 # endif
 
+# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
+#  define EINA_HOT __attribute__ ((hot))
+#  define EINA_COLD __attribute__ ((cold))
+# else
+#  define EINA_HOT
+#  define EINA_COLD
+# endif
+
 # if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
 #  if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 3)
 #   define EINA_PRINTF(fmt, arg) __attribute__((__format__ (__gnu_printf__, 
fmt, arg)))
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 3ea20ec2ff..8b489ab72a 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -1159,37 +1159,6 @@ typedef struct _Efl_Object_Op_Call_Data
    void         *extn4; // for future use to avoid ABI issues
 } Efl_Object_Op_Call_Data;
 
-#define EFL_OBJECT_CALL_CACHE_SIZE 1
-
-typedef struct _Efl_Object_Call_Cache_Index
-{
-   const void       *klass;
-} Efl_Object_Call_Cache_Index;
-
-typedef struct _Efl_Object_Call_Cache_Entry
-{
-   const void       *func;
-} Efl_Object_Call_Cache_Entry;
-
-typedef struct _Efl_Object_Call_Cache_Off
-{
-   int               off;
-} Efl_Object_Call_Cache_Off;
-
-typedef struct _Efl_Object_Call_Cache
-{
-#if EFL_OBJECT_CALL_CACHE_SIZE > 0
-   Efl_Object_Call_Cache_Index index[EFL_OBJECT_CALL_CACHE_SIZE];
-   Efl_Object_Call_Cache_Entry entry[EFL_OBJECT_CALL_CACHE_SIZE];
-   Efl_Object_Call_Cache_Off   off  [EFL_OBJECT_CALL_CACHE_SIZE];
-# if EFL_OBJECT_CALL_CACHE_SIZE > 1
-   int                 next_slot;
-# endif
-#endif
-   Efl_Object_Op               op;
-   unsigned int        generation;
-} Efl_Object_Call_Cache;
-
 // to pass the internal function call to EFL_FUNC_BODY (as Func parameter)
 #define EFL_FUNC_CALL(...) __VA_ARGS__
 
@@ -1205,17 +1174,18 @@ typedef struct _Efl_Object_Call_Cache
 # define EFL_FUNC_TLS __thread
 #endif
 
+
 // cache OP id, get real fct and object data then do the call
 #define EFL_FUNC_COMMON_OP(Obj, Name, DefRet) \
-   static EFL_FUNC_TLS Efl_Object_Call_Cache ___cache; /* static 0 by default 
*/ \
+   static Efl_Object_Op ___op; /* static 0 by default */ \
    Efl_Object_Op_Call_Data ___call; \
    _Eo_##Name##_func _func_;                                            \
-   if (EINA_UNLIKELY((___cache.op == EFL_NOOP) ||                       \
-                     (___cache.generation != _efl_object_init_generation))) \
+   if (EINA_UNLIKELY(___op == EFL_NOOP)) \
      goto __##Name##_op_create; /* yes a goto - see below */ \
-   __##Name##_op_create_done: \
-   if (!_efl_object_call_resolve((Eo *) Obj, #Name, &___call, &___cache, \
-                                 __FILE__, __LINE__)) goto __##Name##_failed; \
+   __##Name##_op_create_done: EINA_HOT; \
+   if (EINA_UNLIKELY(!_efl_object_call_resolve( \
+      (Eo *) Obj, #Name, &___call, ___op, __FILE__, __LINE__))) \
+      goto __##Name##_failed; \
    _func_ = (_Eo_##Name##_func) ___call.func;
 
 // This looks ugly with gotos BUT it moves rare "init" handling code
@@ -1227,13 +1197,11 @@ typedef struct _Efl_Object_Call_Cache
 // of the cacheline that was already fetched should yield better cache
 // hits.
 #define EFL_FUNC_COMMON_OP_END(Obj, Name, DefRet, ErrorCase) \
-__##Name##_op_create: \
-   if (EINA_UNLIKELY(___cache.op != EFL_NOOP)) memset(&___cache, 0, 
sizeof(___cache)); \
-   ___cache.op = _efl_object_op_api_id_get(EFL_FUNC_COMMON_OP_FUNC(Name), Obj, 
#Name, __FILE__, __LINE__); \
-   if (___cache.op == EFL_NOOP) goto __##Name##_failed; \
-   ___cache.generation = _efl_object_init_generation; \
+__##Name##_op_create: EINA_COLD; \
+   ___op = _efl_object_op_api_id_get(EFL_FUNC_COMMON_OP_FUNC(Name), Obj, 
#Name, __FILE__, __LINE__); \
+   if (EINA_UNLIKELY(___op == EFL_NOOP)) goto __##Name##_failed; \
    goto __##Name##_op_create_done; \
-__##Name##_failed: \
+__##Name##_failed: EINA_COLD; \
    ErrorCase \
    return DefRet;
 #define _EFL_OBJECT_API_BEFORE_HOOK
@@ -1335,7 +1303,7 @@ EAPI Efl_Object_Op _efl_object_api_op_id_get(const void 
*api_func) EINA_DEPRECAT
 EAPI Efl_Object_Op _efl_object_op_api_id_get(const void *api_func, const Eo 
*obj, const char *api_func_name, const char *file, int line) 
EINA_ARG_NONNULL(1, 2, 3, 4) EINA_WARN_UNUSED_RESULT;
 
 // gets the real function pointer and the object data
-EAPI Eina_Bool _efl_object_call_resolve(Eo *obj, const char *func_name, 
Efl_Object_Op_Call_Data *call, Efl_Object_Call_Cache *callcache, const char 
*file, int line);
+EAPI Eina_Bool _efl_object_call_resolve(Eo *obj, const char *func_name, 
Efl_Object_Op_Call_Data *call, Efl_Object_Op op, const char *file, int line);
 
 // end of the eo call barrier, unref the obj
 EAPI void _efl_object_call_end(Efl_Object_Op_Call_Data *call);
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 50df250acf..0db34fc35c 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -439,15 +439,14 @@ efl_cast(const Eo *eo_id, const Efl_Class *cur_klass)
 }
 
 EAPI Eina_Bool
-_efl_object_call_resolve(Eo *eo_id, const char *func_name, 
Efl_Object_Op_Call_Data *call, Efl_Object_Call_Cache *cache, const char *file, 
int line)
+_efl_object_call_resolve(Eo *eo_id, const char *func_name, 
Efl_Object_Op_Call_Data *call, Efl_Object_Op op, const char *file, int line)
 {
-   const _Efl_Class *klass, *inputklass, *main_klass;
+   const _Efl_Class *klass, *main_klass;
    const _Efl_Class *cur_klass = NULL;
    _Eo_Object *obj = NULL;
    const Eo_Vtable *vtable = NULL;
    const op_type_funcs *func;
    Eina_Bool is_obj;
-   Eina_Bool is_override = EINA_FALSE;
    Eina_Bool super = EINA_TRUE;
 
    if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE;
@@ -456,14 +455,13 @@ _efl_object_call_resolve(Eo *eo_id, const char 
*func_name, Efl_Object_Op_Call_Da
 
    is_obj = _eo_is_a_obj(eo_id);
 
-   if (is_obj)
+   if (EINA_LIKELY(is_obj == EINA_TRUE))
      {
         EO_OBJ_POINTER_RETURN_VAL_PROXY(eo_id, _obj, EINA_FALSE);
 
         obj = _obj;
         klass = _obj->klass;
         vtable = EO_VTABLE(obj);
-        is_override = _obj_is_override(obj);
         if (EINA_UNLIKELY(_obj->cur_klass != NULL))
           {
              // YES this is a goto with a label to return. this is a
@@ -485,9 +483,7 @@ obj_super_back:
      }
 ok_klass_back:
 
-   inputklass = main_klass =  klass;
-
-   if (!cache->op) goto err_cache_op;
+   main_klass =  klass;
 
    /* If we have a current class, we need to itr to the next. */
    if (cur_klass)
@@ -499,30 +495,7 @@ ok_klass_back:
      }
    else
      {
-# if EFL_OBJECT_CALL_CACHE_SIZE > 0
-        if (!is_override)
-          {
-# if EFL_OBJECT_CALL_CACHE_SIZE > 1
-             int i;
-
-             for (i = 0; i < EFL_OBJECT_CALL_CACHE_SIZE; i++)
-# else
-                const int i = 0;
-# endif
-               {
-                  if ((const void *)inputklass == cache->index[i].klass)
-                    {
-                       func = (const op_type_funcs *)cache->entry[i].func;
-                       call->func = func->func;
-                       if (is_obj)
-                         call->data = (char *)obj + cache->off[i].off;
-                       if (EINA_UNLIKELY(!call->func)) goto err_cache_op;
-                       return EINA_TRUE;
-                    }
-               }
-          }
-#endif
-        func = _vtable_func_get(vtable, cache->op);
+        func = _vtable_func_get(vtable, op);
         // this is not very likely to happen - but may if its an invalid
         // call or a composite object, but either way, it's not very likely
         // so make it a goto to save on instruction cache
@@ -536,22 +509,6 @@ ok_cur_klass_back:
 
         if (is_obj) call->data = _efl_data_scope_get(obj, func->src);
 
-# if EFL_OBJECT_CALL_CACHE_SIZE > 0
-        if (!cur_klass && !is_override)
-          {
-# if EFL_OBJECT_CALL_CACHE_SIZE > 1
-             const int slot = cache->next_slot;
-# else
-             const int slot = 0;
-# endif
-             cache->index[slot].klass = (const void *)inputklass;
-             cache->entry[slot].func = (const void *)func;
-             cache->off[slot].off = (int)((long)((char *)call->data - (char 
*)obj));
-# if EFL_OBJECT_CALL_CACHE_SIZE > 1
-             cache->next_slot = (slot + 1) % EFL_OBJECT_CALL_CACHE_SIZE;
-# endif
-          }
-#endif
         return EINA_TRUE;
      }
 
@@ -570,7 +527,7 @@ end:
              EO_OBJ_POINTER_PROXY(emb_obj_id, emb_obj);
              if (EINA_UNLIKELY(!emb_obj)) continue;
 
-             func = _vtable_func_get(EO_VTABLE(emb_obj), cache->op);
+             func = _vtable_func_get(EO_VTABLE(emb_obj), op);
              if (func == NULL) goto composite_continue;
 
              if (EINA_LIKELY(func->func && func->src))
@@ -594,7 +551,7 @@ composite_continue:
    if (cur_klass)
      {
         ERR("in %s:%d: func '%s' (%d) could not be resolved for class '%s' for 
super of '%s'.",
-            file, line, func_name, cache->op, main_klass->desc->name,
+            file, line, func_name, op, main_klass->desc->name,
             cur_klass->desc->name);
         goto err;
      }
@@ -602,7 +559,7 @@ composite_continue:
      {
         /* we should not be able to take this branch */
         ERR("in %s:%d: func '%s' (%d) could not be resolved for class '%s'.",
-            file, line, func_name, cache->op, main_klass->desc->name);
+            file, line, func_name, op, main_klass->desc->name);
         goto err;
      }
 err_cache_op:
@@ -612,7 +569,7 @@ err_cache_op:
    goto err;
 err_func_src:
    ERR("in %s:%d: you called a pure virtual func '%s' (%d) of class '%s'.",
-       file, line, func_name, cache->op, klass->desc->name);
+       file, line, func_name, op, klass->desc->name);
 err:
    if (is_obj)
      {
@@ -629,7 +586,7 @@ err:
    // yes - special "move out of hot path" code blobs with goto's for
    // speed reasons to have intr prefetches work better and miss less
 ok_cur_klass:
-   func = _eo_kls_itr_next(klass, cur_klass, cache->op, super);
+   func = _eo_kls_itr_next(klass, cur_klass, op, super);
    if (!func) goto end;
    klass = func->src;
    goto ok_cur_klass_back;
@@ -661,7 +618,6 @@ obj_super:
            cur_klass = NULL;
         }
 
-      is_override = _obj_is_override(obj) && (cur_klass == NULL);
    }
    goto obj_super_back;
 

-- 


Reply via email to