2.8 on the 11/34

utzoo!decvax!cca!sri-unix!cbosgd!cbosg!ihnss!ucbvax!ucsfcgl!sdcarl!sdcattb!sdcsvax!phonlab!donn utzoo!decvax!cca!sri-unix!cbosgd!cbosg!ihnss!ucbvax!ucsfcgl!sdcarl!sdcattb!sdcsvax!phonlab!donn
Tue Mar 9 03:50:07 AEST 1982


Hello.  I'm a novice kernel hacker who has taken on the job of
getting Berkeley 2.8 Unix running on a pair of PDP11/34s and I
have some technical questions about Unix's innards and 11/34
hardware.  If you think small 11s are boring then feel free to
skip to the next message...

1) Speed.  We are using one of our 11s as a single-user system to
which we've attached an Evans & Sutherland Picture System II
graphics unit.  We have molecular modelling software for the PS2
that was developed under Version 6 and it seems to run fine under
V7, except that actual display manipulation runs some 5-10%
slower under V7 than under V6.  (Thanks to Berkeley's big disk
blocks, database manipulation runs 10-45% faster.) I'm curious
about where the lost time has gone and what can be done about it.
One of the first things I noticed about Berkeley 2.8 is that
large 11s benefit from an "ed" script that turns calls to the
priority level functions "spl[0-7]" in the assembler output of
the kernel C compilation into actual SPL instructions.  While the
11/34 has no SPL instruction, it can set priority with MFPS and
MTPS, instructions which are equivalent to a MOV with a source
(resp. destination) of the low byte of the processor status word.
>From my reading of the DEC Processor Handbook for PDP's, it
appears that a call to one of the "spl" routines should take some
25-30 mu-sec, whereas a corresponding MFPS and/or MTPS takes 4-7
mu-sec, a substantial saving.  There are lots and lots of calls
to these functions, too; in the source for our currently config-
ured kernel I counted well over 100.  I wrote a little C program
that takes "spl[0-7]" and "splx" calls in assembly language and
intelligently turns them into MFPS and MTPS instructions
(incidentally producing a net small saving in space).  The kernel
I get from this post-processing boots and seems to run all right
(which is to say I booted it once and ran "fsck" with no ill
effects, but was too nervous to persevere).  Has anyone out there
tried this already, or does anyone care to venture an opinion
about whether this is both safe and more efficient?  I'm a little
suspicious of this change because if it works, why wasn't it done
before?

2) Time.  I noticed that one difference from V6 in 2.8 is that
the priority of the clock routine in "clock.c" is (redundantly)
set to level 6 just before performing callouts, while in V6 it
gets set to level 5.  I assume that this is done to block clock
interrupts, since I can't find anything else that interrupts at
that high a priority.  The V6 code is written to be re-entrant,
so that a clock interrupt can occur while a previous clock inter-
rupt is still being serviced, with no harm done (as far as I can
tell).  Berkeley 2.8 V7 locks out clock interrupts, except at
"lightning bolt" time after load metering is done.  Thus a pretty
large amount of code is executed at level 6 at certain times: I
can visualize a clock interrupt being lost when (say) some code
somewhere else in the kernel sets priority level to 6 just before
a clock interrupt wants to arrive; then when the interrupt
finally does get serviced, it may have lots of callouts to do
followed by a lot of load metering to do (say that it's lightning
bolt time), so that by the time an "spl1" is done 34 milliseconds
have been spent at priority level 6...  Does this seem reasonable
on an 11/34?  And why do so many routines set priority to 6 to
block clock interrupts when if the priority is merely elevated to
1 then the clock routine does almost nothing significant but
decrement the callout timer?  The change to the clock routine to
set priority to 6 is not commented, but there are remarks in e.g.
"bk.c" that indicate that this has something to do with clock
interrupt blocking in certain device drivers.  The particular
comment in "bk.c" says that "dzrint" should not be executed at
clock interrupt time in certain places so "spl5"'s need to be
"spl6"'s, but the clock routine won't do any callouts at all if
the priority was elevated at interrupt time...  What's this all
about?  If I don't have any DZ's (I don't) can I change it back
to 5?

3) Size.  The bane of nonseparate I/D.  The 2.8 distribution
didn't come with "awk", a program I'm fond of using under 4.1 BSD
on our VAXen.  I found "awk" source on the 2.8 prerelease tape,
and discovered that I needed "yacc" and "lex" to compile it.
Well, it turns out that the available flavors of "yacc" on the
prerelease tape (MEDIUM and HUGE) are rather too large for my
poor old 11/34; with some hacking I managed to scrunch "yacc"
down to about half of MEDIUM size, and it compiled.  This SMALL
"yacc" was sufficient to compile a SMALL "lex", but neither of
these was capable of handling the parser and scanner of "awk"...
I succeeded in compiling a nonseparate I/D "awk" on an 11/44 and
brought it over to my 11/34, but most unfortunately it runs "out
of space in ALLOC" when presented with any but the most trivial
programs.  Has anyone in netnews-land solved this problem with
compiling "awk" before (short of buying a bigger machine)?

