[net.bugs.uucp] Satellite delays slow UUCP: the 4.3 `select's

chris@umcp-cs.UUCP (Chris Torek) (05/12/86)

In article <3367@mnetor> clewis%mnetor@mnetor.UUCP writes:
>Further, I believe BSD uucp's use "select" with timers to do their
>reads - the receiver goes back into a "select" to read the packet,
>and only if the select times out does it actually send an acknowledge
>for a packet it has already received.

Not quite.  The select() to which you refer is no doubt my own
addition.  Someone (I cannot recall who, if ever I knew) discovered
that at 300 and 1200 baud, uucico was causing an inordinate number
of context switches, slowing down the machine for everyone.  The
cause was determined to be in pkcget():  It would try to read() 64
characters, receive about 10, try for another 54, get 6, try for
48, get 15, ..., and in the process make many essentially useless
system calls and cause all those context switches.

The System III style tty driver has a relatively clean way of fixing
this: one asks the kernel to return from a read() only after a
minimum number of input characters, or minimum time delay, whichever
occurs first.  (The details of this mechanism are irrelevant here,
but I do wish to mention that they were either incorrectly or
misleadingly documented at one time---this is apparent from the
number of times I have seen answers---*differing* answers---to
questions about the actual workings of VMIN and VTIME.  I do not
know whether this has been rectified.)

At any rate, us poor 4BSD folks :-) were stuck with a lesser
solution.  Instead of having the kernel do all our work for us, we
had to fix it in user code.  Clearly this kind of thing is appropriate
for kernels, and if you believe that, I have an ISAM file system
for sale.  (Just to forestall any askers: no, no, I was only kidding!
Please do not ask me for my ISAM file system; I do not have one.)

The original 4.1BSD solution was something along these lines:

	/* linebaudrate==0 -> unknown */
	if (linebaudrate > 0 && linebaudrate < 2400 && nleft > 50)
		sleep(1);

This has the desired affect of allowing the full packet to dribble
in, but tends to introduce ACK delays, especially at 1200 baud.
The granulatity in sleep() is simply too large.  With 4.2, however,
came the ability to generate sub-second sleeps, and I decided to
put this to use.

Now, the `right' amount of time to wait can be determined directly
from the number of characters needed and the baud rate:  If you
need <n> characters, that will take 10*<n>/<baud> seconds to dribble
in over a serial link.  Unfortunately, this simple rule tends to
fail for a number of reasons, the largest being delays between one
read() system call and the next.

What I did was to assume that the each time pkcget() was called,
about 1/10th of one second had passed since the previous call.  I
then computed the remaining time until <n> characters could be
expected to have been received by the kernel.  If this time was at
least 1/50th of one second, I used a select() system call to wait
exactly this long.  (Select() is both simpler and more efficient
than using ITIMER_REAL and alarms.)  If the following read() did
not receive the expected <n> characters, I tried the whole thing
again, but this time I assumed that no time had passed since the
last pkcget().

The 1/50th of a second comes from knowing that the actual select()
delay granularity is 1/100th of a second, and from making a very
pessimistic estimate of the overhead of two context switches (out
of, and in 10 milliseconds, back into, uucico).  If the machine is
heavily loaded, perhaps that is not such a pessimistic estimate
after all.  At any rate, it seems to work.

The 1/10th second `guess' was simply a guess, but it too seems to
work well in practice: with some extra debugging, I determined that
the select() delays usually resulted in a full <n> characters, but
sometimes were too short, with an extra four or five needed to fill
the packet.  The too-short delays were rare enough that I figured
decreasing the between-pkcget()-delay-guess would likely slow down
ACKs somewhat; and I was willing to trade the remaining bit of CPU
load for shorter-duration phone calls.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1415)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu