summaryrefslogtreecommitdiff
path: root/src/lib/eina
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2019-07-28 11:51:15 +0100
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2019-07-28 11:51:15 +0100
commit9b294d6284fbda62dde20bcb31732a1c63a65962 (patch)
tree0ca334db76e922ae119ad554464bb9200f256694 /src/lib/eina
parent0ff42fa4e51d5aa94b6d60e300a77876b82fe952 (diff)
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.
Diffstat (limited to 'src/lib/eina')
-rw-r--r--src/lib/eina/eina_file.c58
-rw-r--r--src/lib/eina/eina_file.h32
-rw-r--r--src/lib/eina/eina_file_common.c44
-rw-r--r--src/lib/eina/eina_file_common.h1
4 files changed, 109 insertions, 26 deletions
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index 068aa12..e334bea 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)
795 Eina_Stringshare *filename; 795 Eina_Stringshare *filename;
796 struct stat file_stat; 796 struct stat file_stat;
797 int fd = -1; 797 int fd = -1;
798 Eina_Statgen statgen;
798 799
799 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); 800 EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
800 801
801 filename = eina_file_sanitize(path); 802 filename = eina_file_sanitize(path);
802 if (!filename) return NULL; 803 if (!filename) return NULL;
803 804
804 if (shared) 805 statgen = eina_file_statgen_get();
806 eina_lock_take(&_eina_file_lock_cache);
807 file = eina_hash_find(_eina_file_cache, filename);
808 statgen = eina_file_statgen_get();
809 if ((!file) || (file->statgen != statgen) || (statgen == 0))
805 { 810 {
811 if (shared)
812 {
806#ifdef HAVE_SHM_OPEN 813#ifdef HAVE_SHM_OPEN
807 fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); 814 fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
808 if ((fd != -1) && (!eina_file_close_on_exec(fd, EINA_TRUE))) 815 if ((fd != -1) && (!eina_file_close_on_exec(fd, EINA_TRUE)))
809 goto on_error; 816 goto on_error;
810#else 817#else
811 goto on_error; 818 goto on_error;
812#endif 819#endif
813 } 820 }
814 else 821 else
815 { 822 {
816#ifdef HAVE_OPEN_CLOEXEC 823#ifdef HAVE_OPEN_CLOEXEC
817 fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO | O_CLOEXEC); 824 fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO | O_CLOEXEC);
818#else 825#else
819 fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO); 826 fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
820 if ((fd != -1) && (!eina_file_close_on_exec(fd, EINA_TRUE))) 827 if ((fd != -1) && (!eina_file_close_on_exec(fd, EINA_TRUE)))
821 goto on_error; 828 goto on_error;
822#endif 829#endif
823 } 830 }
824 831 if (fd < 0) goto on_error;
825 if (fd < 0) goto on_error;
826
827 if (fstat(fd, &file_stat))
828 goto on_error;
829 832
830 eina_lock_take(&_eina_file_lock_cache); 833 if (fstat(fd, &file_stat))
834 goto on_error;
835 if (file) file->statgen = statgen;
831 836
832 file = eina_hash_find(_eina_file_cache, filename); 837 if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
833 if ((file) && !_eina_file_timestamp_compare(file, &file_stat)) 838 {
834 { 839 file->delete_me = EINA_TRUE;
835 file->delete_me = EINA_TRUE; 840 eina_hash_del(_eina_file_cache, file->filename, file);
836 eina_hash_del(_eina_file_cache, file->filename, file); 841 file = NULL;
837 file = NULL; 842 }
838 } 843 }
839 844
840 if (!file) 845 if (!file)
@@ -874,7 +879,7 @@ eina_file_open(const char *path, Eina_Bool shared)
874 } 879 }
875 else 880 else
876 { 881 {
877 close(fd); 882 if (fd >= 0) close(fd);
878 n = file; 883 n = file;
879 } 884 }
880 eina_lock_take(&n->lock); 885 eina_lock_take(&n->lock);
@@ -886,6 +891,7 @@ eina_file_open(const char *path, Eina_Bool shared)
886 return n; 891 return n;
887 892
888 on_error: 893 on_error:
894 eina_lock_release(&_eina_file_lock_cache);
889 INF("Could not open file [%s].", filename); 895 INF("Could not open file [%s].", filename);
890 eina_stringshare_del(filename); 896 eina_stringshare_del(filename);
891 897
diff --git a/src/lib/eina/eina_file.h b/src/lib/eina/eina_file.h
index bc1543e..07a045e 100644
--- a/src/lib/eina/eina_file.h
+++ b/src/lib/eina/eina_file.h
@@ -769,6 +769,38 @@ EAPI Eina_Bool eina_file_close_on_exec(int fd, Eina_Bool on);
769#include "eina_inline_file.x" 769#include "eina_inline_file.x"
770 770
771/** 771/**
772 * @typedef Eina_Statgen
773 * @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
774 * @since 1.23
775 */
776typedef unsigned int Eina_Statgen;
777
778/**
779 * @brief Force the stat generation counter to tick over so any following i/o does real i/o and stat calls
780 * @since 1.23
781 */
782EAPI void eina_file_statgen_next(void);
783
784/**
785 * @brief Get the current stat generation counter value
786 * @return 0 if you should always do stat calls and compare, or some other value that changes like a generation counter
787 * @since 1.23
788 */
789EAPI Eina_Statgen eina_file_statgen_get(void);
790
791/**
792 * @brief Enable stat generation count optimiziing to only stat/do file i/o between generation counts changing
793 * @since 1.23
794 */
795EAPI void eina_file_statgen_enable(void);
796
797/**
798 * @brief Disable stat generation count optimiziing to only stat/do file i/o between generation counts changing
799 * @since 1.23
800 */
801EAPI void eina_file_statgen_bisable(void);
802
803/**
772 * @} 804 * @}
773 */ 805 */
774 806
diff --git a/src/lib/eina/eina_file_common.c b/src/lib/eina/eina_file_common.c
index b62fc22..9369cb2 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;
74# define EINA_FILE_MAGIC_CHECK(f, ...) do {} while(0) 74# define EINA_FILE_MAGIC_CHECK(f, ...) do {} while(0)
75#endif 75#endif
76 76
77static Eina_Spinlock _eina_statgen_lock;
78static Eina_Statgen _eina_statgen = 0;
79
80EAPI void
81eina_file_statgen_next(void)
82{
83 eina_spinlock_take(&_eina_statgen_lock);
84 if (_eina_statgen != 0)
85 {
86 _eina_statgen++;
87 if (_eina_statgen == 0) _eina_statgen = 1;
88 }
89 eina_spinlock_release(&_eina_statgen_lock);
90}
91
92EAPI Eina_Statgen
93eina_file_statgen_get(void)
94{
95 Eina_Statgen s;
96 eina_spinlock_take(&_eina_statgen_lock);
97 s = _eina_statgen;
98 eina_spinlock_release(&_eina_statgen_lock);
99 return s;
100}
101
102EAPI void
103eina_file_statgen_enable(void)
104{
105 eina_spinlock_take(&_eina_statgen_lock);
106 if (_eina_statgen != 0) _eina_statgen = 1;
107 eina_spinlock_release(&_eina_statgen_lock);
108}
109
110EAPI void
111eina_file_statgen_bisable(void)
112{
113 eina_spinlock_take(&_eina_statgen_lock);
114 _eina_statgen = 0;
115 eina_spinlock_release(&_eina_statgen_lock);
116}
117
77static char * 118static char *
78_eina_file_escape(char *path, size_t len) 119_eina_file_escape(char *path, size_t len)
79{ 120{
@@ -1072,6 +1113,8 @@ eina_file_init(void)
1072 return EINA_FALSE; 1113 return EINA_FALSE;
1073 } 1114 }
1074 1115
1116 if (getenv("EINA_STATGEN")) _eina_statgen = 1;
1117 eina_spinlock_new(&_eina_statgen_lock);
1075 eina_lock_recursive_new(&_eina_file_lock_cache); 1118 eina_lock_recursive_new(&_eina_file_lock_cache);
1076 eina_magic_string_set(EINA_FILE_MAGIC, "Eina_File"); 1119 eina_magic_string_set(EINA_FILE_MAGIC, "Eina_File");
1077 1120
@@ -1102,6 +1145,7 @@ eina_file_shutdown(void)
1102 1145
1103 eina_log_domain_unregister(_eina_file_log_dom); 1146 eina_log_domain_unregister(_eina_file_log_dom);
1104 _eina_file_log_dom = -1; 1147 _eina_file_log_dom = -1;
1148 eina_spinlock_free(&_eina_statgen_lock);
1105 return EINA_TRUE; 1149 return EINA_TRUE;
1106} 1150}
1107 1151
diff --git a/src/lib/eina/eina_file_common.h b/src/lib/eina/eina_file_common.h
index 142ee2d..38c1a3c 100644
--- a/src/lib/eina/eina_file_common.h
+++ b/src/lib/eina/eina_file_common.h
@@ -89,6 +89,7 @@ struct _Eina_File
89 89
90 int refcount; /**< Keeps track of references to #map. */ 90 int refcount; /**< Keeps track of references to #map. */
91 int global_refcount; /**< Keeps track of references to #global_map. */ 91 int global_refcount; /**< Keeps track of references to #global_map. */
92 Eina_Statgen statgen;/**< For inexact stats a stat gen count to rate limit syscalls to stat file */
92 93
93#ifndef _WIN32 94#ifndef _WIN32
94 int fd; /**< The file descriptor. */ 95 int fd; /**< The file descriptor. */