Hi Jean-Christian,

On 09/29/2014 01:06 AM, Jean-Christian de Rivaz wrote:
> Hello,
> 
> I tried to use libuv on Linux for an application that require a precise
> periodicity. I observed that uv_timer_start(, ,100, 100) make the
> repetitive epoll() always wait a bit more than 100ms, regardless of the
> callback function execution time (strace -T):
> |
> epoll_wait(5,{},1024,99)            =0<0.099287> <=Firstepoll()wait 99.287ms
> sync()                                 =0<0.054469>
> epoll_wait(5,{},1024,100)           =0<0.100211> <=Secondepoll()wait
> 100.211ms
> sync()                                 =0<0.040866>
> epoll_wait(5,{},1024,100)           =0<0.100207> <===
> sync()                                 =0<0.046870>
> epoll_wait(5,{},1024,100)           =0<0.100214> <===
> sync()                                 =0<0.043035>
> epoll_wait(5,{},1024,100)           =0<0.100139> <===
> |
> I use the sync() in the callback to very simply add a execution of about
> from 40ms to 50ms on the test machine, the final application is more
> complex than that, this is just to keep the example as simple as
> possible. After the first epoll(), all epoll() have a similar length of
> a bit more that 100ms. This already too long delay is in addition to the
> delay of the sync() call. In fine, the period of this example is between
> 140ms and 150ms instead of the expected 100ms. If I filter the sync()
> call time I get this (strace -tt):
> |
> 00:31:27.960802sync()                 =0
> 00:31:28.106703sync()                 =0
> 00:31:28.250530sync()                 =0
> 00:31:28.391060sync()                 =0
> 00:31:28.529861sync()                 =0
> 00:31:28.669751sync()                 =0
> 00:31:28.810477sync()                 =0
> 00:31:28.949302sync()                 =0
> |
> The jitter of the sync() call time is very big, probably equal to the
> callback execution time.
> 
> I tested timerfd_create() on the same machine with a loop of read() on
> the timerfd file and sync(). The result is very different (strace -T):
> |
> timerfd_create(CLOCK_MONOTONIC,0)     =9<0.000013>
> timerfd_settime(9,0,{it_interval={0,100000000},it_value={0,100000000}},NULL)=0<0.000014>
> read(9,"\1\0\0\0\0\0\0\0",8)         =8<0.100138> <==Firstread()on
> timerd fd file wait 100.138ms
> sync()                                 =0<0.053847>
> read(9,"\1\0\0\0\0\0\0\0",8)         =8<0.045944> <=Secondread()wait
> 45.944ms
> sync()                                 =0<0.047778>
> read(9,"\1\0\0\0\0\0\0\0",8)         =8<0.051987> <===
> sync()                                 =0<0.046731>
> read(9,"\1\0\0\0\0\0\0\0",8)         =8<0.053102> <===
> sync()                                 =0<0.044829>
> read(9,"\1\0\0\0\0\0\0\0",8)         =8<0.055018> <===
> |
> The read() delay compensate exactly the sync() delay to make a
> periodicity of exactly 100ms. If I filter the sync() call time I get
> this (strace -tt):
> |
> 00:47:23.687205sync()                 =0
> 00:47:23.787220sync()                 =0
> 00:47:23.887393sync()                 =0
> 00:47:23.987276sync()                 =0
> 00:47:24.087210sync()                 =0
> 00:47:24.187164sync()                 =0
> 00:47:24.287242sync()                 =0
> 00:47:24.387330sync()                 =0
> 00:47:24.487286sync()                 =0
> 00:47:24.587181sync()                 =0
> 00:47:24.687237sync()                 =0
> |
> The jitter of the sync() call time is smaller than 1ms, something that
> the current libuv is unable to do.
> 

Periodic timers are a bit hard. Some people expect that the timer
compensates for the time spent in the callback, some don't cause they
want the interval to be preserved across callbacks. It's also quite
messy to handle the case in which the callback takes longer than the
next interval.

Having that said, timers on libuv don't compensate for the amount of
time spent in the callback.

> I have two questions:
> 1) is there anything that would prevent libuv from
> using timerfd_settime() on Linux ?

There are a couple I can think of: timerfd was added in Linux 2.6.22,
and I believe we still support older kernels, but more importantly,
timerfd would create a file descriptor per timer, that's one million fds
if we have one million timers, vs 0 fds which the current implementation
uses.

> 2) Is there any motivation to do that ?
> 

Hopefully others chime in as well, but I'm not really inclined to go
this route, for the aforementioned reasons. I'm open to be proven
otherwise though :-)


Regards,

-- 
Saúl Ibarra Corretgé
bettercallsaghul.com


Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to