- short-running processes really should be short-running, like 1s not 30s. - when there are more runnable processes than processors, be migrate processes even when there is an equally good runnable without affinity. this prevents vast unfairness. - use monmwit to take it easy on cachelines. performance improvements are pretty impressive. on my ivy bridge machine, kernel builds have gone from 5.4s to 3.9s. Reference: /n/atom/patch/applied/fairsched Date: Sat May 24 07:04:04 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/port/proc.c Sat May 24 07:03:26 2014 +++ /sys/src/nix/port/proc.c Sat May 24 07:03:28 2014 @@ -11,13 +11,14 @@ enum { - Scaling=2, + Scaling = 2, + Shortburst = HZ, /* 1 second */ /* * number of schedulers used. * 1 uses just one, which is the behavior of Plan 9. */ - Nsched = 16, + Nsched = 16, }; Ref noteidalloc; @@ -90,19 +91,6 @@ } /* - * bad planning, once more. - */ -void -procinit0(void) -{ - int i; - - for(i = 0; i < Nsched; i++) - run[i].schedgain = 30; - -} - -/* * Always splhi()'ed. */ void @@ -231,7 +219,7 @@ } if(p != m->readied) m->schedticks = m->ticks + HZ/10; - m->readied = 0; + m->readied = nil; up = p; up->nqtrap = 0; up->nqsyscall = 0; @@ -268,7 +256,7 @@ /* unless preempted, get to run for at least 100ms */ if(anyhigher() - || (!m->proc->fixedpri && (long)(m->ticks - m->schedticks) > 0 && anyready())){ + || (!m->proc->fixedpri && tickscmp(m->ticks, m->schedticks) > 0 && anyready())){ m->readied = nil; /* avoid cooperative scheduling */ m->proc->delaysched++; } @@ -352,7 +340,7 @@ return; if(m->sch == nil) /* may happen during boot */ return; - D = m->sch->schedgain*HZ*Scaling; + D = Shortburst*Scaling; if(n > D) n = D; @@ -365,7 +353,7 @@ p->cpu = 1000 - t; } -//iprint("pid %d %s for %d cpu %d -> %d\n", p->pid,p==up?"active":"inactive",n, ocpu,p->cpu); +//iprint("pid %d %s for %d cpu %d -> %d\n", p->pid, p==up? "active": "inactive", n, ocpu, p->cpu); } /* @@ -494,6 +482,7 @@ pri = reprioritize(p); p->priority = pri; rq = &sch->runq[pri]; + p->readytime = fastticks(nil); p->state = Ready; queueproc(sch, rq, p); if(p->trace) @@ -558,7 +547,7 @@ if(npri != pri){ pl = splhi(); p = dequeueproc(sch, rq, p); - if(p) + if(p != nil) queueproc(sch, &sch->runq[npri], p); splx(pl); goto another; @@ -624,6 +613,16 @@ return nil; } +enum { + /* + * if there are more runnable processes than mach, and nmach>1, + * and nproc%nmach != 0, we need to migrate processes around to + * avoid serious unfairness. this is architecture sensitive. + */ +// Migratedelay = 250*1000, /* 250 µs */ + Migratedelay = 10*1000*1000, /* 10 ms */ +}; + /* * pick a process to run */ @@ -660,12 +659,11 @@ /* * find the highest priority target process that this * processor can run given affinity constraints. - * */ for(rq = &sch->runq[Nrq-1]; rq >= sch->runq; rq--){ - for(p = rq->head; p; p = p->rnext){ + for(p = rq->head; p != nil; p = p->rnext){ if(p->mp == nil || p->mp == m - || (p->wired == nil && i > 0)) + || p->wired == nil && (i>0 || fastticks2ns(fastticks(nil) - p->readytime) >= Migratedelay)) goto found; } } @@ -675,8 +673,10 @@ if(p != nil) goto stolen; spllo(); - /* waste time or halt the CPU */ - idlehands(); + + while(sch->runvec == 0) + monmwait((int*)&sch->runvec, 0); + /* remember how much time we're here */ now = perfticks(); m->perf.inidle += now-start; @@ -1452,16 +1452,17 @@ Schedq *rq; for(sch = run; sch < &run[Nsched]; sch++){ + if(sch->nmach == 0) + continue; for(rq = &sch->runq[Nrq-1]; rq >= sch->runq; rq--){ if(rq->head == nil) continue; - print("sch%ld rq%ld:", sch - run, rq-sch->runq); + iprint("sch%ld rq%ld:", sch - run, rq-sch->runq); for(p = rq->head; p; p = p->rnext) - print(" %d(%lud)", p->pid, m->ticks - p->readytime); - print("\n"); - delay(150); + iprint(" %d(%lludµs)", p->pid, fastticks2us(fastticks(nil) - p->readytime)); + iprint("\n"); } - print("sch%ld: nrdy %d\n", sch - run, sch->nrdy); + iprint("sch%ld: nrdy %d\n", sch - run, sch->nrdy); } } @@ -1671,7 +1672,7 @@ sch = m->sch; p = m->proc; - if(p) { + if(p != nil){ sch->nrun++; p->time[p->insyscall]++; } --- /sys/src/nix/port/portdat.h Sat May 24 07:03:30 2014 +++ /sys/src/nix/port/portdat.h Sat May 24 07:03:32 2014 @@ -703,9 +703,8 @@ Lock; /* runq */ int nrdy; uint delayedscheds; /* statistics */ - int skipscheds; - int preempts; - int schedgain; + uint skipscheds; + uint preempts; uint balancetime; Schedq runq[Nrq]; uint runvec; @@ -835,7 +834,7 @@ int fixedpri; /* priority level does not change */ uint cpu; /* cpu average */ ulong lastupdate; - ulong readytime; /* time process came ready */ + uvlong readytime; /* time process came ready, in fastticks*/ ulong movetime; /* last time process switched processors */ int preempted; /* true if this process hasn't finished the interrupt * that last preempted it @@ -1083,7 +1082,6 @@ extern char* statename[]; extern Lockstats lockstats; extern QLockstats qlockstats; -extern Waitstats waitstats; extern struct { char* n; void (*f)(Ar0*, va_list); --- /sys/src/nix/port/sysproc.c Sat May 24 07:03:34 2014 +++ /sys/src/nix/port/sysproc.c Sat May 24 07:03:36 2014 @@ -847,7 +847,7 @@ val = p->rendval; p->rendval = PTR2UINT(va_arg(list, void*)); - while(p->mach != 0) + while(!procsaved(p)) pause(); ready(p); unlock(up->rgrp); --- /sys/src/nix/port/edf.c Sat May 24 07:03:38 2014 +++ /sys/src/nix/port/edf.c Sat May 24 07:03:39 2014 @@ -575,7 +575,7 @@ sch->nrdy++; sch->runvec |= 1 << PriEdf; p->priority = PriEdf; - p->readytime = m->ticks; + p->readytime = fastticks(nil); p->state = Ready; unlock(sch); if(p->trace) --- /sys/src/nix/port/portfns.h Sat May 24 07:03:41 2014 +++ /sys/src/nix/port/portfns.h Sat May 24 07:03:42 2014 @@ -248,7 +248,6 @@ void procdump(void); int procfdprint(Chan*, int, int, char*, int); void procflushseg(Segment*); -void procinit0(void); void procpriority(Proc*, int, int); void procrestore(Proc*); void procsave(Proc*); --- /sys/src/nix/k10/main.c Sat May 24 07:03:43 2014 +++ /sys/src/nix/k10/main.c Sat May 24 07:03:44 2014 @@ -166,7 +166,6 @@ trapinit(); printinit(); - procinit0(); lapiconline(); ioapiconline(); sipi(); --- /sys/src/nix/port/edf.c Sat May 24 07:03:46 2014 +++ /sys/src/nix/port/edf.c Sat May 24 07:03:47 2014 @@ -575,7 +575,7 @@ sch->nrdy++; sch->runvec |= 1 << PriEdf; p->priority = PriEdf; - p->readytime = m->ticks; + p->readytime = fastticks(nil); p->state = Ready; unlock(sch); if(p->trace) --- /sys/src/nix/port/portfns.h Sat May 24 07:03:49 2014 +++ /sys/src/nix/port/portfns.h Sat May 24 07:03:50 2014 @@ -248,7 +248,6 @@ void procdump(void); int procfdprint(Chan*, int, int, char*, int); void procflushseg(Segment*); -void procinit0(void); void procpriority(Proc*, int, int); void procrestore(Proc*); void procsave(Proc*);