raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=9b294d6284fbda62dde20bcb31732a1c63a65962

commit 9b294d6284fbda62dde20bcb31732a1c63a65962
Author: Carsten Haitzler (Rasterman) <[email protected]>
Date:   Sun Jul 28 11:51:15 2019 +0100

    eina file - stat generation inexactness support
    
    this is a performance optimization. it brings in a "stat generation".
    for now it's disabled by default so we retain previous behavior. this
    stops eina file from opening and stating a file every time you open
    ... it only does it if stat generation is off, or, if the generation
    changed since the last time it opened that file. this makes cache hits
    not have a 3 syscall cost (open+fstat+close). this optimizes that
    lower end of things path. but .. it comes at a cost. if the file
    changes before generation ticks over (which this forces to tick over
    every time the loop exits idle by default).
    
    now here is something to ask.
    
    1. should we have this on by default and accept the "inexactness"
    since you can eina_file_statgen_next() before any call that would do
    i/o to force it to look at the real file stat info...
    2. should we tick over every idle enter OR every N idle enters  or
    every frame we render instead? ... i want to avoid getting a timestamp
    or having a timer interrupt often... so what should we do?
    
    at least this introduces the idea, some api's and an env var to turn
    this on. it definitely cuts down syscalls during things like creation
    of widdgets or objects in large batches etc.
---
 src/lib/ecore/ecore_main.c      |  6 +++++
 src/lib/eina/eina_file.c        | 58 +++++++++++++++++++++++------------------
 src/lib/eina/eina_file.h        | 32 +++++++++++++++++++++++
 src/lib/eina/eina_file_common.c | 44 +++++++++++++++++++++++++++++++
 src/lib/eina/eina_file_common.h |  1 +
 5 files changed, 115 insertions(+), 26 deletions(-)

diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c
index f7d248fc27..e898b6e0f3 100644
--- a/src/lib/ecore/ecore_main.c
+++ b/src/lib/ecore/ecore_main.c
@@ -331,6 +331,7 @@ _ecore_main_uv_poll_cb(uv_poll_t *handle, int status, int 
events)
      {
         DBG("not IDLE anymore");
         _ecore_main_uv_idling = EINA_FALSE;
+        eina_file_statgen_next();
         efl_event_callback_call(obj, EFL_LOOP_EVENT_IDLE_EXIT, NULL);
         _ecore_animator_run_reset();
      }