4) PDP11 long integer brain damage.  Our facility has bought and
is buying more VAXen, but we don't yet have enough cash to
replace our PDP11s (partly because of the way our users are
funded).  One way to conserve resources and perhaps also to
implement inter-machine communication is to share disks among our
CPUs.  We'd like to do this by dual-porting controllers.
Wouldn't it be nice if it were possible to have the same filesys-
tem structure on all our machines?  I asked Bill Jolitz about
this at USENIX and he warned me that it would be a tough job,
because although the filesystem structures are superficially
similar, the PDP11 stores long integers the wrong way, with the
high order word at the low address, unlike a VAX.  All the places
in the kernel where VAX long integers would be read in from disk
would have to be modified to flip the words into PDP11 order.
Well, I thought of a way to accomplish this indirectly.  It turns
out that the most significant part of the funny word order on the
11s has to do with how they are loaded into registers (the high
order word takes the lower-numbered register); instructions like
ASHC, MUL and DIV can only operate on long quantities in regis-
ter.  I have munged a version of the C compiler to put long
integers into register the way the PDP11 likes them but to keep
them in memory in the right (VAX) word order.  The compiler seems
to work (cross my fingers) and I am about ready to start trying
out programs like "mkfs" to see if they do the right thing.
Before I sink too much more of my time into this, does anyone see
why this wouldn't do what I want?

Sorry for the long opus; I hope people find it interesting enough
to send me suggestions at ucbvax!sdcsvax!sdchema!donn or post
them to the newsgroup.

                                        Donn Seeley
                                        UC San Diego Chemistry Dept.
                                        ucbvax!sdcsvax!phonlab!donn
                                        ucbvax!sdcsvax!sdchema!fred!donn
                                        etc.

From: cbosgd!cbosg!teklabs!ucbcad!ARPAVAX:CSVAX:decvax!pur-ee!purdue!pur-phy!crl
Newsgroups: net.bugs.2bsd
Title: Bug fixes to w.c
Article-I.D.: pur-phy.259
Posted: Sat Mar 27 21:23:12 1982
Expires: 
Received: Mon Mar 29 15:40:38 1982

I have found and fixed a bug in the 'w' program, along with cleaning
up a couple of other items.  They are:

	1) 'w' would add up the times of all processes started on
	   the terminal.  Thus, if someone put a process in the back-
	   ground, logged out, and someone else logged on, the job
	   and process times would be incorrect.  This was fixed by
	   comparing the uid of the person currently logged on
	   and the real uid of the processes on that tty.

	2) Since 2.8 bsd has a loadav call, I replaced the peek into
	   memory to calculate it.

	3) Also, since stdout is already buffered, I removed the call
	   to setbuf.

A diff of the changes follow.

Charles LaBrec
pur-ee!physics:crl

