Local interprocess communication ideas


#1

I am currently developing a simple controller. It consists of a GUI
(C++) and a controller (ruby) that talks to a serial port.

Now, I understand that this can (or maybe should) be combined into a
single app that communicated directly with the serial port. However,
I wouldn’t have the opportunity to ask this question if that were the
case!

So, I have an embedded ARM proc with about 200MHz, and I want this app
to feel as responsive as possible. The GUI and controller will both
run on this machine. When a button on the GUI is pressed, the command
is sent to the controller, the controller sends a command out of the
serial port, and an action is taken.

Let’s assume that all parts not including the IPC between the GUI and
the controller are working fine. My question deals with the local IPC
between the GUI and the controller.

I really like XML/RPC. It is really easy and straightforward in Ruby,
and has worked really well in the past for network-based distributable
apps. However, in this case I can see how the overhead of XML and
“IP” communication might make the app feel too slow (It would be bound
to localhost, of course).

I would really like to use a standard protocol, preferably one
natively implemented in ruby already. I just need it to be fast…

So, with all of that info, what does the community recommend for a
lightening fast interprocess communication method?

Feel free to tell me that XML/RPC is fast enough, if it is…

Thanks!

~james


#2

On Jan 17, 2007, at 17:30, James Mills wrote:

So, I have an embedded ARM proc with about 200MHz, and I want this app
to feel as responsive as possible. The GUI and controller will both
run on this machine. When a button on the GUI is pressed, the command
is sent to the controller, the controller sends a command out of the
serial port, and an action is taken.

How responsive are we talking about here? Do you need “twitch” video
game type responsiveness (tens of ms) or something less? Unless you
need twitch video game responsiveness, I’m pretty sure anything over
the local loopback would be fast enough. I’ve written CGIs that ran
on the webserver of an ARM-based embedded device, and despite the
overhead of a real network between me and them, they seemed very
responsive.

If you need tens-of-ms type responsiveness, you might want to use
some shared memory. This couldn’t be done natively in Ruby, but it
would be pretty easy to write some simple C, write a Ruby extension,
and use it that way.

Keep in mind that in my experience, you’ll never be able to get any
better than say 20ms responsiveness, since that’s the task-switching
overhead inherent in using Linux (and I assume other OSes would be
similar). You could get faster by writing kernel extensions, but
that’s even further from a pure Ruby implementation.

Ben


#3

On 2007/01/17, at 23:06, Ben G. wrote:

On Jan 17, 2007, at 17:30, James Mills wrote:

So, I have an embedded ARM proc with about 200MHz, and I want this
app to feel as responsive as possible.

I’ve written CGIs that ran on the webserver of an ARM-based
embedded device, and despite the overhead of a real network
between me and them, they seemed very responsive.

Be lazy! Write a XML/RPC version (if you think it’s not a lot of
work), and only think about more “complicated” IPC if it’s not
enough. You can always blame Ben G. or me! =P

Paulo Jorge Duarte
Köremoved_email_address@domain.invalid


#4

On Jan 18, 2007, at 12:06 AM, ian dacek wrote:

James Mills wrote:

So, with all of that info, what does the community recommend for a
lightening fast interprocess communication method?

Depending on the size of your messages, why not use UDP and your
own simple message format? You’d eliminate the overhead of TCP, not
to mention the bloat of XML. You could send the data for the serial
port with a header or Ruby code prepended, then interpret the
header or eval the code…

The TCP overhead is there for a purpose. UDP is an unreliable
protocol. Packets may get dropped, duplicated, or reordered. If
your application is OK with that, great, but if not then you are
going spend a lot of time designing what basically amounts to TCP
(sequence numbers, retransmission strategies, and so on).

Gary W. (Radar)


#5

James Mills wrote:

run on this machine. When a button on the GUI is pressed, the command
“IP” communication might make the app feel too slow (It would be bound
Thanks!

~james

what OS?


#6

removed_email_address@domain.invalid wrote:

with a header or Ruby code prepended, then interpret the header or
eval the code…

The TCP overhead is there for a purpose. UDP is an unreliable
protocol. Packets may get dropped, duplicated, or reordered. If your
application is OK with that, great, but if not then you are going
spend a lot of time designing what basically amounts to TCP (sequence
numbers, retransmission strategies, and so on).
That’s generally true of UDP, especially between two remote hosts
bridged by a router.

However, going between two ports on the localhost should actually net
something along the lines of a memory copy, depending on the
behind-the-scenes networking implementation.

-ian


#7

James Mills wrote:

So, with all of that info, what does the community recommend for a
lightening fast interprocess communication method?

Depending on the size of your messages, why not use UDP and your own
simple message format? You’d eliminate the overhead of TCP, not to
mention the bloat of XML. You could send the data for the serial port
with a header or Ruby code prepended, then interpret the header or eval
the code…

-ian


#8

On Jan 18, 2007, at 8:14 PM, ian dacek wrote:

That’s generally true of UDP, especially between two remote hosts
bridged by a router.

Memory allocation/starvation issues can cause lost UDP packets even
to/from a single host. I’ll bet there are other possibilities. It is
just a bad starting point to make the assumption that it will be
reliable in your particular circumstance. Of course there are
circumstance in which in will work anyway.

If you know it is to/from the same host then Unix domain sockets
might be an option.

In any case, I just wanted everyone reading that thread to be aware
of the caveats of UDP-based protocols.

Gary W.


#9

Thanks to everyone who had ideas on this one. I love mailing lists.

I ended up using popen3 to launch the GUI from within the ruby code.
I created a listening thread on the stdout handle, and acted upon
anything that came in. This has several advantages for this project.

  • The GUI is really dumb. All it does is generate a three-letter
    message to stdout when a button is pressed or released.

  • All of the prep code and routines needed to set up the serial port
    comms and other prop data can be done before the GUI is launched.

  • The GUI could be tested independently from the ruby portion. This
    was good since it was developed remotely.

In this scenario, popen3 was perfect! It was really fast, and it is
built in.

Thanks again!

~james