On Mon, Jun 30, 2008 at 10:17 AM, Roger Pack <rogerpack2005 at gmail.com> wrote:> Should I handle it? >Go for it.> Also I think what might be really ideal for helping it with > interoperability with other ruby threads would be a run that just blocks up > to a certain time. Kind of like the timeout value passed to select. > so something like loop.run_once_until s #seconds >Rev already runs Ruby threads explicitly every 10ms while the event loop is running with rb_thread_schedule().> The only reason I even care is that I was writing some specs and wanted to > write a test where it closes asynchronously [faking an incoming connection > that causes it to close]. And realized the difficulty. >This test should work as things are, hopefully.> Ah I see--so it''s pretty good as it is now. So on_connect_failed is like a > hard reset? and on_close a graceful ''soft'' reset? >on_connect_failed is called when you''re making an outgoing connection that never completes. on_close is called once that connection has been established and terminates. Also I don''t actually use this but does rev offer us a connect timeout?>There''s no built-in connect timeout at the moment. It''d be fairly easy to add with a TimerWatcher.> What about a timeout if a socket hasn''t written or read for a long time? > [i.e. EM''s heartbeats--which aren''t even turned on by default, and I don''t > use then, but hey, just wondering]. >Nope. Actually all this stuff is built into Revactor, just not Rev :/ Also I''m still unsure why rev would be necessarily slower than EM. Except> that it returns to Ruby once per loop [of necessity in 1.8.6, for > multi-threaded]. >It depends on the usage pattern. When I was running ruby-prof on Thin on Rev the biggest problem I noticed was the Rev::Watcher#detach method. Right now this is O(n) for n concurrent connections, as it''s using a simple array to track watchers. Switching to a hash would improve behavior. It''d also be possible to make it O(n) by using a "bag" like data structure where the order of the descriptors isn''t preserved. Beyond that, it was just the totality of rb_funcalls needed to process incoming I/O events. One potential optimization is to do a "proactor" IOWatcher in C which performs the I/O for you whenever the descriptor is ready.> I''m not sure of the bottleneck, or difference, if there is one, but if it''s > preserving object for GC marking, I wonder if it''s possible to write A ruby > object that has its own GC mark function so that it can safely mark all > current active watchers. >That''s what Rev::Loop is presently doing. The only reason it *needs* to track associated watchers is so they don''t get GC''d. Making the way this works more efficient would improve Rev''s performance. So this ''redefines'' on_write_complete to call close? Nice. The only> reason I can think of to have a close_after_write function would be if > close_after_write is already defined with useful code that you don''t want to > overwrite. >Yep, that''d be a downside, but AFAIK EM got away with not even having an on_write_complete callback, so I think its potential use cases are limited. I''m using in in Revactor to emulate "blocking" write calls. -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/2f871970/attachment.html>
I guess my confusion was why this spec fails: it "should stop" do loop = Rev::Loop.default stopped = false; @server.attach(loop) Thread.new { loop.run stopped = true } sleep 0 # let it start stopped.should == false loop.stop sleep_until(3) { stopped == true } stopped.should == true end I take it that it never ''returns to ruby'' from its run_once unless it actually processes something? Thanks! -R On Mon, Jun 30, 2008 at 11:55 AM, Roger Pack <rogerpack2005 at gmail.com> wrote:>> >> Ah I see--so it''s pretty good as it is now. So on_connect_failed is like >> a hard reset? and on_close a graceful ''soft'' reset? >> >> on_connect_failed is called when you''re making an outgoing connection that >> never completes. on_close is called once that connection has been >> established and terminates. > > never completes meaning "hard reset"? [TCP reset message usually sent when > you contact a port that''s closed--whatever TCP calls it I can''t remember] > > So there is some ambiguity in the reason for on_close still? It could be > terminated by TCP RESET or by a graceful terminate? Or EPIPE or what not? > [Not that it really matters--and it''s already better than EM''s ambiguous > unbind]. > >> then, but hey, just wondering]. >> I''m not sure of the bottleneck, or difference, if there is one, but if >> it''s preserving object for GC marking, I wonder if it''s possible to write A >> ruby object that has its own GC mark function so that it can safely mark all >> current active watchers. >> >> That''s what Rev::Loop is presently doing. The only reason it *needs* to >> track associated watchers is so they don''t get GC''d. Making the way this >> works more efficient would improve Rev''s performance. > > You could defined a custom gc_mark function that marks your active watchers > during mark and sweep. But if it works currently then why fix what ain''t > broke :) > > Wonder if EM runs into GC problems. > >> Switching to a hash would improve behavior. It''d also be possible to make >> it O(n) by using a "bag" like data structure where the o >> rder of the descriptors isn''t preserved. > > but still O(n), so no huge improvement? > > Also am thinking of starting some FAQ or other. Should I just put it in the > README at the bottom or something? Creating it is easy--putting it > somewhere where it can hopefully stay up to date and actually get used by > people--that is something different. Accessibility. It probably won''t be > much just answers to my own questions. > > Thanks! > > -R >
On Mon, Jun 30, 2008 at 12:05 PM, Roger Pack <rogerpack2005 at gmail.com> wrote:> I guess my confusion was why this spec fails: >Right now Rev::Loop#stop isn''t thread-safe.> I take it that it never ''returns to ruby'' from its run_once unless it > actually processes something? >Yeah, the actual check that will stop the loop isn''t performed until events are actually dispatched. So if there aren''t any events dispatched, the loop won''t stop. Making this work would require some changes to the C code, and mutexes around the @running ivar. -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/39e5ba06/attachment.html>
On Jun 30, 2008, at 12:31 PM, Tony Arcieri wrote:> On Mon, Jun 30, 2008 at 12:05 PM, Roger Pack > <rogerpack2005 at gmail.com> wrote: > I guess my confusion was why this spec fails: > > Right now Rev::Loop#stop isn''t thread-safe. > > I take it that it never ''returns to ruby'' from its run_once unless it > actually processes something? > > Yeah, the actual check that will stop the loop isn''t performed until > events are actually dispatched. So if there aren''t any events > dispatched, the loop won''t stop. > > Making this work would require some changes to the C code, and > mutexes around the @running ivar.Hopefully the C code stuff would be enough :) I guess EM could run into the same type of thing [something in the reactor could call stop, while some other thread calls stop, and EM stops and restarts before the other thread calls stop--or something pathological like that] but it doesn''t seem to be a big problem. Another way would be to push the @running var into the C code. Since Ruby will only be running one thread at a time, a function that sets it in C is like atomic. The way rev currently runs currently [not going back to ruby unless necessary] is probably far faster cpu-wise, and if I need instant stop access, I could always add a loop break reader. Anyway it''s not too high prio, just confusing. I''ll make a note of it in the faq :) I can see that rev is more of a core eventer, not as fleshed out as EM or revactor. But hopefully with fewer bugs [ugh]. I almost wonder if that rb_thread_schedule call makes it less efficient if it''s single threaded--I assume not? Also I assume that in Ruby 1.9 the global lock is release during the select calls so that it can be true multi-threaded? [at least I think that''s how it [should] work--does that make sense?] -R -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/701bf8e1/attachment-0001.html>
On Mon, Jun 30, 2008 at 1:08 PM, Roger Pack <rogerpack2005 at gmail.com> wrote:> Another way would be to push the @running var into the C code. Since Ruby > will only be running one thread at a time, a function that sets it in C is > like atomic. >Except Ruby 1.9 uses multiple threads, so it''d still need a mutex in C code for that case. Also, it''d need to "wake up" the thread making the blocking call, as it''d be sleeping in a system call.> The way rev currently runs currently [not going back to ruby unless > necessary] is probably far faster cpu-wise, and if I need instant stop > access, I could always add a loop break reader. >There''s an AsyncWatcher type which allows you to signal a loop and wake it up. That''s how a stop function would probably have to be implemented: http://rev.rubyforge.org/rdoc/classes/Rev/AsyncWatcher.html> I can see that rev is more of a core eventer, not as fleshed out as EM or > revactor. But hopefully with fewer bugs [ugh]. >Yeah, right now Rev isn''t the everything-and-the-kitchen-sink type framework EventMachine is. There''s certainly bugs, but as the majority of the code is in Ruby instead of C/C++ they should be easier to locate and fix.> I almost wonder if that rb_thread_schedule call makes it less efficient if > it''s single threaded--I assume not? >It does slow things down, although right now that''s nowhere close to the main performance bottleneck. For high performance on Ruby 1.8 Rev would really need to take over the duties of rb_thread_schedule(). This would allow it to make system calls that block indefinitely in the event no threads are runnable.> Also I assume that in Ruby 1.9 the global lock is release during the select > calls so that it can be true multi-threaded? >Yep, on Ruby 1.9 Rev uses the rb_thread_blocking_region() function to make syscalls that block indefinitely. -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/b58b18e0/attachment.html>
On Jun 30, 2008, at 1:19 PM, Tony Arcieri wrote:> On Mon, Jun 30, 2008 at 1:08 PM, Roger Pack > <rogerpack2005 at gmail.com> wrote: > Another way would be to push the @running var into the C code. > Since Ruby will only be running one thread at a time, a function > that sets it in C is like atomic. > > Except Ruby 1.9 uses multiple threads, so it''d still need a mutex in > C code for that case. Also, it''d need to "wake up" the thread > making the blocking call, as it''d be sleeping in a system call.Ahh so in 1.9 does it select for longer? Or is it either a loopbreak reader or wait 10ms? :) If @running is within a region bounded by the global thread lock would it be like ''atomic''?> > > The way rev currently runs currently [not going back to ruby unless > necessary] is probably far faster cpu-wise, and if I need instant > stop access, I could always add a loop break reader. > > There''s an AsyncWatcher type which allows you to signal a loop and > wake it up. That''s how a stop function would probably have to be > implemented: > > http://rev.rubyforge.org/rdoc/classes/Rev/AsyncWatcher.htmlI see so asynchwatcher is essentially a loop break reader. I wonder if you can actually send it an empty packet for its ''touch'' :)> > I can see that rev is more of a core eventer, not as fleshed out as > EM or revactor. But hopefully with fewer bugs [ugh]. > > Yeah, right now Rev isn''t the everything-and-the-kitchen-sink type > framework EventMachine is. There''s certainly bugs, but as the > majority of the code is in Ruby instead of C/C++ they should be > easier to locate and fix. > > I almost wonder if that rb_thread_schedule call makes it less > efficient if it''s single threaded--I assume not? > > It does slow things down, although right now that''s nowhere close to > the main performance bottleneck. For high performance on Ruby 1.8 > Rev would really need to take over the duties of > rb_thread_schedule(). This would allow it to make system calls that > block indefinitely in the event no threads are runnable.Yeah going after bottlenecks is probably a better idea than fine tuning. Lol.> > Also I assume that in Ruby 1.9 the global lock is release during the > select calls so that it can be true multi-threaded? > > Yep, on Ruby 1.9 Rev uses the rb_thread_blocking_region() function > to make syscalls that block indefinitely.so not 10ms? Thanks! -R -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/bd8f3cc2/attachment.html>
On Mon, Jun 30, 2008 at 1:27 PM, Roger Pack <rogerpack2005 at gmail.com> wrote:> Ahh so in 1.9 does it select for longer? Or is it either a loopbreak > reader or wait 10ms? :) >With Ruby 1.9 it can block idefinitely, so there''s nothing breaking the loop to scheduler Ruby threads. It just sits and blocks until one of the descriptors becomes ready. Much more efficient than 1.8, to the point that Rev was originally outperforming EventMachine on 1.9 (but that was before EM started using rb_thread_blocking_region too) so not 10ms?>The 10ms thing is only on Ruby 1.8.> If @running is within a region bounded by the global thread lock would it > be like ''atomic''? >Hard to say, you could probably depend on the GVL to be a mutex for it in 1.9, but not in 1.8. It seems to me like the best approach is to wrap it in a Mutex and be done with it.> I see so asynchwatcher is essentially a loop break reader. >Yep, AsyncWatcher is designed to let one thread (be it a 1.8 green thread or a 1.9 native thread) wake up another one and execute the specified callback.> I wonder if you can actually send it an empty packet for its ''touch'' :) >Not really sure what you mean... -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/10f0b3ee/attachment.html>
> Yep, AsyncWatcher is designed to let one thread (be it a 1.8 green > thread or a 1.9 native thread) wake up another one and execute the > specified callback. > > I wonder if you can actually send it an empty packet for its > ''touch'' :) > > Not really sure what you mean...Currently it runs its loopbreaker by sending "\0" -- I was just tongue in cheek wondering if it could send "" :) -R
Tony Arcieri <tony at medioh.com> wrote:> On Mon, Jun 30, 2008 at 1:27 PM, Roger Pack <rogerpack2005 at gmail.com> wrote: >> >> Ahh so in 1.9 does it select for longer? Or is it either a loopbreak >> reader or wait 10ms? :) > > With Ruby 1.9 it can block idefinitely, so there''s nothing breaking the loop > to scheduler Ruby threads. It just sits and blocks until one of the > descriptors becomes ready.Nice. Way to be efficient :) The only reason I can think of for NOT wanting to block indefinitely [in EM''s case] is to check if connect timeouts have occurred, or ''idle timeouts'' [heartbeats]. I don''t even use those, and they''re easily configurable with watchers.
On Mon, Jun 30, 2008 at 2:25 PM, Roger Pack <rogerpack2005 at gmail.com> wrote:> Nice. Way to be efficient :) > The only reason I can think of for NOT wanting to block indefinitely > [in EM''s case] is to check if connect timeouts have occurred, or ''idle > timeouts'' [heartbeats]. I don''t even use those, and they''re easily > configurable with watchers. >Yep, TimerWatchers let you break out of the loop at configurable intervals, and can be used to implement connection timeouts. There''s other watchers that libev implements but Rev does not presently wrap as well, like ev_stat watchers that can be used to monitor filesystem events. Seems useful for things like autotest that monitor the filesystem for changes. -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080630/24dade27/attachment.html>