Lots of concurrent IO.

Lex Spoon lex at cc.gatech.edu
Wed Aug 15 13:16:58 UTC 2001


> You only cover the input side of things, but the output side is almost as
> important. I'd like to have my code block on the sockets, rather than
> busywait because I don't want the UI slowdown and squeak always using 100%
> CPU and slow the rest of the machine down.

This can be solved, too: simply *limit* your polling to 100 polls per
second.  That's precisely what Morphic does to avoid using 100% CPU
while idle.



> 
> > Those arguments aside, here are the numbers.  I just checked, and my
> > modest 366 MHz computer can do 95,000 #dataAvailable's per second on a
> > socket that is open but idle.  That's 95 checks per millisecond, and 950
> > times as fast as the 10 millisecond threshold mentioned above.  Thus, on
> > a completely idle system, you check 950 sockets 100 times per second.
> 
> These numbers are superb; I hadn't realized they were quite this good..
> But at, say, 1-3 commands/sec/socket, say, 500 sockets polled at 10ms,
> thats 50,000 polls/sec, of which only about 500-1500 will have any data.
> So, I'm spending about half of that CPU polling, and half constructing a
> Then add in the time and polling for output.. :/


Hmm.  Yes, 50% is being used to poll for input in this extreme case. 
But it *is* the extreme case!  It's a large number of connections, with
a not-too-fast computer, where you are expecting very few active sockets
but for those sockets to consume a lot of CPU.

Also, #dataAvailable hasn't been optimized at all.  Currently it is
making a system call into the kernel (this was on Linux, by the way),
but probably it could be improved to cache the results if nothing has
changed about the socket.  In fact, it might be worth revisiting the
whole VM<->image network interface with a mind to servers -- the current
setup is really optimized, it seems, for clients that have a single
socket open and which have nothing to do while waiting for the socket to
become active.



You mentioned also that you are worried about output as well as input. 
This only matters for backlogged sockets, though.  Again, this depends
on your server, but in a lot of cases output will usually be consumed
immediately into the kernel's buffer; typically a kernel will hold a few
tens of kilobytes for you before write()  (and thus #sendSomeData:)
starts to fail.  (Well, I say "typically".  This is what I've observed
on Linux....)



> > >
> > > My problem:
> > >    I can't get the reader process to block. If I use
> > >   Socket>>waitForDataUntil: (Socket deadlineSecs: 60)
> >
> > This will wait for 60 seconds, but it really should return early if data
> > arrives.  Can you make a small example that causes this problem?
> >
> 
> I can describe what circumstances it happens:

Okay, I'm going to have to play with this.  It really shouldn't happen. 
:(


> But it seems like squeak implements this waitForDataUntil internally as
> being a busywait loop anyways.. Oh well.

Actually, there's a semaphore wait buried in the loop somewhere.  It's
just that the semaphore getting signalled isn't a guarantee that any
particular event has happened, and so the code must query the socket
after the semaphore is signalled.

In fact, if you don't mind devoting a thread to each socket, then you
can do a "wait" in each thread and achive your 0 polling goal.  You
could even single-thread things again after the waits by having a
message queue (SharedQueue in Squeak) with active sockets, which is
queried from a main thread.

I agree that a "poll *all* of these sockets" primitive would be handy,
by the way.


> > In fact, after reading all of this, maybe just using StringSocket is
> > sounding like a reasonable approach.
> 
> I'll check it out, now if only it had documentation..

Doh!  Well, in a nutshell:

	sock := StringSocket on: realSocket   "create a string socket"

	sock nextPut: #('hello' 'there')    "enqueue a string array"
	sock nextOrNil		"retrieve the next string from the queue, if there is
one"
	sock next		"retrieve the next string -- it's an error to send this if
there isn't one!"
	sock processIO	"send data to/from the underlying socket; should be
called periodically"


The main design problems using StringSocket are:

	1. Converting your packets to and from arrays of strings.  (This is
easier, it seems to me, than converting all the way to a single string.)
 This is the most painful and time-consuming part of all the little
network programs I've written in Squeak.

	2. Finding a place to call processIO and to poll #nextOrNil.


Lex Spoon




More information about the Squeak-dev mailing list