[I copied this to the libev list as I tried to give a very comprehensive
 answer that might be of interest to others]

> Does this mean that if a watcher does
> 
>       event_add() -> loop -> event_add()
> 
> --i.e. when not using EV_PERSIST--that no additional EPOLL_CTL_DEL or
> EPOLL_CTL_ADD calls are done?

Lets clarify:
>       event_add() -> loop -> event_add()
                              ^ event received and watcher restarted before
                                next iteration

The strict answer is no, it does not mean that, because that has been the
behaviour of libev ever since, and this behaviour didn't change :)

The trival answer is yes, because libev never did DEL/ADD in that case,
but instead would try a (much cheaper) MOD, and this behaviour hasn't
changed with the new version. Libev never did syscalls within event_add or
event_del, it only marked the fd as "needs check" and only before the next
event poll would it recalculate its interest set (leading to MOD which is
much cheaper than an ADD or DEL even individually).

What the recent optimisation does is that it does is suppress the DEL
and MOD in cases where the fd hasn't "changed" (changes can only be detected by 
policy,
see 
http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#The_special_problem_of_disappearing_)

That means a stop/start does not result in any epoll_ctl call in common
cases, and in the same or less number of syscalls in exceptional ones (the
only pessimisation is an additional event loop iteration in the worst
case, and potential garbage fds staying in the epoll set for a while).

This works only when using the native libev API currently.

I am also not sure that it can be done with the libevent API, as it
doesn't have the same fd generation guarantees as libev requires (for
example, the libevent testsuite manages to re-use the same fd number for
different fds with the same watcher, making any optimisation impossible).

For your example this means that you will have one EPOLL_CTL_MOD call per
iteration instead of an ADD/DEL combination as with libevent. When using
the native API, even that call would be optimised away (making it as cheap
syscall-wise as a persistent watcher).

To go into more details, here are some examples with the native API
(assuming the same watcher and no other activity):

   ev_io_stop // automatic or via event_del
   ev_io_set with same fd
   ev_io_start

   this would cause a MOD to be attempted, as ev_io_set is interpreted
   as possible file description change. this is also what the libevent
   emulation does as it calls ev_io_set internally when the watcher isn't
   active.

   ev_io_stop
   ev_io_start

   this would result in no additional syscall (this is the new change).

   ev_io_stop

   this would also result in no additional syscall (also a new change).
   libev assumes the fd is gone, and if it receives an event for it, it
   will automatically DEL it, the worst possible case.

This change reduced the number of failures in epoll_ctl enourmously in all
my programs: one is a client that makes hundreds of quick requests each
with a new tcp connection, one is a web server that does rate-limiting
and frequently stops watchers on existing fds for a "long" time, and
one is a game server which never calls start/stop on an existing client
connection.

The first program suffered from a lot of DEL => EBADF calls when the fd
was already gone (or ENOENT if it was replaced), the second case lost an
enourmous number of MOD calls (and gained a few DELs) and the last one
didn't change at all.

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

_______________________________________________
libev mailing list
[email protected]
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev

Reply via email to