@@ -794,6 +795,7 @@ _ecore_main_gsource_dispatch(GSource    *source EINA_UNUSED,
    if (ecore_idling && events_ready)
      {
         _ecore_animator_run_reset();
+        eina_file_statgen_next();
         efl_event_callback_call(obj, EFL_LOOP_EVENT_IDLE_EXIT, NULL);
         ecore_idling = 0;
      }
@@ -808,6 +810,7 @@ _ecore_main_gsource_dispatch(GSource    *source EINA_UNUSED,
         if (ecore_fds_ready || events_ready || timers_ready)
           {
              _ecore_animator_run_reset();
+             eina_file_statgen_next();
              efl_event_callback_call(obj, EFL_LOOP_EVENT_IDLE_EXIT, NULL);
              ecore_idling = 0;
           }
@@ -867,6 +870,7 @@ _ecore_main_loop_timer_run(uv_timer_t *timer EINA_UNUSED)
    if (_ecore_main_uv_idling)
      {
         _ecore_main_uv_idling = EINA_FALSE;
+        eina_file_statgen_next();
         efl_event_callback_call(obj, EFL_LOOP_EVENT_IDLE_EXIT, NULL);
         _ecore_animator_run_reset();
      }
@@ -2243,6 +2247,7 @@ _ecore_main_loop_uv_prepare(uv_prepare_t *handle 
EINA_UNUSED)
 
         if (_ecore_main_uv_idling)
           {
+             eina_file_statgen_next();
              efl_event_callback_call(obj, EFL_LOOP_EVENT_IDLE_EXIT, NULL);
              _ecore_animator_run_reset();
              _ecore_main_uv_idling = EINA_FALSE;
@@ -2473,6 +2478,7 @@ process_all: 
//-*********************************************************
    if (!once_only)
      {
         _ecore_animator_run_reset(); // XXX:
+        eina_file_statgen_next();
         efl_event_callback_call(obj, EFL_LOOP_EVENT_IDLE_EXIT, NULL);
      }
    // call the fd handler per fd that became alive...
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index 068aa12e14..e334beaf21 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -795,46 +795,51 @@ eina_file_open(const char *path, Eina_Bool shared)
    Eina_Stringshare *filename;
    struct stat file_stat;
    int fd = -1;
+   Eina_Statgen statgen;
 
    EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
 
    filename = eina_file_sanitize(path);
    if (!filename) return NULL;
 
-   if (shared)
+   statgen = eina_file_statgen_get();
+   eina_lock_take(&_eina_file_lock_cache);
+   file = eina_hash_find(_eina_file_cache, filename);
+   statgen = eina_file_statgen_get();
+   if ((!file) || (file->statgen != statgen) || (statgen == 0))
      {
+        if (shared)
+          {
 #ifdef HAVE_SHM_OPEN
-        fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
-        if ((fd != -1)  && (!eina_file_close_on_exec(fd, EINA_TRUE)))
-          goto on_error;
+             fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
+             if ((fd != -1)  && (!eina_file_close_on_exec(fd, EINA_TRUE)))
+               goto on_error;
 #else
-        goto on_error;
+             goto on_error;
 #endif
-     }
-   else
-     {
+          }
+        else
+          {
 #ifdef HAVE_OPEN_CLOEXEC
-        fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO | O_CLOEXEC);
+             fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO | 
O_CLOEXEC);
 #else
-        fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
-        if ((fd != -1)  && (!eina_file_close_on_exec(fd, EINA_TRUE)))
-          goto on_error;
+             fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
+             if ((fd != -1)  && (!eina_file_close_on_exec(fd, EINA_TRUE)))
+               goto on_error;
 #endif
-     }
-
-   if (fd < 0) goto on_error;
-
-   if (fstat(fd, &file_stat))
-     goto on_error;
+          }
+        if (fd < 0) goto on_error;
 
-   eina_lock_take(&_eina_file_lock_cache);
+        if (fstat(fd, &file_stat))
+          goto on_error;
+        if (file) file->statgen = statgen;
 
-   file = eina_hash_find(_eina_file_cache, filename);
-   if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
-     {
-        file->delete_me = EINA_TRUE;
-        eina_hash_del(_eina_file_cache, file->filename, file);
-        file = NULL;
+        if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
+          {
+             file->delete_me = EINA_TRUE;
+             eina_hash_del(_eina_file_cache, file->filename, file);
+             file = NULL;
+          }
      }
 
    if (!file)
@@ -874,7 +879,7 @@ eina_file_open(const char *path, Eina_Bool shared)
      }
    else
      {
-        close(fd);
+        if (fd >= 0) close(fd);
         n = file;
      }
    eina_lock_take(&n->lock);
@@ -886,6 +891,7 @@ eina_file_open(const char *path, Eina_Bool shared)
    return n;
 
  on_error:
+   eina_lock_release(&_eina_file_lock_cache);
    INF("Could not open file [%s].", filename);
    eina_stringshare_del(filename);
 
diff --git a/src/lib/eina/eina_file.h b/src/lib/eina/eina_file.h
index bc1543e26e..07a045e1b4 100644
--- a/src/lib/eina/eina_file.h
+++ b/src/lib/eina/eina_file.h
@@ -768,6 +768,38 @@ EAPI Eina_Bool eina_file_close_on_exec(int fd, Eina_Bool 
on);
 
 #include "eina_inline_file.x"
 
