From: Raul Parolari on
I am using Ruby (as a prototype version) to communicate with a network
of solar cells (driven by firmware), over Udp. It works most of the time
perfectly (delivering messages with 1-5 milliseconds precision, even
beyond what we need).

But once in a while, this happens (ubuntu machine) while waiting the
response (from solar cells):

result = select(( [ comm ], nil, [ comm ], 0.050))

if result.nil?
# handle 50 msec timeout
else
# data
end

All is perfect for several thousands of messages, until this: we receive
data (in the "else" branch) 5 seconds later; so, the select remained
blocked for 5 seconds without signaling the 50 msec timeout.

I controlled the Api (even going back even to Comer & Stevens books, as
the system calls map to the C ones), and I think that the code (I only
show a small part above) is correct.
Finally, I concluded that the garbage collector must be entering in
action and for a few seconds (that usually are very close to 5)
everything stops in Ruby.

We were planning to port this area to C++ in any case; but at a certain
moment the performance results were so accurate that we thought to keep
Ruby even for communication (as it allows, using a bit of
metaprogramming, to read on the fly configuration files, in other words
all that we love with Ruby, etc).

If anyone has insight on this, let me know.

(Please, only avoid answers like "if you want real time, use C, not
Ruby!"; we know that. But the point is that Ruby was a magnificent
surprise in this area, aside from what described above, and I just
wonder if there is any thought or insight in this area).

Raul Parolari
--
Posted via http://www.ruby-forum.com/.

From: Roger Pack on
> All is perfect for several thousands of messages, until this: we receive
> data (in the "else" branch) 5 seconds later; so, the select remained
> blocked for 5 seconds without signaling the 50 msec timeout.

Maybe it is doing DNS lookup. You could try
BasicSocket.do_not_reverse_lookup=true

-rp
--
Posted via http://www.ruby-forum.com/.

From: Caleb Clausen on
On 4/25/10, Raul Parolari <raulparolari(a)gmail.com> wrote:
> But once in a while, this happens (ubuntu machine) while waiting the
> response (from solar cells):
>
> result = select(( [ comm ], nil, [ comm ], 0.050))
>
> if result.nil?
> # handle 50 msec timeout
> else
> # data
> end
>
> All is perfect for several thousands of messages, until this: we receive
> data (in the "else" branch) 5 seconds later; so, the select remained
> blocked for 5 seconds without signaling the 50 msec timeout.
>
> I controlled the Api (even going back even to Comer & Stevens books, as
> the system calls map to the C ones), and I think that the code (I only
> show a small part above) is correct.
> Finally, I concluded that the garbage collector must be entering in
> action and for a few seconds (that usually are very close to 5)
> everything stops in Ruby.

I also suspect GC is your issue here. You could try to reduce the
latency cost of GC by forcing GC to happen every time thru the main
loop.... This will reduce the tme it takes for any individual GC cycle
by increasing the total amount of time spent in GC. You might also try
reducing the amount of garbage (and for that matter non-garbage)
objects which your program creates.

From: Raul Parolari on
Caleb Clausen wrote:
> On 4/25/10, Raul Parolari <raulparolari(a)gmail.com> wrote:
>>
>> All is perfect for several thousands of messages, until this: we receive
>> data (in the "else" branch) 5 seconds later; so, the select remained
>> blocked for 5 seconds without signaling the 50 msec timeout.
>>..
>> Finally, I concluded that the garbage collector must be entering in
>> action and for a few seconds (that usually are very close to 5)
>> everything stops in Ruby.
>
> I also suspect GC is your issue here. You could try to reduce the
> latency cost of GC by forcing GC to happen every time thru the main
> loop.... This will reduce the tme it takes for any individual GC cycle
> by increasing the total amount of time spent in GC. You might also try
> reducing the amount of garbage (and for that matter non-garbage)
> objects which your program creates.

Thanks Caleb

can you point out a link to how to do that (making GC to happen every
time?); I found pages which mention setting Ruby Constants, but let me
know what is the best page if you have the chance.

Regarding reducing amount of garbage, it is a good tip (that I had began
to apply); coming from compiled languages, I tend to use a variable for
each "entity", so that the final computation looks like a clear
mathematical formula (instead of those 140 characters lines that I see
all over in Rails which compute everything right there on the line. I
begin to understand why they may be doing it.. although I wonder what it
must be maintaining such a monstrous code. Hopefully, there is a good
compromise).

Thanks very much for the suggestions

Raul
--
Posted via http://www.ruby-forum.com/.

From: Roger Pack on

> I also suspect GC is your issue here. You could try to reduce the
> latency cost of GC by forcing GC to happen every time thru the main
> loop.... This will reduce the tme it takes for any individual GC cycle
> by increasing the total amount of time spent in GC. You might also try
> reducing the amount of garbage (and for that matter non-garbage)
> objects which your program creates.

If you're looking to reduce jitter, you could use jruby which has a
tunable GC.

http://wiki.github.com/rdp/ruby_tutorials_core/gc

GL.
-rp


--
Posted via http://www.ruby-forum.com/.