[mod.sources] speedup for bm on some machines

sources-request@panda.UUCP (03/15/86)

Mod.sources:  Volume 4, Issue 32
Submitted by: genrad!decvax!utzoo!henry (Henry Spencer)

On some machines with some Unix implementations (PDP11 running V7 for
example, but there probably are others), bulk data copying from system
to user space which is not aligned on word boundaries is a terrible
performance disaster.  Bm, Peter Bain's Boyer-Moore grep program, suffers
from this.  Fortunately, it's easy to fix:

1. In line 43 of Execute.c (this is for bm version 1.2, recently posted),
	change "read" to "xread".

2. Add the following source file, xread.c, to the compilation.

This code could probably be improved a bit, but as it is it makes a
difference of a factor of 4 (!) in bm's performance on utzoo.

				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

P.S. I've thrown in a quickie version of bcopy() for people who don't have it.

----------
/*
 * Fast-read routine.  Tries to do read(2)s at block boundaries on disk, and
 * always does them at word boundaries in core.
 *
 * This code assumes that BUFSIZ is reasonable for internal buffering and
 * that one can test a pointer for alignment by casting to int and ANDing
 * with (sizeof(int)-1).
 */

#include <stdio.h>

static char xbuf[BUFSIZ];
static int xleft = 0;
static char *xrest = NULL;

int
xread(desc, buf, len)
int desc;
char *buf;
int len;
{
	register int todo;
	register int n;
	char *place;
	int ndone;
	register int ret;

	ndone = 0;
	place = buf;
	todo = len;

	while (todo > 0) {
		if (xleft > 0) {
			/* Data available in our internal buffer. */
			n = (xleft > todo) ? todo : xleft;
			bcopy(xrest, place, n);
			todo -= n;
			xleft -= n;
			xrest += n;
			ndone += n;
			place += n;
		} else if (todo >= BUFSIZ && (((int)place)&(sizeof(int)-1)) == 0) {
			/* Conditions suitable for a direct read. */
			n = todo / BUFSIZ;
			ret = read(desc, place, n*BUFSIZ);
			if (ret < 0)
				return(ret);
			if (ret == 0)
				return(ndone);
			ndone += ret;
			place += ret;
			todo -= ret;
		} else {
			/* None of the above, refill the internal buffer. */
			ret = read(desc, xbuf, BUFSIZ);
			if (ret < 0)
				return(ret);
			if (ret == 0)
				return(ndone);
			xleft = ret;
			xrest = xbuf;
		}
	}
	return(ndone);
}
----------
/*
 * bcopy - copy n bytes from a to b
 */

bcopy(a, b, n)
char *a;
char *b;
int n;
{
	register char *from;
	register char *to;
	register int count;

	from = a;
	to = b;
	count = n;

	while (--count >= 0)
		*to++ = *from++;
}
----------