--- AnyEvent/lib/AnyEvent.pm 2008/04/24 08:38:13 1.59 +++ AnyEvent/lib/AnyEvent.pm 2008/04/25 07:43:25 1.72 @@ -2,7 +2,7 @@ AnyEvent - provide framework for multiple event loops -EV, Event, Coro::EV, Coro::Event, Glib, Tk, Perl, Event::Lib, Qt - various supported event loops +EV, Event, Coro::EV, Coro::Event, Glib, Tk, Perl, Event::Lib, Qt, POE - various supported event loops =head1 SYNOPSIS @@ -80,11 +80,12 @@ module. During the first call of any watcher-creation method, the module tries -to detect the currently loaded event loop by probing whether one of -the following modules is already loaded: L, L, -L, L, L, L, L, L. The first one -found is used. If none are found, the module tries to load these modules -(excluding Event::Lib and Qt) in the order given. The first one that can +to detect the currently loaded event loop by probing whether one of the +following modules is already loaded: L, L, L, +L, L, L, L, L, L, +L. The first one found is used. If none are found, the module tries +to load these modules (excluding Event::Lib, Qt and POE as the pure perl +adaptor should always succeed) in the order given. The first one that can be successfully loaded will be used. If, after this, still none could be found, AnyEvent will fall back to a pure-perl event loop, which is not very efficient, but should work everywhere. @@ -364,6 +365,17 @@ AnyEvent::Impl::Perl pure-perl implementation, inefficient but portable. AnyEvent::Impl::Qt based on Qt, cannot be autoprobed (see its docs). AnyEvent::Impl::EventLib based on Event::Lib, leaks memory and worse. + AnyEvent::Impl::POE based on POE, not generic enough for full support. + +There is no support for WxWidgets, as WxWidgets has no support for +watching file handles. However, you can use WxWidgets through the +POE Adaptor, as POE has a Wx backend that simply polls 20 times per +second, which was considered to be too horrible to even consider for +AnyEvent. Likewise, other POE backends can be used by AnyEvent by using +it's adaptor. + +AnyEvent knows about L and L and will try to use L when +autodetecting them. =item AnyEvent::detect @@ -424,7 +436,7 @@ use Carp; -our $VERSION = '3.2'; +our $VERSION = '3.3'; our $MODEL; our $AUTOLOAD; @@ -441,11 +453,13 @@ [Event:: => AnyEvent::Impl::Event::], [Glib:: => AnyEvent::Impl::Glib::], [Tk:: => AnyEvent::Impl::Tk::], + [Wx:: => AnyEvent::Impl::POE::], + [Prima:: => AnyEvent::Impl::POE::], [AnyEvent::Impl::Perl:: => AnyEvent::Impl::Perl::], -); -my @models_detect = ( - [Qt:: => AnyEvent::Impl::Qt::], # requires special main program + # everything below here will not be autoprobed as the pureperl backend should work everywhere [Event::Lib:: => AnyEvent::Impl::EventLib::], # too buggy + [Qt:: => AnyEvent::Impl::Qt::], # requires special main program + [POE::Kernel:: => AnyEvent::Impl::POE::], # lasciate ogni speranza ); our %method = map +($_ => 1), qw(io timer signal child condvar broadcast wait one_event DESTROY); @@ -459,12 +473,14 @@ if (eval "require $model") { $MODEL = $model; warn "AnyEvent: loaded model '$model' (forced by \$PERL_ANYEVENT_MODEL), using it.\n" if $verbose > 1; + } else { + warn "AnyEvent: unable to load model '$model' (from \$PERL_ANYEVENT_MODEL):\n$@" if $verbose; } } # check for already loaded models unless ($MODEL) { - for (@REGISTRY, @models, @models_detect) { + for (@REGISTRY, @models) { my ($package, $model) = @$_; if (${"$package\::VERSION"} > 0) { if (eval "require $model") { @@ -661,6 +677,14 @@ =item C +By default, AnyEvent will be completely silent except in fatal +conditions. You can set this environment variable to make AnyEvent more +talkative. + +When set to C<1> or higher, causes AnyEvent to warn about unexpected +conditions, such as not being able to load the event model specified by +C. + When set to C<2> or higher, cause AnyEvent to report to STDERR which event model it chooses. @@ -838,6 +862,114 @@ $quit->wait; + +=head1 BENCHMARK + +To give you an idea of the performance and overheads that AnyEvent adds +over the event loops themselves (and to give you an impression of the +speed of various event loops), here is a benchmark of various supported +event models natively and with anyevent. The benchmark creates a lot of +timers (with a zero timeout) and io watchers (watching STDOUT, a pty, to +become writable, which it is), lets them fire exactly once and destroys +them again. + +=head2 Explanation of the columns + +I is the number of event watchers created/destroyed. Since +different event models feature vastly different performances, each event +loop was given a number of watchers so that overall runtime is acceptable +and similar between tested event loop (and keep them from crashing): Glib +would probably take thousands of years if asked to process the same number +of watchers as EV in this benchmark. + +I is the number of bytes (as measured by the resident set size, +RSS) consumed by each watcher. This method of measuring captures both C +and Perl-based overheads. + +I is the time, in microseconds (millionths of seconds), that it +takes to create a single watcher. The callback is a closure shared between +all watchers, to avoid adding memory overhead. That means closure creation +and memory usage is not included in the figures. + +I is the time, in microseconds, used to invoke a simple +callback. The callback simply counts down a Perl variable and after it was +invoked "watcher" times, it would C<< ->broadcast >> a condvar once to +signal the end of this phase. + +I is the time, in microseconds, that it takes to destroy a single +watcher. + +=head2 Results + + name watcher bytes create invoke destroy comment + EV/EV 400000 244 0.56 0.46 0.31 EV native interface + EV/Any 100000 610 3.52 0.91 0.75 EV + AnyEvent watchers + CoroEV/Any 100000 610 3.49 0.92 0.75 coroutines + Coro::Signal + Perl/Any 16000 654 4.64 1.22 0.77 pure perl implementation + Event/Event 16000 523 28.05 21.38 0.86 Event native interface + Event/Any 16000 943 34.43 20.48 1.39 Event + AnyEvent watchers + Glib/Any 16000 1357 96.99 12.55 55.51 quadratic behaviour + Tk/Any 2000 1855 27.01 66.61 14.03 SEGV with >> 2000 watchers + POE/Event 2000 6644 108.15 768.19 14.33 via POE::Loop::Event + POE/Select 2000 6343 94.69 807.65 562.69 via POE::Loop::Select + +=head2 Discussion + +The benchmark does I measure scalability of the event loop very +well. For example, a select-based event loop (such as the pure perl one) +can never compete with an event loop that uses epoll when the number of +file descriptors grows high. In this benchmark, only a single filehandle +is used (although some of the AnyEvent adaptors dup() its file descriptor +to worka round bugs). + +C is the sole leader regarding speed and memory use, which are both +maximal/minimal, respectively. Even when going through AnyEvent, there is +only one event loop that uses less memory (the C module natively), and +no faster event model, not event C natively. + +The pure perl implementation is hit in a few sweet spots (both the +zero timeout and the use of a single fd hit optimisations in the perl +interpreter and the backend itself). Nevertheless tis shows that it +adds very little overhead in itself. Like any select-based backend its +performance becomes really bad with lots of file descriptors, of course, +but this was not subjetc of this benchmark. + +The C module has a relatively high setup and callback invocation cost, +but overall scores on the third place. + +C's memory usage is quite a bit bit higher, features a faster +callback invocation and overall lands in the same class as C. + +The C adaptor works relatively well, the fact that it crashes with +more than 2000 watchers is a big setback, however, as correctness takes +precedence over speed. Nevertheless, its performance is surprising, as the +file descriptor is dup()ed for each watcher. This shows that the dup() +employed by some adaptors is not a big performance issue (it does incur a +hidden memory cost inside the kernel, though). + +C, regardless of underlying event loop (wether using its pure perl +select-based backend or the Event module) shows abysmal performance and +memory usage: Watchers use almost 30 times as much memory as EV watchers, +and 10 times as much memory as both Event or EV via AnyEvent. Watcher +invocation is almost 700 times slower than with AnyEvent's pure perl +implementation. The design of the POE adaptor class in AnyEvent can not +really account for this, as session creation overhead is small compared +to execution of the state machine, which is coded pretty optimally within +L. POE simply seems to be abysmally slow. + +=head2 Summary + +Using EV through AnyEvent is faster than any other event loop, but most +event loops have acceptable performance with or without AnyEvent. + +The overhead AnyEvent adds is usually much smaller than the overhead of +the actual event loop, only with extremely fast event loops such as the EV +adds Anyevent significant overhead. + +And you should simply avoid POE like the plague if you want performance or +reasonable memory usage. + + =head1 FORK Most event libraries are not fork-safe. The ones who are usually are @@ -846,6 +978,7 @@ If you have to fork, you must either do so I creating your first watcher OR you must not use AnyEvent at all in the child. + =head1 SECURITY CONSIDERATIONS AnyEvent can be forced to load any event model via @@ -862,19 +995,21 @@ use AnyEvent; + =head1 SEE ALSO Event modules: L, L, L, L, L, L, L, L, L, L, -L, L. +L, L, L. Implementations: L, L, L, L, L, L, L, L, -L. +L, L. Nontrivial usage examples: L, L. + =head1 AUTHOR Marc Lehmann