M carrera/dat.h => carrera/dat.h +1 -0
@@ 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 */
M carrera/main.c => carrera/main.c +1 -0
@@ 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;
M carrera/mem.h => carrera/mem.h +1 -0
@@ 197,6 197,7 @@
#define KPTELOG 7
#define KPTESIZE (1<<KPTELOG)
#define SEGMAPSIZE 512
+#define SSEGMAPSIZE 16
#define NTLBPID 256 /* number of pids */
#define NTLB 48 /* number of entries */
M pc/dat.h => pc/dat.h +1 -0
@@ 75,6 75,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 */
M pc/l.s => pc/l.s +1 -2
@@ 397,8 397,7 @@ TEXT fpinit(SB), $0 /* enable and init */
TEXT fpsave(SB), $0 /* save state and disable */
MOVL p+0(FP), AX
- WAIT
- FSAVE 0(AX)
+ FSAVE 0(AX) /* no WAIT */
FPOFF
RET
M pc/main.c => pc/main.c +51 -22
@@ 424,6 424,7 @@ confinit(void)
if(conf.nproc > 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<<i) & status))
+ continue;
+ msg = mathmsg[i];
+ break;
+ }
+ sprint(note, "sys: fp: %s fppc=0x%lux", msg, up->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<<i) & status){
- msg = mathmsg[i];
- sprint(note, "sys: fp: %s fppc=0x%lux", msg, up->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;
}
M pc/mem.h => pc/mem.h +3 -2
@@ 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))
/*
M pc/scsi.c => pc/scsi.c +1 -1
@@ 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;
M port/alloc.c => port/alloc.c +2 -1
@@ 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);
}
M port/devmnt.c => port/devmnt.c +10 -1
@@ 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;
A port/devmntstats.c => port/devmntstats.c +236 -0
@@ 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,
+};
M port/portdat.h => port/portdat.h +3 -2
@@ 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
M port/segment.c => port/segment.c +55 -19
@@ 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);
M port/swap.c => port/swap.c +5 -9
@@ 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;
}
}
M port/systab.h => port/systab.h +7 -6
@@ 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]);