diff options
| author | root <root> | 2007-12-22 05:47:56 +0000 | 
|---|---|---|
| committer | root <root> | 2007-12-22 05:47:56 +0000 | 
| commit | db2ba1d67df543c8e0dbfc578005b065983bdc94 (patch) | |
| tree | 68f18360b0091ffd1276b02ad32c7d6ac74a8c6d | |
| parent | 40948ce9e4d9dad5abfb7ce8bf9a0a7b7952f654 (diff) | |
*** empty log message ***
| -rw-r--r-- | Symbols.ev | 3 | ||||
| -rw-r--r-- | ev.3 | 48 | ||||
| -rw-r--r-- | ev.c | 91 | ||||
| -rw-r--r-- | ev.h | 8 | ||||
| -rw-r--r-- | ev.pod | 45 | ||||
| -rw-r--r-- | ev_vars.h | 6 | ||||
| -rw-r--r-- | ev_wrap.h | 8 | ||||
| -rw-r--r-- | libev.m4 | 8 | 
8 files changed, 200 insertions, 17 deletions
| @@ -37,9 +37,12 @@ ev_prepare_stop  ev_recommended_backends  ev_ref  ev_set_allocator +ev_set_io_collect_interval  ev_set_syserr_cb +ev_set_timeout_collect_interval  ev_signal_start  ev_signal_stop +ev_sleep  ev_stat_start  ev_stat_stat  ev_stat_stop @@ -129,7 +129,7 @@  .\" ========================================================================  .\"  .IX Title "EV 1" -.TH EV 1 "2007-12-21" "perl v5.8.8" "User Contributed Perl Documentation" +.TH EV 1 "2007-12-22" "perl v5.8.8" "User Contributed Perl Documentation"  .SH "NAME"  libev \- a high performance full\-featured event loop written in C  .SH "SYNOPSIS" @@ -257,6 +257,11 @@ library in any way.  Returns the current time as libev would use it. Please note that the  \&\f(CW\*(C`ev_now\*(C'\fR function is usually faster and also often returns the timestamp  you actually want to know. +.IP "void ev_sleep (ev_tstamp interval)" 4 +.IX Item "void ev_sleep (ev_tstamp interval)" +Sleep for the given interval: The current thread will be blocked until +either it is interrupted or the given time interval has passed. Basically +this is a subsecond-resolution \f(CW\*(C`sleep ()\*(C'\fR.  .IP "int ev_version_major ()" 4  .IX Item "int ev_version_major ()"  .PD 0 @@ -465,7 +470,7 @@ but it scales phenomenally better. While poll and select usually scale  like O(total_fds) where n is the total number of fds (or the highest fd),  epoll scales either O(1) or O(active_fds). The epoll design has a number  of shortcomings, such as silently dropping events in some hard-to-detect -cases and rewuiring a syscall per fd change, no fork support and bad +cases and rewiring a syscall per fd change, no fork support and bad  support for dup:  .Sp  While stopping, setting and starting an I/O watcher in the same iteration @@ -726,6 +731,41 @@ Example: For some weird reason, unregister the above signal handler again.  \&  ev_ref (loop);  \&  ev_signal_stop (loop, &exitsig);  .Ve +.IP "ev_set_io_collect_interval (ev_tstamp interval)" 4 +.IX Item "ev_set_io_collect_interval (ev_tstamp interval)" +.PD 0 +.IP "ev_set_timeout_collect_interval (ev_tstamp interval)" 4 +.IX Item "ev_set_timeout_collect_interval (ev_tstamp interval)" +.PD +These advanced functions influence the time that libev will spend waiting +for events. Both are by default \f(CW0\fR, meaning that libev will try to +invoke timer/periodic callbacks and I/O callbacks with minimum latency. +.Sp +Setting these to a higher value (the \f(CW\*(C`interval\*(C'\fR \fImust\fR be >= \f(CW0\fR) +allows libev to delay invocation of I/O and timer/periodic callbacks to +increase efficiency of loop iterations. +.Sp +The background is that sometimes your program runs just fast enough to +handle one (or very few) event(s) per loop iteration. While this makes +the program responsive, it also wastes a lot of \s-1CPU\s0 time to poll for new +events, especially with backends like \f(CW\*(C`select ()\*(C'\fR which have a high +overhead for the actual polling but can deliver many events at once. +.Sp +By setting a higher \fIio collect interval\fR you allow libev to spend more +time collecting I/O events, so you can handle more events per iteration, +at the cost of increasing latency. Timeouts (both \f(CW\*(C`ev_periodic\*(C'\fR and +\&\f(CW\*(C`ev_timer\*(C'\fR) will be not affected. +.Sp +Likewise, by setting a higher \fItimeout collect interval\fR you allow libev +to spend more time collecting timeouts, at the expense of increased +latency (the watcher callback will be called later). \f(CW\*(C`ev_io\*(C'\fR watchers +will not be affected. +.Sp +Many programs can usually benefit by setting the io collect interval to +a value near \f(CW0.1\fR or so, which is often enough for interactive servers +(of course not for games), likewise for timeouts. It usually doesn't make +much sense to set it to a lower value than \f(CW0.01\fR, as this approsaches +the timing granularity of most systems.  .SH "ANATOMY OF A WATCHER"  .IX Header "ANATOMY OF A WATCHER"  A watcher is a structure that you create and register to record your @@ -2503,6 +2543,10 @@ runtime if successful). Otherwise no use of the realtime clock option will  be attempted. This effectively replaces \f(CW\*(C`gettimeofday\*(C'\fR by \f(CW\*(C`clock_get  (CLOCK_REALTIME, ...)\*(C'\fR and will not normally affect correctness. See the  note about libraries in the description of \f(CW\*(C`EV_USE_MONOTONIC\*(C'\fR, though. +.IP "\s-1EV_USE_NANOSLEEP\s0" 4 +.IX Item "EV_USE_NANOSLEEP" +If defined to be \f(CW1\fR, libev will assume that \f(CW\*(C`nanosleep ()\*(C'\fR is available +and will use it for delays. Otherwise it will use \f(CW\*(C`select ()\*(C'\fR.  .IP "\s-1EV_USE_SELECT\s0" 4  .IX Item "EV_USE_SELECT"  If undefined or defined to be \f(CW1\fR, libev will compile in support for the @@ -56,6 +56,14 @@ extern "C" {  #  endif  # endif +# ifndef EV_USE_NANOSLEEP +#  if HAVE_NANOSLEEP +#   define EV_USE_NANOSLEEP 1 +#  else +#   define EV_USE_NANOSLEEP 0 +#  endif +# endif +  # ifndef EV_USE_SELECT  #  if HAVE_SELECT && HAVE_SYS_SELECT_H  #   define EV_USE_SELECT 1 @@ -148,6 +156,10 @@ extern "C" {  # define EV_USE_REALTIME 0  #endif +#ifndef EV_USE_NANOSLEEP +# define EV_USE_NANOSLEEP 0 +#endif +  #ifndef EV_USE_SELECT  # define EV_USE_SELECT 1  #endif @@ -209,6 +221,12 @@ extern "C" {  # define EV_USE_INOTIFY 0  #endif +#if !EV_USE_NANOSLEEP +# ifndef _WIN32 +#  include <sys/select.h> +# endif +#endif +  #if EV_USE_INOTIFY  # include <sys/inotify.h>  #endif @@ -410,6 +428,33 @@ ev_now (EV_P)  }  #endif +void +ev_sleep (ev_tstamp delay) +{ +  if (delay > 0.) +    { +#if EV_USE_NANOSLEEP +      struct timespec ts; + +      ts.tv_sec  = (time_t)delay; +      ts.tv_nsec = (long)((delay - (ev_tstamp)(ts.tv_sec)) * 1e9); + +      nanosleep (&ts, 0); +#elif defined(_WIN32) +      Sleep (delay * 1e3); +#else +      struct timeval tv; + +      tv.tv_sec  = (time_t)delay; +      tv.tv_usec = (long)((delay - (ev_tstamp)(tv.tv_sec)) * 1e6); + +      select (0, 0, 0, 0, &tv); +#endif +    } +} + +/*****************************************************************************/ +  int inline_size  array_nextsize (int elem, int cur, int cnt)  { @@ -944,6 +989,18 @@ ev_loop_count (EV_P)    return loop_count;  } +void +ev_set_io_collect_interval (EV_P_ ev_tstamp interval) +{ +  io_blocktime = interval; +} + +void +ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) +{ +  timeout_blocktime = interval; +} +  static void noinline  loop_init (EV_P_ unsigned int flags)  { @@ -962,6 +1019,9 @@ loop_init (EV_P_ unsigned int flags)        now_floor = mn_now;        rtmn_diff = ev_rt_now - mn_now; +      io_blocktime      = 0.; +      timeout_blocktime = 0.; +        /* pid check not overridable via env */  #ifndef _WIN32        if (flags & EVFLAG_FORKCHECK) @@ -1458,39 +1518,50 @@ ev_loop (EV_P_ int flags)        /* calculate blocking time */        { -        ev_tstamp block; +        ev_tstamp waittime  = 0.; +        ev_tstamp sleeptime = 0.; -        if (expect_false (flags & EVLOOP_NONBLOCK || idleall || !activecnt)) -          block = 0.; /* do not block at all */ -        else +        if (expect_true (!(flags & EVLOOP_NONBLOCK || idleall || !activecnt)))            {              /* update time to cancel out callback processing overhead */              time_update (EV_A_ 1e100); -            block = MAX_BLOCKTIME; +            waittime = MAX_BLOCKTIME;              if (timercnt)                {                  ev_tstamp to = ((WT)timers [0])->at - mn_now + backend_fudge; -                if (block > to) block = to; +                if (waittime > to) waittime = to;                }  #if EV_PERIODIC_ENABLE              if (periodiccnt)                {                  ev_tstamp to = ((WT)periodics [0])->at - ev_rt_now + backend_fudge; -                if (block > to) block = to; +                if (waittime > to) waittime = to;                }  #endif -            if (expect_false (block < 0.)) block = 0.; +            if (expect_false (waittime < timeout_blocktime)) +              waittime = timeout_blocktime; + +            sleeptime = waittime - backend_fudge; + +            if (expect_true (sleeptime > io_blocktime)) +              sleeptime = io_blocktime; + +            if (sleeptime) +              { +                ev_sleep (sleeptime); +                waittime -= sleeptime; +              }            }          ++loop_count; -        backend_poll (EV_A_ block); +        backend_poll (EV_A_ waittime);          /* update ev_rt_now, do magic */ -        time_update (EV_A_ block); +        time_update (EV_A_ waittime + sleeptime);        }        /* queue pending timers and reschedule them */ @@ -346,6 +346,7 @@ unsigned int ev_recommended_backends (void);  unsigned int ev_embeddable_backends (void);  ev_tstamp ev_time (void); +void ev_sleep (ev_tstamp delay); /* sleep for a while */  /* Sets the allocation function to use, works like realloc.   * It is used to allocate and free memory. @@ -403,8 +404,8 @@ void ev_default_destroy (void); /* destroy the default loop */  /* you can actually call it at any time, anywhere :) */  void ev_default_fork (void); -unsigned int ev_backend (EV_P); -unsigned int ev_loop_count (EV_P); +unsigned int ev_backend (EV_P);    /* backend in use by loop */ +unsigned int ev_loop_count (EV_P); /* number of loop iterations */  #endif  #define EVLOOP_NONBLOCK	1 /* do not block/wait */ @@ -417,6 +418,9 @@ unsigned int ev_loop_count (EV_P);  void ev_loop (EV_P_ int flags);  void ev_unloop (EV_P_ int how); /* set to 1 to break out of event loop, set to 2 to break out of all event loops */ +void ev_set_io_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ +void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval); /* sleep at least this time, default 0 */ +  /*   * ref/unref can be used to add or remove a refcount on the mainloop. every watcher   * keeps one reference. if you have a long-runing watcher you never unregister that @@ -117,6 +117,12 @@ Returns the current time as libev would use it. Please note that the  C<ev_now> function is usually faster and also often returns the timestamp  you actually want to know. +=item ev_sleep (ev_tstamp interval) + +Sleep for the given interval: The current thread will be blocked until +either it is interrupted or the given time interval has passed. Basically +this is a subsecond-resolution C<sleep ()>. +  =item int ev_version_major ()  =item int ev_version_minor () @@ -571,6 +577,40 @@ Example: For some weird reason, unregister the above signal handler again.    ev_ref (loop);    ev_signal_stop (loop, &exitsig); +=item ev_set_io_collect_interval (loop, ev_tstamp interval) + +=item ev_set_timeout_collect_interval (loop, ev_tstamp interval) + +These advanced functions influence the time that libev will spend waiting +for events. Both are by default C<0>, meaning that libev will try to +invoke timer/periodic callbacks and I/O callbacks with minimum latency. + +Setting these to a higher value (the C<interval> I<must> be >= C<0>) +allows libev to delay invocation of I/O and timer/periodic callbacks to +increase efficiency of loop iterations. + +The background is that sometimes your program runs just fast enough to +handle one (or very few) event(s) per loop iteration. While this makes +the program responsive, it also wastes a lot of CPU time to poll for new +events, especially with backends like C<select ()> which have a high +overhead for the actual polling but can deliver many events at once. + +By setting a higher I<io collect interval> you allow libev to spend more +time collecting I/O events, so you can handle more events per iteration, +at the cost of increasing latency. Timeouts (both C<ev_periodic> and +C<ev_timer>) will be not affected. + +Likewise, by setting a higher I<timeout collect interval> you allow libev +to spend more time collecting timeouts, at the expense of increased +latency (the watcher callback will be called later). C<ev_io> watchers +will not be affected. + +Many programs can usually benefit by setting the io collect interval to +a value near C<0.1> or so, which is often enough for interactive servers +(of course not for games), likewise for timeouts. It usually doesn't make +much sense to set it to a lower value than C<0.01>, as this approsaches +the timing granularity of most systems. +  =back @@ -2299,6 +2339,11 @@ be attempted. This effectively replaces C<gettimeofday> by C<clock_get  (CLOCK_REALTIME, ...)> and will not normally affect correctness. See the  note about libraries in the description of C<EV_USE_MONOTONIC>, though. +=item EV_USE_NANOSLEEP + +If defined to be C<1>, libev will assume that C<nanosleep ()> is available +and will use it for delays. Otherwise it will use C<select ()>. +  =item EV_USE_SELECT  If undefined or defined to be C<1>, libev will compile in support for the @@ -3,14 +3,18 @@  VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */  VARx(ev_tstamp, mn_now)    /* monotonic clock "now" */  VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */ + +VARx(ev_tstamp, io_blocktime); +VARx(ev_tstamp, timeout_blocktime); +  VARx(int, backend)  VARx(int, activecnt) /* total number of active events ("refcount") */  VARx(unsigned int, loop_count); /* total number of loop iterations/blocks */ +VARx(int, backend_fd)  VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */  VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev))  VAR (backend_poll  , void (*backend_poll)(EV_P_ ev_tstamp timeout)) -VARx(int, backend_fd)  #if !defined(_WIN32) || EV_GENWRAP  VARx(pid_t, curpid) @@ -4,13 +4,15 @@  #define now_floor ((loop)->now_floor)  #define mn_now ((loop)->mn_now)  #define rtmn_diff ((loop)->rtmn_diff) +#define io_blocktime ((loop)->io_blocktime) +#define timeout_blocktime ((loop)->timeout_blocktime)  #define backend ((loop)->backend)  #define activecnt ((loop)->activecnt)  #define loop_count ((loop)->loop_count) +#define backend_fd ((loop)->backend_fd)  #define backend_fudge ((loop)->backend_fudge)  #define backend_modify ((loop)->backend_modify)  #define backend_poll ((loop)->backend_poll) -#define backend_fd ((loop)->backend_fd)  #define curpid ((loop)->curpid)  #define postfork ((loop)->postfork)  #define vec_ri ((loop)->vec_ri) @@ -67,13 +69,15 @@  #undef now_floor  #undef mn_now  #undef rtmn_diff +#undef io_blocktime +#undef timeout_blocktime  #undef backend  #undef activecnt  #undef loop_count +#undef backend_fd  #undef backend_fudge  #undef backend_modify  #undef backend_poll -#undef backend_fd  #undef curpid  #undef postfork  #undef vec_ri @@ -14,6 +14,14 @@ AC_CHECK_FUNC(clock_gettime, [], [     fi  ]) +AC_CHECK_FUNC(nanonsleep, [], [  +   if test -z "$LIBEV_M4_AVOID_LIBRT"; then +      AC_CHECK_LIB(rt, nanonsleep)  +      unset ac_cv_func_nanonsleep +      AC_CHECK_FUNCS(nanonsleep) +   fi +]) +  AC_CHECK_LIB(m, ceil) | 
