summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-11-27 17:05:06 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2016-11-27 17:21:51 +0900
commit81242af6f958df4e81b1bf84ec01af655111774a (patch)
tree00983a07261c9645c3c8b14d90677f04c1e07484
parent6a462f925f7b4bed35692ede4664b876241deb3e (diff)
downloadefl-81242af6f958df4e81b1bf84ec01af655111774a.tar.gz
ecore animator - timer based ticker - add epoll support if available
the ecore time based animator that ticked away used select for timeouts to listen to either a timeout OR the control fd that would tell it to tick or not tick. my profiles show this as consuming 1.03% of my profile sample time - just the select call in the time based animator. this adds the option of epoll + timerfd + having kernel repeat the timer fd interval (since epoll timeouts at best can do 1ms resolution). my profiling shows this to use 0.62% of profile time vs 1.03% for select, so it's a tiny win. this only compiles if epoll and timerfd support have already been detected at compile time. it also runtime falls back to select if epoll and timerfd setup fail. @optimize
-rw-r--r--src/lib/ecore/ecore_anim.c212
1 files changed, 185 insertions, 27 deletions
diff --git a/src/lib/ecore/ecore_anim.c b/src/lib/ecore/ecore_anim.c
index 66432868d5..c4197fa4e1 100644
--- a/src/lib/ecore/ecore_anim.c
+++ b/src/lib/ecore/ecore_anim.c
@@ -9,6 +9,12 @@
#include <sys/types.h>
#include <sys/stat.h>
+#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_TIMERFD_H)
+# define HAVE_EPOLL 1
+# include <sys/epoll.h>
+# include <sys/timerfd.h>
+#endif
+
#ifdef _WIN32
# include <winsock2.h>
@@ -58,7 +64,7 @@ static Eina_Bool _ecore_animator_run(void *data);
static int animators_delete_me = 0;
static Ecore_Animator *animators = NULL;
-static double animators_frametime = 1.0 / 30.0;
+static volatile double animators_frametime = 1.0 / 60.0;
static unsigned int animators_suspended = 0;
static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
@@ -105,55 +111,207 @@ _timer_send_time(double t)
static void
_timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
{
+#ifdef HAVE_EPOLL
+ int pollfd = -1, timerfd = -1;
+ struct epoll_event pollev = { 0 };
+ struct epoll_event pollincoming[2];
+ uint64_t timerfdbuf;
+ int i;
+ unsigned int t_ft;
+ double pframetime = -1.0;
+ struct itimerspec tspec_new;
+ struct itimerspec tspec_old;
+#endif
fd_set rfds, wfds, exfds;
struct timeval tv;
+ Eina_Bool data_control;
+ Eina_Bool data_timeout;
unsigned int t;
signed char tick = 0;
- double t0, d;
+ double t0, d, ft;
int ret;
eina_thread_name_set(eina_thread_self(), "Eanimator-timer");
#ifdef HAVE_PRCTL
prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
#endif
- while (!ecore_thread_check(thread))
+
+#ifdef HAVE_EPOLL
+ pollfd = epoll_create(1);
+ if (pollfd >= 0) _ecore_fd_close_on_exec(pollfd);
+
+#if defined(TFD_NONBLOCK) && defined(TFD_CLOEXEC)
+ timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
+#endif
+ if (timerfd < 0)
+ {
+ timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
+ if (timerfd >= 0) _ecore_fd_close_on_exec(timerfd);
+ }
+ if (timerfd < 0)
{
- DBG("------- timer_event_is_busy=%i", timer_event_is_busy);
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&exfds);
- FD_SET(timer_fd_read, &rfds);
-
- t0 = ecore_time_get();
- d = fmod(t0, animators_frametime);
- if (tick)
+ close(pollfd);
+ pollfd = -1;
+ }
+
+#define INPUT_TIMER_CONTROL ((void *) ((unsigned long) 0x11))
+#define INPUT_TIMER_TIMERFD ((void *) ((unsigned long) 0x22))
+
+ if (pollfd >= 0)
+ {
+ pollev.data.ptr = INPUT_TIMER_CONTROL;
+ pollev.events = EPOLLIN;
+ if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timer_fd_read, &pollev) != 0)
{
- DBG("sleep...");
- t = (animators_frametime - d) * 1000000.0;
- tv.tv_sec = t / 1000000;
- tv.tv_usec = t % 1000000;
- ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, &tv);
+ close(timerfd);
+ timerfd = -1;
+ close(pollfd);
+ pollfd = -1;
}
- else
+ if (pollfd >= 0)
{
- DBG("wait...");
- ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, NULL);
+ pollev.data.ptr = INPUT_TIMER_TIMERFD;
+ pollev.events = EPOLLIN;
+ if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timerfd, &pollev) != 0)
+ {
+ close(timerfd);
+ timerfd = -1;
+ close(pollfd);
+ pollfd = -1;
+ }
}
- if ((ret == 1) && (FD_ISSET(timer_fd_read, &rfds)))
+ }
+
+ if (pollfd >= 0)
+ {
+ while (!ecore_thread_check(thread))
{
- if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1)
+ data_control = EINA_FALSE;
+ data_timeout = EINA_FALSE;
+ ft = animators_frametime;
+
+ DBG("------- timer_event_is_busy=%i", timer_event_is_busy);
+
+ t0 = ecore_time_get();
+ d = fmod(t0, ft);
+ if (tick)
+ {
+ if (pframetime != ft)
+ {
+ t = (ft - d) * 1000000000.0;
+ t_ft = ft * 1000000000.0;
+ tspec_new.it_value.tv_sec = t / 1000000000;
+ tspec_new.it_value.tv_nsec = t % 1000000000;
+ tspec_new.it_interval.tv_sec = t_ft / 1000000000;
+ tspec_new.it_interval.tv_nsec = t_ft % 1000000000;
+ timerfd_settime(timerfd, 0, &tspec_new, &tspec_old);
+ pframetime = ft;
+ }
+ DBG("sleep...");
+ ret = epoll_wait(pollfd, pollincoming, 2, -1);
+ }
+ else
+ {
+ tspec_new.it_value.tv_sec = 0;
+ tspec_new.it_value.tv_nsec = 0;
+ tspec_new.it_interval.tv_sec = 0;
+ tspec_new.it_interval.tv_nsec = 0;
+ pframetime = -1.0;
+ timerfd_settime(timerfd, 0, &tspec_new, &tspec_old);
+ DBG("wait...");
+ ret = epoll_wait(pollfd, pollincoming, 2, -1);
+ }
+
+ for (i = 0; i < ret; i++)
+ {
+ if (pollincoming[i].events & EPOLLIN)
+ {
+ if (pollincoming[i].data.ptr == INPUT_TIMER_TIMERFD)
+ {
+ read(timerfd, &timerfdbuf, sizeof(timerfdbuf));
+ data_timeout = EINA_TRUE;
+ }
+ else if (pollincoming[i].data.ptr == INPUT_TIMER_CONTROL)
+ data_control = EINA_TRUE;
+ }
+ }
+ if (data_control)
+ {
+ if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1)
+ {
+ ERR("Cannot read from animator control fd");
+ }
+ DBG("tick = %i", tick);
+ if (tick == -1) goto done;
+ }
+ else if (data_timeout)
{
- ERR("Cannot read from animator control fd");
+ if (tick) _timer_send_time(t0 - d + ft);
}
- DBG("tick = %i", tick);
- if (tick == -1) goto done;
}
- else
+ }
+ else
+#endif
+ {
+ while (!ecore_thread_check(thread))
{
- if (tick) _timer_send_time(t0 - d + animators_frametime);
+ data_control = EINA_FALSE;
+ data_timeout = EINA_FALSE;
+ ft = animators_frametime;
+
+ DBG("------- timer_event_is_busy=%i", timer_event_is_busy);
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&exfds);
+ FD_SET(timer_fd_read, &rfds);
+
+ t0 = ecore_time_get();
+ d = fmod(t0, ft);
+ if (tick)
+ {
+ DBG("sleep...");
+ t = (animators_frametime - d) * 1000000.0;
+ tv.tv_sec = t / 1000000;
+ tv.tv_usec = t % 1000000;
+ ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, &tv);
+ }
+ else
+ {
+ DBG("wait...");
+ ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, NULL);
+ }
+ if ((ret == 1) && (FD_ISSET(timer_fd_read, &rfds)))
+ data_control = EINA_TRUE;
+ else if (ret == 0)
+ data_timeout = EINA_TRUE;
+ if (data_control)
+ {
+ if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1)
+ {
+ ERR("Cannot read from animator control fd");
+ }
+ DBG("tick = %i", tick);
+ if (tick == -1) goto done;
+ }
+ else if (data_timeout)
+ {
+ if (tick) _timer_send_time(t0 - d + ft);
+ }
}
}
done:
+#ifdef HAVE_EPOLL
+ if (pollfd >= 0)
+ {
+ close(pollfd);
+ pollfd = -1;
+ }
+ if (timerfd >= 0)
+ {
+ close(timerfd);
+ timerfd = -1;
+ }
+#endif
pipe_close(timer_fd_read);
timer_fd_read = -1;
pipe_close(timer_fd_write);