forked from enlightenment/efl
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.
This commit is contained in:
parent
0ff42fa4e5
commit
9b294d6284
|
@ -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...
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
#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;
|
||||
#else
|
||||
goto on_error;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_OPEN_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;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (fd < 0) goto on_error;
|
||||
|
||||
if (fstat(fd, &file_stat))
|
||||
goto on_error;
|
||||
|
||||
statgen = eina_file_statgen_get();
|
||||
eina_lock_take(&_eina_file_lock_cache);
|
||||
|
||||
file = eina_hash_find(_eina_file_cache, filename);
|
||||
if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
|
||||
statgen = eina_file_statgen_get();
|
||||
if ((!file) || (file->statgen != statgen) || (statgen == 0))
|
||||
{
|
||||
file->delete_me = EINA_TRUE;
|
||||
eina_hash_del(_eina_file_cache, file->filename, file);
|
||||
file = NULL;
|
||||
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;
|
||||
#else
|
||||
goto on_error;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef HAVE_OPEN_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;
|
||||
#endif
|
||||
}
|
||||
if (fd < 0) goto on_error;
|
||||
|
||||
if (fstat(fd, &file_stat))
|
||||
goto on_error;
|
||||
if (file) file->statgen = statgen;
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
Loading…
Reference in New Issue