On 09/29/2014 08:24 AM, Saúl Ibarra Corretgé wrote:
> 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,
> 

Also, on top the above, creating and processing a timer requires 3
syscalls: timerfd_create, timerfd_gettime and read vs 0 if we keep the
min-heap.

-- 
Saúl Ibarra Corretgé
bettercallsaghul.com


Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to