forked from enlightenment/efl
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
This commit is contained in:
parent
6a462f925f
commit
81242af6f9
|
@ -9,6 +9,12 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.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
|
#ifdef _WIN32
|
||||||
|
|
||||||
# include <winsock2.h>
|
# include <winsock2.h>
|
||||||
|
@ -58,7 +64,7 @@ static Eina_Bool _ecore_animator_run(void *data);
|
||||||
|
|
||||||
static int animators_delete_me = 0;
|
static int animators_delete_me = 0;
|
||||||
static Ecore_Animator *animators = NULL;
|
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 unsigned int animators_suspended = 0;
|
||||||
|
|
||||||
static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
|
static Ecore_Animator_Source src = ECORE_ANIMATOR_SOURCE_TIMER;
|
||||||
|
@ -105,19 +111,154 @@ _timer_send_time(double t)
|
||||||
static void
|
static void
|
||||||
_timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
|
_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;
|
fd_set rfds, wfds, exfds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
Eina_Bool data_control;
|
||||||
|
Eina_Bool data_timeout;
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
signed char tick = 0;
|
signed char tick = 0;
|
||||||
double t0, d;
|
double t0, d, ft;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
eina_thread_name_set(eina_thread_self(), "Eanimator-timer");
|
eina_thread_name_set(eina_thread_self(), "Eanimator-timer");
|
||||||
#ifdef HAVE_PRCTL
|
#ifdef HAVE_PRCTL
|
||||||
prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
|
prctl(PR_SET_TIMERSLACK, 1, 0, 0, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
close(timerfd);
|
||||||
|
timerfd = -1;
|
||||||
|
close(pollfd);
|
||||||
|
pollfd = -1;
|
||||||
|
}
|
||||||
|
if (pollfd >= 0)
|
||||||
|
{
|
||||||
|
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 (pollfd >= 0)
|
||||||
|
{
|
||||||
while (!ecore_thread_check(thread))
|
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);
|
||||||
|
|
||||||
|
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);
|
DBG("------- timer_event_is_busy=%i", timer_event_is_busy);
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
|
@ -125,7 +266,7 @@ _timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
|
||||||
FD_SET(timer_fd_read, &rfds);
|
FD_SET(timer_fd_read, &rfds);
|
||||||
|
|
||||||
t0 = ecore_time_get();
|
t0 = ecore_time_get();
|
||||||
d = fmod(t0, animators_frametime);
|
d = fmod(t0, ft);
|
||||||
if (tick)
|
if (tick)
|
||||||
{
|
{
|
||||||
DBG("sleep...");
|
DBG("sleep...");
|
||||||
|
@ -140,6 +281,10 @@ _timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
|
||||||
ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, NULL);
|
ret = select(timer_fd_read + 1, &rfds, &wfds, &exfds, NULL);
|
||||||
}
|
}
|
||||||
if ((ret == 1) && (FD_ISSET(timer_fd_read, &rfds)))
|
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)
|
if (pipe_read(timer_fd_read, &tick, sizeof(tick)) != 1)
|
||||||
{
|
{
|
||||||
|
@ -148,12 +293,25 @@ _timer_tick_core(void *data EINA_UNUSED, Ecore_Thread *thread)
|
||||||
DBG("tick = %i", tick);
|
DBG("tick = %i", tick);
|
||||||
if (tick == -1) goto done;
|
if (tick == -1) goto done;
|
||||||
}
|
}
|
||||||
else
|
else if (data_timeout)
|
||||||
{
|
{
|
||||||
if (tick) _timer_send_time(t0 - d + animators_frametime);
|
if (tick) _timer_send_time(t0 - d + ft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
|
#ifdef HAVE_EPOLL
|
||||||
|
if (pollfd >= 0)
|
||||||
|
{
|
||||||
|
close(pollfd);
|
||||||
|
pollfd = -1;
|
||||||
|
}
|
||||||
|
if (timerfd >= 0)
|
||||||
|
{
|
||||||
|
close(timerfd);
|
||||||
|
timerfd = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
pipe_close(timer_fd_read);
|
pipe_close(timer_fd_read);
|
||||||
timer_fd_read = -1;
|
timer_fd_read = -1;
|
||||||
pipe_close(timer_fd_write);
|
pipe_close(timer_fd_write);
|
||||||
|
|
Loading…
Reference in New Issue