From 81242af6f958df4e81b1bf84ec01af655111774a Mon Sep 17 00:00:00 2001 From: "Carsten Haitzler (Rasterman)" Date: Sun, 27 Nov 2016 17:05:06 +0900 Subject: [PATCH] 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 --- src/lib/ecore/ecore_anim.c | 216 ++++++++++++++++++++++++++++++++----- 1 file changed, 187 insertions(+), 29 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 #include +#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_SYS_TIMERFD_H) +# define HAVE_EPOLL 1 +# include +# include +#endif + #ifdef _WIN32 # include @@ -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)) - { - 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) +#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) + { + 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); - } - if ((ret == 1) && (FD_ISSET(timer_fd_read, &rfds))) - { - if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1) + pollev.data.ptr = INPUT_TIMER_TIMERFD; + pollev.events = EPOLLIN; + if (epoll_ctl(pollfd, EPOLL_CTL_ADD, timerfd, &pollev) != 0) { - ERR("Cannot read from animator control fd"); + close(timerfd); + timerfd = -1; + close(pollfd); + pollfd = -1; } - DBG("tick = %i", tick); - if (tick == -1) goto done; } - else + } + + if (pollfd >= 0) + { + 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); + + 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) + { + if (tick) _timer_send_time(t0 - d + ft); + } + } + } + else +#endif + { + while (!ecore_thread_check(thread)) + { + 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);