*** w.c.brk	Sat Mar 27 21:00:56 1982  (old version)
--- w.c		Sat Mar 27 21:07:36 1982  (new    "   )
***************
*** 15,20
  #include <ctype.h>
  #include <utmp.h>
  #include <time.h>
  #include <sys/param.h>
  #include <sys/stat.h>
  #include <sys/proc.h>

--- 15,21 -----
  #include <ctype.h>
  #include <utmp.h>
  #include <time.h>
+ #include <pwd.h>
  #include <sys/param.h>
  #include <sys/stat.h>
  #include <sys/proc.h>
***************
*** 33,38
  	dev_t	w_tty;			/* tty device of process */
  	char	w_comm[15];		/* user.u_comm, null terminated */
  	char	w_args[ARGWIDTH+1];	/* args if interesting process */
  } pr[NPROC];
  
  struct	nlist nl[] = {

--- 34,40 -----
  	dev_t	w_tty;			/* tty device of process */
  	char	w_comm[15];		/* user.u_comm, null terminated */
  	char	w_args[ARGWIDTH+1];	/* args if interesting process */
+ 	int	w_ruid;			/* real user id */
  } pr[NPROC];
  
  struct	nlist nl[] = {
***************
*** 58,63
  int	nswap;
  int	file;
  dev_t	tty;
  char	doing[520];		/* process attached to terminal */
  time_t	proctime;		/* cpu time of process in doing */
  short	avenrun[3];

--- 60,66 -----
  int	nswap;
  int	file;
  dev_t	tty;
+ int	uid;
  char	doing[520];		/* process attached to terminal */
  time_t	proctime;		/* cpu time of process in doing */
  double	load[3];
***************
*** 60,66
  dev_t	tty;
  char	doing[520];		/* process attached to terminal */
  time_t	proctime;		/* cpu time of process in doing */
- short	avenrun[3];
  double	load[3];
  
  #define	DIV60(t)	((t+30)/60)    /* x/60 rounded */ 

--- 63,68 -----
  int	uid;
  char	doing[520];		/* process attached to terminal */
  time_t	proctime;		/* cpu time of process in doing */
  double	load[3];
  
  #define	DIV60(t)	((t+30)/60)    /* x/60 rounded */ 
***************
*** 64,70
  double	load[3];
  
  #define	DIV60(t)	((t+30)/60)    /* x/60 rounded */ 
! #define	TTYEQ		(tty == pr[i].w_tty)
  #define IGINT		(1+3*1)		/* ignoring both SIGINT & SIGQUIT */
  
  long	round();

--- 66,72 -----
  double	load[3];
  
  #define	DIV60(t)	((t+30)/60)    /* x/60 rounded */ 
! #define	TTYEQ		(tty == pr[i].w_tty && uid == pr[i].w_ruid)
  #define IGINT		(1+3*1)		/* ignoring both SIGINT & SIGQUIT */
  
  long	round();
***************
*** 75,80
  char	*getptr();
  FILE	*popen();
  struct	tm *localtime();
  
  int	debug;			/* true if -d flag: debugging output */
  int	header = 1;		/* true if -h flag: don't print heading */

--- 77,83 -----
  char	*getptr();
  FILE	*popen();
  struct	tm *localtime();
+ struct	passwd *getpwnam();
  
  int	debug;			/* true if -d flag: debugging output */
  int	header = 1;		/* true if -h flag: don't print heading */
***************
*** 107,113
  	register int i, j;
  	char *cp;
  	register int curpid, empty;
! 	char obuf[BUFSIZ];
  
  	setbuf(stdout, obuf);
  	login = (argv[0][0] == '-');

--- 110,116 -----
  	register int i, j;
  	char *cp;
  	register int curpid, empty;
! 	struct passwd *pwptr;
  
  	login = (argv[0][0] == '-');
  	cp = rindex(argv[0], '/');
***************
*** 109,115
  	register int curpid, empty;
  	char obuf[BUFSIZ];
  
- 	setbuf(stdout, obuf);
  	login = (argv[0][0] == '-');
  	cp = rindex(argv[0], '/');
  	firstchar = login ? argv[0][1] : (cp==0) ? argv[0][0] : cp[1];

--- 112,117 -----
  	register int curpid, empty;
  	struct passwd *pwptr;
  
  	login = (argv[0][0] == '-');
  	cp = rindex(argv[0], '/');
  	firstchar = login ? argv[0][1] : (cp==0) ? argv[0][0] : cp[1];
***************
*** 212,233
  		rewind(ut);
  		printf("  %d users", nusers);
  
! 		if (nl[X_AVENRUN].n_type > 0) {
! 			/*
! 			 * Print 1, 5, and 15 minute load averages.
! 			 * (Found by looking in kernel for avenrun).
! 			 */
! 			printf(",  load average:");
! 			lseek(mem, (long)nl[X_AVENRUN].n_value, 0);
! 			read(mem, avenrun, sizeof(avenrun));
! 			for (i = 0; i < (sizeof(avenrun)/sizeof(avenrun[0])); i++) {
! 				load[i] = avenrun[i] / 256.0;
! 				if (i > 0)
! 					printf(",");
! 				printf(" %.2f", load[i]);
! 			}
! 		}
! 		printf("\n");
  		if (firstchar == 'u')
  			exit(0);
  

--- 214,221 -----
  		rewind(ut);
  		printf("  %d users", nusers);
  
! 		loadav(load);
! 		printf(",  load average: %.2f %.2f %.2f\n", load[0], load[1], load[2]);
  		if (firstchar == 'u')
  			exit(0);
  
***************
*** 247,252
  		}
  		if (utmp.ut_name[0] == '\0')
  			continue;	/* that tty is free */
  		if (sel_user && strncmp(utmp.ut_name, sel_user, 8) != 0)
  			continue;	/* we wanted only somebody else */
  

