alternate approach to timer inaccuracy due to cached times

Marc Lehmann schmorp at schmorp.de
Thu Oct 13 08:48:40 CEST 2011


On Tue, Oct 11, 2011 at 05:15:54PM -0700, Shaun Lindsay <srlindsay at gmail.com> wrote:
> Hello,

Hi!

> As mentioned in the above link, you can force an update of the cached time
> via ev_update_now(), but this doesn't practically address the issue.

Well, it should address the issue, thats what it is made for - why do you
think it doesn't address the issue?

> case, the triggering of any of the timeouts would constitute an error case,
> so I'd need to call ev_update_now() before every timer start.

In most cases, you would have events that invalidate the error case -
having these at higher priority would solve that problem in a better way.

> timeouts where immediate, nondeterministic expiration is an acceptable
> condition,

You are not talking about libev, are you? Even without calling
ev_update_now there is nothing nondeterministic, and timers don't timeout
immediately in any case.

> time for every timer anyway.  From a gevent perspective, it also becomes
> difficult to expose the update call in a sane way to the user, since the
> event architecture is hidden beneath the greenlet/coroutine abstraction.

I can't say much about gevent, but that seems to indicate a design issue
with gevent to me.

> Deferring calls ev_timer_start to the end of the dispatch cycle, then
> starting them in a batch would fix this issue.

Well, it doesn't make anything more deterministic, or avoids timers timing
out immediately, you are just trading one behaviour for another.

> One nice advantage of this approach is that under heavy load, the timeouts
> will occur later than the requested time, rather than before the requested

Libev guarantees that timeouts never trigger before the requested time
already.

> time, which seems saner from an application perspective -- I'd rather have a
> 100ms timeout fire at 200ms than fire in 0ms.

The latter can only happen if you use two different clocks to compare
times.  This is rather meaningless - libev will never timeout a timer
requesting a 100ms timeout before or even at 100ms after the requested time.

> probably need modification to be consistent, like adding a struct ev_timer
> *next to all ev_timers for use in a linked list, for instance.  I'm also not

Unrelated to the problem: the libev way of doing things would be to have
an array for those timers, which would likely be faster and save some
memory.

>  Now that I think about it, timers started by callbacks from other timers
> might not get picked up until the next event cycle, which might be bad, I'm
> not sure.  Somebody more familiar with the code can probably point me in the
> right direction on that.

I think if you are hitting such a problem in gevent, this is a design issue
in gevent - any event system should be able to deal with delays in event
processing in a sane way.

Fixing the desing might be hard, though, but since gevent doesn't expose
libev, adding an ev_update_now before creating a timer seems like an easy
workaround (after all, other high-performance event libraries do that too
:)

If this is only important for some timers, you could either do it only for
those, or base your timings on ev_time(), as described in the manpage.

And last not least, you could easily implement this in gevent, where it
probably belongs, as it works around a (probably minor) design limitation
in gevent.

-- 
                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_              http://www.deliantra.net
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      schmorp at schmorp.de
      -=====/_/_//_/\_,_/ /_/\_\



More information about the libev mailing list