From 4be4bfc2e7dc7aa2441a01d738df84a58b122a99 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Wed, 16 Sep 1998 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1998-09-16 --- carrera/dat.h | 1 + carrera/main.c | 1 + carrera/mem.h | 1 + pc/dat.h | 1 + pc/l.s | 3 +- pc/main.c | 73 +++++++++----- pc/mem.h | 5 +- pc/scsi.c | 2 +- port/alloc.c | 3 +- port/devmnt.c | 11 ++- port/devmntstats.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ port/portdat.h | 5 +- port/segment.c | 74 ++++++++++---- port/swap.c | 14 +-- port/systab.h | 13 +-- 15 files changed, 378 insertions(+), 65 deletions(-) create mode 100644 port/devmntstats.c diff --git a/carrera/dat.h b/carrera/dat.h index 53b899558c6b288cd86f9336997e663def6235c5..8ffa230753e8e60dd7faa498ebe2185ad457e65a 100644 --- a/carrera/dat.h +++ b/carrera/dat.h @@ -47,6 +47,7 @@ struct Conf ulong upages; /* user page pool */ ulong nimage; /* number of page cache image headers */ ulong nswap; /* number of swap pages */ + int nswppo; /* max # of pageouts per segment pass */ ulong base0; /* base of bank 0 */ ulong base1; /* base of bank 1 */ ulong copymode; /* 0 is copy on write, 1 is copy on reference */ diff --git a/carrera/main.c b/carrera/main.c index 2400fb08524cd3223a342e32a761cada4d201283..490651a5638e9bba5a613d35a9694b0d733b8781 100644 --- a/carrera/main.c +++ b/carrera/main.c @@ -482,6 +482,7 @@ confinit(void) /* set up other configuration parameters */ conf.nproc = 100; conf.nswap = conf.npage*3; + conf.nswppo = 4096; conf.nimage = 200; conf.monitor = 1; diff --git a/carrera/mem.h b/carrera/mem.h index d62dd779103d07240cdf73164a9bcddf1a5a6335..ff8cd8f471c0156c92a7760857b5e1feaf4bbfc2 100644 --- a/carrera/mem.h +++ b/carrera/mem.h @@ -197,6 +197,7 @@ #define KPTELOG 7 #define KPTESIZE (1< 2000) conf.nproc = 2000; conf.nswap = conf.nproc*80; + conf.nswppo = 4096; conf.nimage = 200; } @@ -439,44 +440,52 @@ static char* mathmsg[] = "error", }; +static void +mathnote(void) +{ + int i; + ulong status; + char *msg, note[ERRLEN]; + + status = up->fpsave.status; + + /* + * Some attention should probably be paid here to the + * exception masks and error summary. + */ + msg = "unknown"; + for(i = 0; i < 8; i++){ + if(!((1<fpsave.pc); + postnote(up, 1, note, NDebug); +} + /* * math coprocessor error */ static void matherror(Ureg *ur, void*) { - ulong status; - int i; - char *msg; - char note[ERRLEN]; - /* * a write cycle to port 0xF0 clears the interrupt latch attached * to the error# line from the 387 */ - outb(0xF0, 0xFF); + if(!(m->cpuiddx & 0x01)) + outb(0xF0, 0xFF); /* * save floating point state to check out error */ fpenv(&up->fpsave); - status = up->fpsave.status; + mathnote(); - msg = 0; - for(i = 0; i < 8; i++) - if((1<fpsave.pc); - postnote(up, 1, note, NDebug); - break; - } - if(msg == 0){ - sprint(note, "sys: fp: unknown fppc=0x%lux", up->fpsave.pc); - postnote(up, 1, note, NDebug); - } if(ur->pc & KZERO) - panic("fp: status %lux fppc=0x%lux pc=0x%lux", status, - up->fpsave.pc, ur->pc); + panic("fp: status %lux fppc=0x%lux pc=0x%lux", + up->fpsave.status, up->fpsave.pc, ur->pc); } /* @@ -491,6 +500,17 @@ mathemu(Ureg*, void*) up->fpstate = FPactive; break; case FPinactive: + /* + * Before restoring the state, check for any pending + * exceptions, there's no way to restore the state without + * generating an unmasked exception. + * More attention should probably be paid here to the + * exception masks and error summary. + */ + if((up->fpsave.status & ~up->fpsave.control) & 0x07F){ + mathnote(); + break; + } fprestore(&up->fpsave); up->fpstate = FPactive; break; @@ -538,8 +558,17 @@ procsave(Proc *p) if(p->fpstate == FPactive){ if(p->state == Moribund) fpoff(); - else + else{ + /* + * Fpsave() stores without handling pending + * unmasked exeptions. Postnote() can't be called + * here as sleep() already has up->rlock, so + * the handling of pending exceptions is delayed + * until the process runs again and generates an + * emulation fault to activate the FPU. + */ fpsave(&up->fpsave); + } p->fpstate = FPinactive; } diff --git a/pc/mem.h b/pc/mem.h index 18360eddefdef0ae369ef1bb9e6e1bf60be65183..56da30b6dce50426070c9ba622151973971d63f9 100644 --- a/pc/mem.h +++ b/pc/mem.h @@ -50,7 +50,7 @@ #define KZERO 0x80000000 /* base of kernel address space */ #define KTZERO 0x80100000 /* first address in kernel text */ #define USTKTOP (KZERO-BY2PG) /* byte just beyond user stack */ -#define USTKSIZE (4*1024*1024) /* size of user stack */ +#define USTKSIZE (16*1024*1024) /* size of user stack */ #define TSTKTOP (USTKTOP-USTKSIZE) /* end of new stack in sysexec */ #define TSTKSIZ 100 @@ -101,7 +101,8 @@ */ #define PTEMAPMEM (1024*1024) #define PTEPERTAB (PTEMAPMEM/BY2PG) -#define SEGMAPSIZE 512 +#define SEGMAPSIZE 1984 +#define SSEGMAPSIZE 16 #define PPN(x) ((x)&~(BY2PG-1)) /* diff --git a/pc/scsi.c b/pc/scsi.c index 74c7f6a7590cbb88b23eac3f5cc0deaf601c19a7..7aa866d39c2c528320be78c2e262df0b89ff0e35 100644 --- a/pc/scsi.c +++ b/pc/scsi.c @@ -45,7 +45,7 @@ scsireset(void) if(isaconfig("scsi", ctlrno, ctlr) == 0) continue; for(i = 0; scsidev[i]; i++){ - if(strcmp(ctlr->type, scsidev[i]->type)) + if(cistrcmp(ctlr->type, scsidev[i]->type)) continue; if((ctlr->io = scsidev[i]->reset(ctlrno, ctlr)) == 0) break; diff --git a/port/alloc.c b/port/alloc.c index 2ca80624ffb576a8c55956eda372bd1128b1311f..5622ee18c7899c7bcdf65f0b931548797fa74f1f 100644 --- a/port/alloc.c +++ b/port/alloc.c @@ -484,9 +484,10 @@ poolsummary(void) int i; for(i = 0; i < table.n; i++) - print("Arena: %s cursize=%lud; maxsize=%lud\n", + print("Arena: %s cursize=%lud; arenasize=%lud; maxsize=%lud\n", table.pool[i].name, table.pool[i].cursize, + table.pool[i].arenasize, table.pool[i].maxsize); } diff --git a/port/devmnt.c b/port/devmnt.c index a3ad25e925db93ee0a793e621e419e702fbb30e3..3c8c998868e4bd51fb88c61ba9c2917da847947a 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -11,6 +11,7 @@ struct Mntrpc Mntrpc* list; /* Free/pending list */ Fcall request; /* Outgoing file system protocol message */ Fcall reply; /* Incoming reply */ + uvlong stime; /* start time */ Mnt* m; /* Mount device during rpc */ Rendez r; /* Place to hang out */ char* rpc; /* I/O Data buffer */ @@ -55,6 +56,7 @@ void mntrecover(Mnt*, Mntrpc*); Chan* mntchan(void); int defmaxmsg = MAXFDATA; +extern void (*mntstats)(int, Chan*, uvlong); enum { @@ -676,6 +678,8 @@ mountio(Mnt *m, Mntrpc *r) if(devtab[m->c->type]->write(m->c, r->rpc, n, 0) != n) error(Emountrpc); } + r->stime = fastticks(nil); + r->bytes = n; poperror(); } @@ -766,9 +770,14 @@ mountmux(Mnt *m, Mntrpc *r) r->rpc = dp; q->reply = r->reply; q->done = 1; + if(mntstats != nil) + (*mntstats)(q->request.type, m->c, q->stime); wakeup(&q->r); - }else + }else { + if(mntstats != nil) + (*mntstats)(r->request.type, m->c, q->stime); q->done = 1; + } return; } l = &q->list; diff --git a/port/devmntstats.c b/port/devmntstats.c new file mode 100644 index 0000000000000000000000000000000000000000..fdd8ce464d90b3d02141b7ccb347dbd85dce95df --- /dev/null +++ b/port/devmntstats.c @@ -0,0 +1,236 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +void (*mntstats)(int, Chan*, uvlong); + +enum +{ + Qmntstat = 1<<12, + + Nhash= 31, + Nms= 256, + Nrpc= (Tmax-Tnop)/2, +}; + +typedef struct Mntstats Mntstats; +struct Mntstats +{ + Mntstats *next; + int inuse; + Chan c; + uvlong hi[Nrpc]; /* high water time spent/msg type */ + uvlong tot[Nrpc]; /* cumulative time spent/msg type */ + uvlong bytes[Nrpc]; /* cumulative bytes xfered */ + ulong n[Nrpc]; /* number of messages/msg type */ + ulong last100[Nrpc]; /* avg time for last 100 */ +}; + +static struct +{ + Lock; + Mntstats *hash[Nhash]; + Mntstats all[Nms]; + int n; +} msalloc; + +static void +_mntstats(int type, Chan *c, uvlong start) +{ + uint h; + Mntstats **l, *m; + uvlong elapsed; + ulong x; + + elapsed = fastticks(nil) - start; + type -= Tnop; + type >>= 1; + + h = (c->dev<<4)+(c->type<<2)+c->qid.path; + h %= Nhash; + for(l = &msalloc.hash[h]; *l; l = &(*l)->next) + if(eqchan(&(*l)->c, c, 0)) + break; + m = *l; + + if(m == nil){ + lock(&msalloc); + for(m = msalloc.all; m < &msalloc.all[Nms]; m++) + if(m->inuse && eqchan(&m->c, c, 0)) + break; + if(m == &msalloc.all[Nms]) + for(m = msalloc.all; m < &msalloc.all[Nms]; m++){ + if(m->inuse == 0){ + m->inuse = 1; + m->c = *c; + *l = m; + msalloc.n++; + break; + } + } + unlock(&msalloc); + if(m >= &msalloc.all[Nms]) + return; + } + + if(m->hi[type] < elapsed) + m->hi[type] = elapsed; + m->tot[type] += elapsed; + m->n[type]++; + x = elapsed; + m->last100[type] = (m->last100[type]*127 + x)>>7; +} + +static int +mntstatsgen(Chan *c, Dirtab*, int, int i, Dir *dp) +{ + Qid q; + char name[NAMELEN]; + Mntstats *m; + + m = &msalloc.all[i]; + if(i > Nms || m->inuse == 0) + return -1; + + q = (Qid){Qmntstat+i, 0}; + snprint(name, NAMELEN, "%C%lud.%lux", devtab[m->c.type]->dc, m->c.dev, m->c.qid.path); + devdir(c, q, name, 0, eve, 0666, dp); + + return 1; +} + +static void +mntstatsinit(void) +{ + mntstats = _mntstats; +} + +static Chan* +mntstatsattach(char *spec) +{ + return devattach('z', spec); +} + +static int +mntstatswalk(Chan *c, char *name) +{ + return devwalk(c, name, 0, msalloc.n, mntstatsgen); +} + +static void +mntstatsstat(Chan *c, char *dp) +{ + devstat(c, dp, 0, msalloc.n, mntstatsgen); +} + +static Chan* +mntstatsopen(Chan *c, int omode) +{ + return devopen(c, omode, 0, msalloc.n, mntstatsgen); +} + +static void +mntstatsclose(Chan*) +{ +} + +enum +{ + Nline= 80, +}; + +char *rpcname[Nrpc] = +{ + "nop", + "osession", + "error", + "flush", + "oattach", + "clone", + "walk", + "open", + "create", + "read", + "write", + "clunk", + "remove", + "stat", + "wstat", + "clwalk", + "auth", + "session", + "attach", +}; + +static long +mntstatsread(Chan *c, void *buf, long n, vlong off) +{ + char *a, *start; + ulong o; + char xbuf[Nline+1]; + Mntstats *m; + uvlong avg; + + start = a = buf; + + if(n <= 0) + return n; + + if(c->qid.path & CHDIR) + return devdirread(c, buf, n, 0, msalloc.n, mntstatsgen); + + m = &msalloc.all[c->qid.path - Qmntstat]; + o = off; + if((o % Nline) != 0) + error(Ebadarg); + n = n/Nline; + o = o/Nline; + while(n > 0 && o < Nrpc){ + if(m->n[o] > 0) + avg = m->tot[o]/m->n[o]; + else + avg = 0; + sprint(xbuf, "%-8.8s %16.0llud %16.0llud %9.0lud %16.0llud %9.0lud\n", + rpcname[o], m->hi[o], + m->tot[o], m->n[o], avg, m->last100[o]); + memmove(a, xbuf, Nline); + a += Nline; + o++; + n--; + } + return a - start; +} + +static long +mntstatswrite(Chan*, void*, long, vlong) +{ + lock(&msalloc); + memset(msalloc.all, 0, sizeof(msalloc.all)); + msalloc.n = 0; + unlock(&msalloc); + return 0; +} + +Dev mntstatsdevtab = { + 'z', + "mntstats", + + devreset, + mntstatsinit, + mntstatsattach, + devclone, + mntstatswalk, + mntstatsstat, + mntstatsopen, + devcreate, + mntstatsclose, + mntstatsread, + devbread, + mntstatswrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/port/portdat.h b/port/portdat.h index 0ac6e5febf4c76955b332ec2b74939aa4a74dacb..49072ae5981dde7469972fed6649bd41fa5f32e4 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -374,7 +374,6 @@ struct Segment Ref; QLock lk; ushort steal; /* Page stealer lock */ - Segment *next; /* free list pointers */ ushort type; /* segment type */ ulong base; /* virtual base */ ulong top; /* virtual top */ @@ -385,7 +384,9 @@ struct Segment Image *image; /* text in file attached to this segment */ Physseg *pseg; ulong* profile; /* Tick profile area */ - Pte *map[SEGMAPSIZE]; + Pte **map; + int mapsize; + Pte *ssegmap[SSEGMAPSIZE]; }; enum diff --git a/port/segment.c b/port/segment.c index cba364cf4b783991b53a87282293ab741138798d..128bb9f595b1ba5d199abbde9dadeb5c2a91674f 100644 --- a/port/segment.c +++ b/port/segment.c @@ -48,6 +48,7 @@ Segment * newseg(int type, ulong base, ulong size) { Segment *s; + int mapsize; if(size > (SEGMAPSIZE*PTEPERTAB)) error(Enovmem); @@ -58,6 +59,17 @@ newseg(int type, ulong base, ulong size) s->base = base; s->top = base+(size*BY2PG); s->size = size; + + mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB; + if(mapsize > nelem(s->ssegmap)){ + s->map = smalloc(mapsize*sizeof(Pte*)); + s->mapsize = mapsize; + } + else{ + s->map = s->ssegmap; + s->mapsize = nelem(s->ssegmap); + } + return s; } @@ -91,12 +103,14 @@ putseg(Segment *s) if(i) putimage(i); - emap = &s->map[SEGMAPSIZE]; + emap = &s->map[s->mapsize]; for(pp = s->map; pp < emap; pp++) if(*pp) freepte(s, *pp); qunlock(&s->lk); + if(s->map != s->ssegmap) + free(s->map); if(s->profile != 0) free(s->profile); free(s); @@ -108,7 +122,7 @@ relocateseg(Segment *s, ulong offset) Page **pg, *x; Pte *pte, **p, **endpte; - endpte = &s->map[SEGMAPSIZE]; + endpte = &s->map[s->mapsize]; for(p = s->map; p < endpte; p++) { if(*p == 0) continue; @@ -123,7 +137,7 @@ relocateseg(Segment *s, ulong offset) Segment* dupseg(Segment **seg, int segno, int share) { - int i; + int i, size; Pte *pte; Segment *n, *s; @@ -174,7 +188,8 @@ dupseg(Segment **seg, int segno, int share) n->flen = s->flen; break; } - for(i = 0; i < SEGMAPSIZE; i++) + size = s->mapsize; + for(i = 0; i < size; i++) if(pte = s->map[i]) n->map[i] = ptecpy(pte); @@ -374,7 +389,8 @@ ibrk(ulong addr, int seg) { Segment *s, *ns; ulong newtop, newsize; - int i; + int i, mapsize; + Pte **map; s = up->seg[seg]; if(s == 0) @@ -413,10 +429,19 @@ ibrk(ulong addr, int seg) } } - if(newsize > (PTEMAPMEM*SEGMAPSIZE)/BY2PG) { + if(newsize > (SEGMAPSIZE*PTEPERTAB)) { qunlock(&s->lk); error(Enovmem); } + mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB; + if(mapsize > s->mapsize){ + map = smalloc(mapsize*sizeof(Pte*)); + memmove(map, s->map, s->mapsize); + if(s->map != s->ssegmap) + free(s->map); + s->map = map; + s->mapsize = mapsize; + } s->top = newtop; s->size = newsize; @@ -430,7 +455,7 @@ ibrk(ulong addr, int seg) void mfreeseg(Segment *s, ulong start, int pages) { - int i, j; + int i, j, size; ulong soff; Page *pg; Page *list; @@ -438,8 +463,9 @@ mfreeseg(Segment *s, ulong start, int pages) soff = start-s->base; j = (soff&(PTEMAPMEM-1))/BY2PG; + size = s->mapsize; list = nil; - for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) { + for(i = soff/PTEMAPMEM; i < size; i++) { if(pages <= 0) break; if(s->map[i] == 0) { @@ -477,7 +503,7 @@ out: } } -int +Segment* isoverlap(Proc *p, ulong va, int len) { int i; @@ -491,9 +517,9 @@ isoverlap(Proc *p, ulong va, int len) continue; if((newtop > ns->base && newtop <= ns->top) || (va >= ns->base && va < ns->top)) - return 1; + return ns; } - return 0; + return nil; } int @@ -526,8 +552,8 @@ addphysseg(Physseg* new) ulong segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) { - int i, sno; - Segment *s; + int sno; + Segment *s, *os; Physseg *ps; if(va != 0 && (va&KZERO) == KZERO) /* BUG: Only ok for now */ @@ -537,7 +563,7 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) vmemchr(name, 0, ~0); for(sno = 0; sno < NSEG; sno++) - if(p->seg[sno] == 0 && sno != ESEG) + if(p->seg[sno] == nil && sno != ESEG) break; if(sno == NSEG) @@ -545,18 +571,28 @@ segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) len = PGROUND(len); - /* Find a hole in the address space */ + /* + * Find a hole in the address space. + * Starting at the lowest possible stack address - len, + * check for an overlapping segment, and repeat at the + * base of that segment - len until either a hole is found + * or the address space is exhausted. + */ if(va == 0) { va = p->seg[SSEG]->base - len; - for(i = 0; i < 20; i++) { - if(isoverlap(p, va, len) == 0) + for(;;) { + os = isoverlap(p, va, len); + if(os == nil) break; + va = os->base; + if(len > va) + error(Enovmem); va -= len; } } va = va&~(BY2PG-1); - if(isoverlap(p, va, len)) + if(isoverlap(p, va, len) != nil) error(Esoverlap); for(ps = physseg; ps->name; ps++) @@ -568,7 +604,7 @@ found: if(len > ps->size) error(Enovmem); - attr &= ~SG_TYPE; /* Turn off what we are not allowed */ + attr &= ~SG_TYPE; /* Turn off what is not allowed */ attr |= ps->attr; /* Copy in defaults */ s = newseg(attr, va, len/BY2PG); diff --git a/port/swap.c b/port/swap.c index d4453d4fcbacdb9eda7a743be86ea6a291c3ed9e..2c979c08c9401a48f91b1b87dbfb3903aef6be00 100644 --- a/port/swap.c +++ b/port/swap.c @@ -12,11 +12,6 @@ static void pageout(Proc*, Segment*); static void pagepte(int, Page**); static void pager(void*); -enum -{ - Maxpages = SEGMAXSIZE/BY2PG, /* Max # of pageouts per segment pass */ -}; - Image swapimage; static int swopen; static Page **iolist; @@ -30,7 +25,7 @@ swapinit(void) swapalloc.alloc = swapalloc.swmap; swapalloc.last = swapalloc.swmap; swapalloc.free = conf.nswap; - iolist = xalloc(Maxpages*sizeof(Page*)); + iolist = xalloc(conf.nswppo*sizeof(Page*)); if(swapalloc.swmap == 0 || iolist == 0) panic("swapinit: not enough memory"); @@ -163,7 +158,7 @@ loop: static void pageout(Proc *p, Segment *s) { - int type, i; + int type, i, size; Pte *l; Page **pg, *entry; @@ -189,7 +184,8 @@ pageout(Proc *p, Segment *s) /* Pass through the pte tables looking for memory pages to swap out */ type = s->type&SG_TYPE; - for(i = 0; i < SEGMAPSIZE; i++) { + size = s->mapsize; + for(i = 0; i < size; i++) { l = s->map[i]; if(l == 0) continue; @@ -205,7 +201,7 @@ pageout(Proc *p, Segment *s) pagepte(type, pg); - if(ioptr >= Maxpages) + if(ioptr >= conf.nswppo) goto out; } } diff --git a/port/systab.h b/port/systab.h index bcbff6f639983db3428d4793410f1f20671ec49a..ffa86f227bdffde01daf6bfd25e66cbad5959078 100644 --- a/port/systab.h +++ b/port/systab.h @@ -19,8 +19,7 @@ Syscall syssegbrk; Syscall sysmount; Syscall sysopen; Syscall sysread; -Syscall sysseek; -Syscall sysvseek; +Syscall sysoseek; Syscall syssleep; Syscall sysstat; Syscall sysrfork; @@ -43,6 +42,8 @@ Syscall sysunmount; Syscall syswait; Syscall syswrite9p; Syscall sysread9p; +Syscall sysseek; +Syscall sysdeath; Syscall *systab[]={ [SYSR1] sysr1, @@ -61,8 +62,7 @@ Syscall *systab[]={ [MOUNT] sysmount, [OPEN] sysopen, [READ] sysread, - [SEEK] sysseek, - [VSEEK] sysvseek, + [OSEEK] sysoseek, [SLEEP] syssleep, [STAT] sysstat, [RFORK] sysrfork, @@ -85,6 +85,7 @@ Syscall *systab[]={ [WAIT] syswait, [WRITE9P] syswrite9p, [READ9P] sysread9p, + [SEEK] sysseek, }; char *sysctab[]={ @@ -104,8 +105,7 @@ char *sysctab[]={ [MOUNT] "Mount", [OPEN] "Open", [READ] "Read", - [SEEK] "Seek", - [VSEEK] "Vseek", + [OSEEK] "Oseek", [SLEEP] "Sleep", [STAT] "Stat", [RFORK] "Rfork", @@ -128,6 +128,7 @@ char *sysctab[]={ [WAIT] "Wait", [WRITE9P] "Write9p", [READ9P] "Read9p", + [SEEK] "Seek", }; int nsyscall = (sizeof systab/sizeof systab[0]);