+/**
+ * @typedef Eina_Statgen
+ * @brief Stat Generation count state with it being 0 when disabled or some 
other value that is comparable (== or !=) to a stored value and if it is not 
equal, then do the actual stat i/o work
+ * @since 1.23
+ */
+typedef unsigned int Eina_Statgen;
+
+/**
+ * @brief Force the stat generation counter to tick over so any following i/o 
does real i/o and stat calls
+ * @since 1.23
+ */
+EAPI void         eina_file_statgen_next(void);
+
+/**
+ * @brief Get the current stat generation counter value
+ * @return 0 if you should always do stat calls and compare, or some other 
value that changes like a generation counter
+ * @since 1.23
+ */
+EAPI Eina_Statgen eina_file_statgen_get(void);
+
+/**
+ * @brief Enable stat generation count optimiziing to only stat/do file i/o 
between generation counts changing
+ * @since 1.23
+ */
+EAPI void         eina_file_statgen_enable(void);
+
+/**
+ * @brief Disable stat generation count optimiziing to only stat/do file i/o 
between generation counts changing
+ * @since 1.23
+ */
+EAPI void         eina_file_statgen_bisable(void);
+
 /**
  * @}
  */
diff --git a/src/lib/eina/eina_file_common.c b/src/lib/eina/eina_file_common.c
index b62fc22b80..9369cb2cc5 100644
--- a/src/lib/eina/eina_file_common.c
+++ b/src/lib/eina/eina_file_common.c
@@ -74,6 +74,47 @@ Eina_Lock _eina_file_lock_cache;
 # define EINA_FILE_MAGIC_CHECK(f, ...) do {} while(0)
 #endif
 
+static Eina_Spinlock _eina_statgen_lock;
+static Eina_Statgen _eina_statgen = 0;
+
+EAPI void
+eina_file_statgen_next(void)
+{
+   eina_spinlock_take(&_eina_statgen_lock);
+   if (_eina_statgen != 0)
+     {
+        _eina_statgen++;
+        if (_eina_statgen == 0) _eina_statgen = 1;
+     }
+   eina_spinlock_release(&_eina_statgen_lock);
+}
+
+EAPI Eina_Statgen
+eina_file_statgen_get(void)
+{
+   Eina_Statgen s;
+   eina_spinlock_take(&_eina_statgen_lock);
+   s = _eina_statgen;
+   eina_spinlock_release(&_eina_statgen_lock);
+   return s;
+}
+
+EAPI void
+eina_file_statgen_enable(void)
+{
+   eina_spinlock_take(&_eina_statgen_lock);
+   if (_eina_statgen != 0) _eina_statgen = 1;
+   eina_spinlock_release(&_eina_statgen_lock);
+}
+
+EAPI void
+eina_file_statgen_bisable(void)
+{
+   eina_spinlock_take(&_eina_statgen_lock);
+   _eina_statgen = 0;
+   eina_spinlock_release(&_eina_statgen_lock);
+}
+
 static char *
 _eina_file_escape(char *path, size_t len)
 {
@@ -1072,6 +1113,8 @@ eina_file_init(void)
         return EINA_FALSE;
      }
 
+   if (getenv("EINA_STATGEN")) _eina_statgen = 1;
+   eina_spinlock_new(&_eina_statgen_lock);
    eina_lock_recursive_new(&_eina_file_lock_cache);
    eina_magic_string_set(EINA_FILE_MAGIC, "Eina_File");
 
@@ -1102,6 +1145,7 @@ eina_file_shutdown(void)
 
    eina_log_domain_unregister(_eina_file_log_dom);
    _eina_file_log_dom = -1;
+   eina_spinlock_free(&_eina_statgen_lock);
    return EINA_TRUE;
 }
 
diff --git a/src/lib/eina/eina_file_common.h b/src/lib/eina/eina_file_common.h
index 142ee2d852..38c1a3c4ee 100644
--- a/src/lib/eina/eina_file_common.h
+++ b/src/lib/eina/eina_file_common.h
@@ -89,6 +89,7 @@ struct _Eina_File
 
    int refcount;        /**< Keeps track of references to #map. */
    int global_refcount; /**< Keeps track of references to #global_map. */
+   Eina_Statgen statgen;/**< For inexact stats a stat gen count to rate limit 
syscalls to stat file */
 
 #ifndef _WIN32
    int fd; /**< The file descriptor. */

-- 


Reply via email to