--- 235,243 -----
  		}
  		if (utmp.ut_name[0] == '\0')
  			continue;	/* that tty is free */
+ 		if ((pwptr = getpwnam(utmp.ut_name)) == NULL )
+ 			continue;	/* can't figure out who's on it */
+ 		uid = pwptr->pw_uid;
  		if (sel_user && strncmp(utmp.ut_name, sel_user, 8) != 0)
  			continue;	/* we wanted only somebody else */
  
***************
*** 488,493
  		pr[np].w_time = up.u_utime + up.u_stime;
  		pr[np].w_ctime = up.u_cutime + up.u_cstime;
  		pr[np].w_tty = up.u_ttyd;
  		up.u_comm[14] = 0;	/* Bug: This bombs next field. */
  		strcpy(pr[np].w_comm, up.u_comm);
  		/*

--- 479,485 -----
  		pr[np].w_time = up.u_utime + up.u_stime;
  		pr[np].w_ctime = up.u_cutime + up.u_cstime;
  		pr[np].w_tty = up.u_ttyd;
+ 		pr[np].w_ruid = up.u_ruid;
  		up.u_comm[14] = 0;	/* Bug: This bombs next field. */
  		strcpy(pr[np].w_comm, up.u_comm);
  		/*
From: cbosgd!cbosg!teklabs!ucbcad!ARPAVAX:C70:sri-unix!cca!cecvax!pur-ee!purdue!pur-phy!crl
Newsgroups: net.bugs.2bsd
Title: A fix to the w.c bug fix (sigh)
Article-I.D.: pur-phy.260
Posted: Mon Mar 29 13:27:45 1982
Expires: 
Received: Thu Apr  1 03:45:01 1982

Well, I guess I spoke too soon with my previous bug fix.  There's a 
problem that I didn't notice before. This occurs when someone is logged
on has an 8-character user name.  Because most of the users around
here have short id's, I missed this point in testing.  The entry in
utmp is not guaranteed to be null-terminated, so the call to getpwnam()
returns NULL when that happens.  The fix is indicated below.
Also, if you haven't done so already, it is really advantageous to make
w be setuid to root so that it can use the phys() system call (if you
have it).  This reduces system time used by about 5 sec.

Charles LaBrec
pur-ee!physics:crl

----------------------------------------
*** w.c.old	Mon Mar 29 13:11:10 1982
--- w.c		Mon Mar 29 13:14:11 1982
***************
*** 108,114
  {
  	int days, hrs, mins;
  	register int i, j;
! 	char *cp;
  	register int curpid, empty;
  	struct passwd *pwptr;
  

--- 108,114 -----
  {
  	int days, hrs, mins;
  	register int i, j;
! 	char *cp, tmp[9];
  	register int curpid, empty;
  	struct passwd *pwptr;
  
***************
*** 235,241
  		}
  		if (utmp.ut_name[0] == '\0')
  			continue;	/* that tty is free */
! 		if ((pwptr = getpwnam(utmp.ut_name)) == NULL )
  			continue;	/* can't figure out who's on it */
  		uid = pwptr->pw_uid;
  		if (sel_user && strncmp(utmp.ut_name, sel_user, 8) != 0)

--- 235,243 -----
  		}
  		if (utmp.ut_name[0] == '\0')
  			continue;	/* that tty is free */
! 		strncpy(tmp, utmp.ut_name, 8);
! 		tmp[8] = '\0';		/* make sure it's null-terminated */
! 		if ((pwptr = getpwnam(tmp)) == NULL )
  			continue;	/* can't figure out who's on it */
  		uid = pwptr->pw_uid;
  		if (sel_user && strncmp(utmp.ut_name, sel_user, 8) != 0)



More information about the Comp.bugs.2bsd mailing list