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
signature.asc
Description: OpenPGP digital signature
