[comp.unix.xenix] Serial I/O performance under Unix on the AT, some thoughts and ideas

karl@sugar.UUCP (Karl Lehenbauer) (10/30/87)

I have an 8-MHz AT clone with 5 MB RAM and a Digicomm Digiboard 8 eight-port 
serial I/O board.  It runs Microport Unix System V/AT 2.2U.  The inability of
System V/AT to handle much high-speed input and it's tendency to hang ports
or crash on hangups during I/O has been well documented and much discussed
on the net.  In this posting I will enumerate several thoughts I've had on 
the subject of speeding up serial I/O.  This will include a simple algorithm 
for a very fast character queue that I haven't seen before.

First, it appears that following the standard method of using ttypatch results
in the V/AT driver looking at all the UARTs configured to use that interrupt.
The Digiboard 8 (and I presume others) has a status register that returns a
mask showing which UARTs have interrupts pending, one UART per bit.  If the
V/AT (or one provided by Digiboard or someone else) driver examined that 
register, it would consume less overhead during interrupt processing than 
looking at each UART's status register to determine its interrupt status.

Digiboard (and again, I presume others) owners can configure the board on a
port-by-port basis as to address and particularly, interrupt.  Assuming the
V/AT driver looks only at UARTs ttypatch'ed to be on the interrupt received
and not at all UARTs every serial interrupt, splitting four ports to COM1
and four to COM2 (or whatever) reduces interrupt processing overhead.  Also,
if the above condition is true, users with one really fast line (uucp to
direct machine or very high speed modem) may instead wish to give that line
its own interrupt.

To anyone who will respond "buy a smart board":  I can't afford a smart
board.  I already have a dumb board, and it still costs over $500.

To Microport or any other driver writer:  Please consider hacking it out in
assembly.  It's a critical performance area, particularly on the AT since
its performance is marginal.

Also to Microport:  I suppose you consider the source to your AT serial
driver to be really really proprietary.  I presume it was one of the bigger
pieces of code you had to write yourselves.  I request though, if you could,
that you post the source.  Then, many hackers will take a crack at speeding
it up (like the aforementioned Digiboard status register stuff) and they'll 
do so for free.  I would like to have a crack at it, but without a sample
to work from, the job is much harder.

Here is an idea for a real fast character queue.  This example is for one port 
only, i.e. no indirection based on minor device number...for example purposes 
only:

Fast character queue:

There are two buffers.  Each buffer can contain many characters, probably
a few hundred.  The writer owns one of the buffers and writes serially into
it.  The reader reads from the other buffer and, when it's exhausted,
swaps it's buffer for the writer's buffer (if there's any data in the
writers buffer).  If the writer's buffer overflows, it's a buffer overflow -
no attempt is made to switch to the reader's buffer.  To have the same 
number of characters buffered as with a standard circular queue, each of
the buffers would have to contain as many characters as the standard circular
queue, thus more memory, but in this era it's not much of a consideration.

#define QSIZE 512	/* number of characters in each queue */

int windex;	/* 0-relative writer's index */
int rindex;	/* 0-relative reader's index */

int lastbyte;	/* last byte (0-relative) of data in reader's queue */

char *wbp, *rbp, *tmpp;	/* writer's and reader's and temp buffer pointers */

init() 
{
	wbp = &buffer_a[0];	/* write buffer pointer gets one buffer */
	rbp = &buffer_b[0];	/* read buffer pointer gets the other */
	rindex = windex = 0;	/* set indexes to zero, no data in bufs */
}

wq(c)		/* write a character into the queue */
char c;
{
	get(writelock);		/* semaphore lock for writer's buf and vars */
	if (windex > QSIZE)
		overflow;
	wbp[windex++] = c;	/* write the char into the writer's buffer */
	release(writelock);
}

int rq()	/* read a character from the queue */
{
	if (rindex < lastbyte)	/* there's data in the read buffer */
		return(rbp[rindex++]);	/* return the next byte */
	get(writelock);
				/* There's no data in the read buffer, */
	if (windex == 0)	/* Is there data in write buffer? */
	{
		release(writelock);	/* no, blow out */
		return empty;
	}
	tmpp = wbp;		/* yes, swap reader's and writer's buffers */
	wbp = rbp;
	lastbyte = windex;	/* get n chars written in for reader */
	windex = 0;		/* set writer's index to 0 for new buf */
	release(writelock);
	rindex = 1;		/* set reader to the second char, we're
				 * returning the first one */
	rbp = tmpp;		/* finish swap outside of the lock for speed */
	return(rbp[0]);
}

The advantage over the usual circular queue is the algorithm doesn't have to
do the usual "if ((inp + 1) mod QSIZE == outp" business; that is, it
doesn't have to handle rolling around the end of the queue.  

A multibyte read would be a useful hack for speed improvement, as well.
Very large buffers (several K bytes) might buy some breathing room.

Note that this algorithm, because of its simplicity, is well suited for 
implementation in assembly languangua

greg@xios.XIOS.UUCP (Greg Franks) (11/06/87)

In article <943@sugar.UUCP> karl@sugar.UUCP (Karl Lehenbauer) writes
about how to do a tty driver, multiport cards etc.

Multiport cards: the one we have (Bell Tech HUB), comes with its own
driver.  I don't think that uport's tty drivers handle many multiport
cards (they are all different...). 

Re assembly code to buffer the characters: they already do it in the
standard drivers.  It is still too slow at times.  And yes, they have
special buffers.  Remember: any driver (including sio) that sits at spl7
toooooo long kills the uarts. 

Hopefully, version 2.3 will fix all this - we're waiting with baited
breath for our copies to arrive!
-- 
Greg Franks             XIOS Systems Corporation, 1600 Carling Avenue,
(613) 725-5411          Ottawa, Ontario, Canada, K1Z 8R8
uunet!mnetor!dciem!nrcaer!xios!greg    "There's so much to sea in Nova Scotia"