提交 ff1eef00 创建 作者: Nickolai Zeldovich's avatar Nickolai Zeldovich

Merge branch 'scale-amd64' of git+ssh://pdos.csail.mit.edu/home/am0/6.828/xv6 into scale-amd64

...@@ -126,7 +126,8 @@ void ideintr(void); ...@@ -126,7 +126,8 @@ void ideintr(void);
void iderw(struct buf*); void iderw(struct buf*);
// idle.cc // idle.cc
extern struct proc *idlep[NCPU]; struct proc * idleproc(void);
void idlezombie(struct proc*);
// ioapic.c // ioapic.c
void ioapicenable(int irq, int cpu); void ioapicenable(int irq, int cpu);
...@@ -179,6 +180,7 @@ int pipewrite(struct pipe*, char*, int); ...@@ -179,6 +180,7 @@ int pipewrite(struct pipe*, char*, int);
// proc.c // proc.c
struct proc* allocproc(void); struct proc* allocproc(void);
struct proc* copyproc(struct proc*); struct proc* copyproc(struct proc*);
void finishproc(struct proc*);
void exit(void); void exit(void);
int fork(int); int fork(int);
int growproc(int); int growproc(int);
...@@ -190,7 +192,7 @@ void userinit(void); ...@@ -190,7 +192,7 @@ void userinit(void);
int wait(void); int wait(void);
void yield(void); void yield(void);
struct proc* threadalloc(void (*fn)(void*), void *arg); struct proc* threadalloc(void (*fn)(void*), void *arg);
void threadpin(void (*fn)(void*), void *arg, const char *name, int cpu); struct proc* threadpin(void (*fn)(void*), void *arg, const char *name, int cpu);
// prof.c // prof.c
extern int profenable; extern int profenable;
...@@ -262,7 +264,7 @@ void freework(struct work *w); ...@@ -262,7 +264,7 @@ void freework(struct work *w);
// cilk.c // cilk.c
#if CILKENABLE #if CILKENABLE
void cilk_push(void *rip, u64 arg0, u64 arg1); void cilk_push(void (*fn)(uptr, uptr), u64 arg0, u64 arg1);
void cilk_start(void); void cilk_start(void);
void cilk_end(void); void cilk_end(void);
void cilk_dump(void); void cilk_dump(void);
......
...@@ -42,11 +42,13 @@ struct klockstat; ...@@ -42,11 +42,13 @@ struct klockstat;
// Debug knobs // Debug knobs
#define LOCKSTAT_BIO 1 #define LOCKSTAT_BIO 1
#define LOCKSTAT_CILK 1
#define LOCKSTAT_CONDVAR 0 #define LOCKSTAT_CONDVAR 0
#define LOCKSTAT_CONSOLE 1 #define LOCKSTAT_CONSOLE 1
#define LOCKSTAT_CRANGE 1 #define LOCKSTAT_CRANGE 1
#define LOCKSTAT_FS 1 #define LOCKSTAT_FS 1
#define LOCKSTAT_GC 1 #define LOCKSTAT_GC 1
#define LOCKSTAT_IDLE 1
#define LOCKSTAT_KALLOC 1 #define LOCKSTAT_KALLOC 1
#define LOCKSTAT_KMALLOC 1 #define LOCKSTAT_KMALLOC 1
#define LOCKSTAT_NET 1 #define LOCKSTAT_NET 1
......
template <typename T>
struct percpu {
int myid() {
return mycpu()->id;
}
const T* operator->() const {
return cpu(myid());
}
T* operator->() {
return cpu(myid());
}
T& operator*() {
return *cpu(myid());
}
T& operator[](int id) {
return *cpu(id);
}
const T& operator[](int id) const {
return *cpu(id);
}
T* cpu(int id) {
return &pad_[id].v_;
}
struct {
T v_ __mpalign__;
__padout__;
} pad_[NCPU];
};
...@@ -92,3 +92,4 @@ sys_async(int fd, size_t count, off_t off, ...@@ -92,3 +92,4 @@ sys_async(int fd, size_t count, off_t off,
msg->submitted = 1; msg->submitted = 1;
return 0; return 0;
} }
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "queue.h" #include "queue.h"
#include "proc.hh" #include "proc.hh"
#include "mtrace.h" #include "mtrace.h"
#include "wq.hh"
#define NSLOTS (1 << CILKSHIFT) #define NSLOTS (1 << CILKSHIFT)
...@@ -59,7 +60,6 @@ struct cilkthread { ...@@ -59,7 +60,6 @@ struct cilkthread {
struct cilkstat { struct cilkstat {
u64 push; u64 push;
u64 full; u64 full;
u64 pop;
u64 steal; u64 steal;
__padout__; __padout__;
} __mpalign__; } __mpalign__;
...@@ -67,12 +67,6 @@ struct cilkstat { ...@@ -67,12 +67,6 @@ struct cilkstat {
static struct cilkqueue queue[NCPU] __mpalign__; static struct cilkqueue queue[NCPU] __mpalign__;
static struct cilkstat stat[NCPU] __mpalign__; static struct cilkstat stat[NCPU] __mpalign__;
static struct cilkqueue *
cilk_cur(void)
{
return &queue[mycpu()->id];
}
static struct cilkframe * static struct cilkframe *
cilk_frame(void) cilk_frame(void)
{ {
...@@ -85,73 +79,20 @@ cilk_stat(void) ...@@ -85,73 +79,20 @@ cilk_stat(void)
return &stat[mycpu()->id]; return &stat[mycpu()->id];
} }
static int
__cilk_push(struct cilkqueue *q, struct cilkthread *t)
{
int i;
i = q->head;
if ((i - q->tail) == NSLOTS) {
cilk_stat()->full++;
return -1;
}
i = i & (NSLOTS-1);
q->thread[i] = t;
q->head++;
cilk_stat()->push++;
return 0;
}
static struct cilkthread *
__cilk_pop(struct cilkqueue *q)
{
int i;
acquire(&q->lock);
i = q->head;
if ((i - q->tail) == 0) {
release(&q->lock);
return 0;
}
i = (i-1) & (NSLOTS-1);
q->head--;
release(&q->lock);
cilk_stat()->pop++;
return q->thread[i];
}
static struct cilkthread *
__cilk_steal(struct cilkqueue *q)
{
int i;
acquire(&q->lock);
i = q->tail;
if ((i - q->head) == 0) {
release(&q->lock);
return 0;
}
i = i & (NSLOTS-1);
q->tail++;
release(&q->lock);
cilk_stat()->steal++;
return q->thread[i];
}
static void static void
__cilk_run(struct cilkthread *th) __cilk_run(struct work *w, void *xfn, void *arg0, void *arg1, void *xframe)
{ {
void (*fn)(uptr arg0, uptr arg1) = (void(*)(uptr,uptr))th->rip; void (*fn)(uptr arg0, uptr arg1) = (void(*)(uptr,uptr))xfn;
struct cilkframe *frame = (struct cilkframe *)xframe;
struct cilkframe *old = mycpu()->cilkframe; struct cilkframe *old = mycpu()->cilkframe;
mycpu()->cilkframe = th->frame; if (old != frame)
fn(th->arg0, th->arg1); cilk_stat()->steal++;
mycpu()->cilkframe = frame;
fn((uptr)arg0, (uptr)arg1);
mycpu()->cilkframe = old; mycpu()->cilkframe = old;
th->frame->ref--; frame->ref--;
kfree(th);
} }
// Add the (rip, arg0, arg1) work to the local work queue. // Add the (rip, arg0, arg1) work to the local work queue.
...@@ -160,56 +101,27 @@ __cilk_run(struct cilkthread *th) ...@@ -160,56 +101,27 @@ __cilk_run(struct cilkthread *th)
void void
cilk_push(void (*fn)(uptr, uptr), u64 arg0, u64 arg1) cilk_push(void (*fn)(uptr, uptr), u64 arg0, u64 arg1)
{ {
struct cilkthread *th; struct work *w;
th = (struct cilkthread *) kalloc(); w = allocwork();
if (th == nullptr) { if (w == nullptr) {
fn(arg0, arg1); fn(arg0, arg1);
return; return;
} }
th->rip = (uptr) fn; w->rip = (void*)__cilk_run;
th->arg0 = arg0; w->arg0 = (void*)fn;
th->arg1 = arg1; w->arg1 = (void*)arg0;
th->frame = cilk_frame(); w->arg2 = (void*)arg1;
w->arg3 = (void*)cilk_frame();
if (__cilk_push(cilk_cur(), th)) {
kfree(th); if (wq_push(w)) {
freework(w);
fn(arg0, arg1); fn(arg0, arg1);
} else cilk_stat()->full++;
} else {
cilk_frame()->ref++; cilk_frame()->ref++;
} cilk_stat()->push++;
// Try to execute one cilkthread.
// Check local queue then steal from other queues.
int
cilk_trywork(void)
{
struct cilkthread *th;
int i;
pushcli();
th = __cilk_pop(cilk_cur());
if (th != nullptr) {
__cilk_run(th);
popcli();
return 1;
}
// XXX(sbw) should be random
for (i = 0; i < NCPU; i++) {
if (i == mycpu()->id)
continue;
th = __cilk_steal(&queue[i]);
if (th != nullptr) {
__cilk_run(th);
popcli();
return 1;
}
} }
popcli();
return 0;
} }
// Start a new work queue frame. // Start a new work queue frame.
...@@ -229,21 +141,9 @@ cilk_start(void) ...@@ -229,21 +141,9 @@ cilk_start(void)
void void
cilk_end(void) cilk_end(void)
{ {
while (cilk_frame()->ref != 0) { while (cilk_frame()->ref != 0)
struct cilkthread *th; wq_trywork();
int i;
while ((th = __cilk_pop(cilk_cur())) != nullptr)
__cilk_run(th);
for (i = 0; i < NCPU; i++) {
th = __cilk_steal(&queue[i]);
if (th != nullptr) {
__cilk_run(th);
break;
}
}
}
mycpu()->cilkframe = 0; mycpu()->cilkframe = 0;
popcli(); popcli();
} }
...@@ -253,8 +153,8 @@ cilk_dump(void) ...@@ -253,8 +153,8 @@ cilk_dump(void)
{ {
int i; int i;
for (i = 0; i < NCPU; i++) for (i = 0; i < NCPU; i++)
cprintf("push %lu full %lu pop %lu steal %lu\n", cprintf("push %lu full %lu steal %lu\n",
stat[i].push, stat[i].full, stat[i].pop, stat[i].steal); stat[i].push, stat[i].full, stat[i].steal);
} }
static void static void
...@@ -285,7 +185,7 @@ testcilk(void) ...@@ -285,7 +185,7 @@ testcilk(void)
running = 0; running = 0;
} else { } else {
while (running) while (running)
cilk_trywork(); wq_trywork();
} }
popcli(); popcli();
} }
......
...@@ -6,8 +6,75 @@ ...@@ -6,8 +6,75 @@
#include "proc.hh" #include "proc.hh"
#include "cpu.hh" #include "cpu.hh"
#include "sched.hh" #include "sched.hh"
#include "percpu.hh"
struct proc *idlep[NCPU] __mpalign__; struct idle {
struct proc *cur;
struct proc *heir;
SLIST_HEAD(zombies, proc) zombies;
struct spinlock lock;
};
static percpu<idle> idlem;
void idleloop(void);
struct proc *
idleproc(void)
{
assert(mycpu()->ncli > 0);
return idlem->cur;
}
void
idlezombie(struct proc *p)
{
acquire(&idlem[mycpu()->id].lock);
SLIST_INSERT_HEAD(&idlem[mycpu()->id].zombies, p, child_next);
release(&idlem[mycpu()->id].lock);
}
void
idlebequeath(void)
{
// Only the current idle thread may call this function
assert(mycpu()->ncli > 0);
assert(myproc() == idlem->cur);
assert(idlem->heir != nullptr);
idlem->cur = idlem->heir;
acquire(&idlem->heir->lock);
idlem->heir->set_state(RUNNABLE);
release(&idlem->heir->lock);
}
static void
idleheir(void *x)
{
post_swtch();
idlem->heir = nullptr;
idleloop();
}
static inline void
finishzombies(void)
{
struct idle *i = &idlem[mycpu()->id];
if (!SLIST_EMPTY(&i->zombies)) {
struct proc *p, *np;
acquire(&i->lock);
SLIST_FOREACH_SAFE(p, &i->zombies, child_next, np) {
SLIST_REMOVE(&i->zombies, p, proc, child_next);
finishproc(p);
}
release(&i->lock);
}
}
void void
idleloop(void) idleloop(void)
...@@ -29,11 +96,31 @@ idleloop(void) ...@@ -29,11 +96,31 @@ idleloop(void)
myproc()->set_state(RUNNABLE); myproc()->set_state(RUNNABLE);
sched(); sched();
finishzombies();
if (steal() == 0) { if (steal() == 0) {
int worked; int worked;
do { do {
assert(mycpu()->ncli == 0); assert(mycpu()->ncli == 0);
// If we don't have an heir, try to allocate one
if (idlem->heir == nullptr) {
struct proc *p;
p = allocproc();
if (p == nullptr)
break;
snprintf(p->name, sizeof(p->name), "idleh_%u", mycpu()->id);
p->cpuid = mycpu()->id;
p->cpu_pin = 1;
p->context->rip = (u64)idleheir;
p->cwd = nullptr;
idlem->heir = p;
}
worked = wq_trywork(); worked = wq_trywork();
// If we are no longer the idle thread, exit
if (worked && idlem->cur != myproc())
exit();
} while(worked); } while(worked);
sti(); sti();
} }
...@@ -43,13 +130,16 @@ idleloop(void) ...@@ -43,13 +130,16 @@ idleloop(void)
void void
initidle(void) initidle(void)
{ {
// allocate a fake PID for each scheduler thread
struct proc *p = allocproc(); struct proc *p = allocproc();
if (!p) if (!p)
panic("initidle allocproc"); panic("initidle allocproc");
SLIST_INIT(&idlem[cpunum()].zombies);
initlock(&idlem[cpunum()].lock, "idle_lock", LOCKSTAT_IDLE);
snprintf(p->name, sizeof(p->name), "idle_%u", cpunum()); snprintf(p->name, sizeof(p->name), "idle_%u", cpunum());
mycpu()->proc = p; mycpu()->proc = p;
myproc()->cpuid = cpunum();
myproc()->cpu_pin = 1; myproc()->cpu_pin = 1;
idlep[cpunum()] = p; idlem->cur = p;
} }
...@@ -83,6 +83,7 @@ cmain(u64 mbmagic, u64 mbaddr) ...@@ -83,6 +83,7 @@ cmain(u64 mbmagic, u64 mbaddr)
initkalloc(mbaddr); initkalloc(mbaddr);
initproc(); // process table initproc(); // process table
initsched(); // scheduler run queues initsched(); // scheduler run queues
initidle();
initgc(); // gc epochs and threads initgc(); // gc epochs and threads
initbio(); // buffer cache initbio(); // buffer cache
initinode(); // inode cache initinode(); // inode cache
...@@ -95,7 +96,6 @@ cmain(u64 mbmagic, u64 mbaddr) ...@@ -95,7 +96,6 @@ cmain(u64 mbmagic, u64 mbaddr)
initlockstat(); initlockstat();
initpci(); initpci();
initnet(); initnet();
initidle();
if (VERBOSE) if (VERBOSE)
cprintf("ncpu %d %lu MHz\n", ncpu, cpuhz / 1000000); cprintf("ncpu %d %lu MHz\n", ncpu, cpuhz / 1000000);
......
...@@ -152,9 +152,13 @@ exit(void) ...@@ -152,9 +152,13 @@ exit(void)
// Parent might be sleeping in wait(). // Parent might be sleeping in wait().
acquire(&(myproc()->lock)); acquire(&(myproc()->lock));
// Kernel threads might not have a parent // Kernel threads might not have a parent
if (myproc()->parent != nullptr) if (myproc()->parent != nullptr)
cv_wakeup(&(myproc()->parent->cv)); cv_wakeup(&(myproc()->parent->cv));
else
idlezombie(myproc());
if (wakeupinit) if (wakeupinit)
cv_wakeup(&bootproc->cv); cv_wakeup(&bootproc->cv);
...@@ -458,6 +462,21 @@ fork(int flags) ...@@ -458,6 +462,21 @@ fork(int flags)
return pid; return pid;
} }
void
finishproc(struct proc *p)
{
ksfree(slab_stack, p->kstack);
p->kstack = 0;
p->vmap->decref();
if (!xnspid->remove(p->pid, &p))
panic("wait: ns_remove");
p->pid = 0;
p->parent = 0;
p->name[0] = 0;
p->killed = 0;
freeproc(p);
}
// Wait for a child process to exit and return its pid. // Wait for a child process to exit and return its pid.
// Return -1 if this process has no children. // Return -1 if this process has no children.
int int
...@@ -478,16 +497,7 @@ wait(void) ...@@ -478,16 +497,7 @@ wait(void)
pid = p->pid; pid = p->pid;
SLIST_REMOVE(&myproc()->childq, p, proc, child_next); SLIST_REMOVE(&myproc()->childq, p, proc, child_next);
release(&myproc()->lock); release(&myproc()->lock);
ksfree(slab_stack, p->kstack); finishproc(p);
p->kstack = 0;
p->vmap->decref();
if (!xnspid->remove(p->pid, &p))
panic("wait: ns_remove");
p->pid = 0;
p->parent = 0;
p->name[0] = 0;
p->killed = 0;
freeproc(p);
return pid; return pid;
} }
release(&p->lock); release(&p->lock);
...@@ -533,12 +543,12 @@ threadalloc(void (*fn)(void *), void *arg) ...@@ -533,12 +543,12 @@ threadalloc(void (*fn)(void *), void *arg)
p->context->rip = (u64)threadstub; p->context->rip = (u64)threadstub;
p->context->r12 = (u64)fn; p->context->r12 = (u64)fn;
p->context->r13 = (u64)arg; p->context->r13 = (u64)arg;
p->parent = myproc(); p->parent = nullptr;
p->cwd = 0; p->cwd = nullptr;
return p; return p;
} }
void struct proc*
threadpin(void (*fn)(void*), void *arg, const char *name, int cpu) threadpin(void (*fn)(void*), void *arg, const char *name, int cpu)
{ {
struct proc *p; struct proc *p;
...@@ -553,4 +563,5 @@ threadpin(void (*fn)(void*), void *arg, const char *name, int cpu) ...@@ -553,4 +563,5 @@ threadpin(void (*fn)(void*), void *arg, const char *name, int cpu)
acquire(&p->lock); acquire(&p->lock);
addrun(p); addrun(p);
release(&p->lock); release(&p->lock);
return p;
} }
...@@ -26,7 +26,7 @@ void ...@@ -26,7 +26,7 @@ void
post_swtch(void) post_swtch(void)
{ {
if (mycpu()->prev->get_state() == RUNNABLE && if (mycpu()->prev->get_state() == RUNNABLE &&
mycpu()->prev != idlep[mycpu()->id]) mycpu()->prev != idleproc())
addrun(mycpu()->prev); addrun(mycpu()->prev);
release(&mycpu()->prev->lock); release(&mycpu()->prev->lock);
} }
...@@ -42,6 +42,11 @@ sched(void) ...@@ -42,6 +42,11 @@ sched(void)
if(!holding(&myproc()->lock)) if(!holding(&myproc()->lock))
panic("sched proc->lock"); panic("sched proc->lock");
#endif #endif
if (myproc() == idleproc() &&
myproc()->get_state() != RUNNABLE) {
extern void idlebequeath(void);
idlebequeath();
}
if(mycpu()->ncli != 1) if(mycpu()->ncli != 1)
panic("sched locks"); panic("sched locks");
if(myproc()->get_state() == RUNNING) if(myproc()->get_state() == RUNNING)
...@@ -59,7 +64,7 @@ sched(void) ...@@ -59,7 +64,7 @@ sched(void)
struct proc *next = schednext(); struct proc *next = schednext();
if (next == nullptr) { if (next == nullptr) {
if (myproc()->get_state() != RUNNABLE) { if (myproc()->get_state() != RUNNABLE) {
next = idlep[mycpu()->id]; next = idleproc();
} else { } else {
myproc()->set_state(RUNNING); myproc()->set_state(RUNNING);
mycpu()->intena = intena; mycpu()->intena = intena;
......
...@@ -175,11 +175,11 @@ wq_trywork(void) ...@@ -175,11 +175,11 @@ wq_trywork(void)
struct work *w; struct work *w;
int i; int i;
pushcli(); //pushcli();
w = __wq_pop(mycpu()->id); w = __wq_pop(mycpu()->id);
if (w != nullptr) { if (w != nullptr) {
__wq_run(w); __wq_run(w);
popcli(); //popcli();
return 1; return 1;
} }
// XXX(sbw) should be random // XXX(sbw) should be random
...@@ -190,12 +190,12 @@ wq_trywork(void) ...@@ -190,12 +190,12 @@ wq_trywork(void)
w = __wq_steal(i); w = __wq_steal(i);
if (w != nullptr) { if (w != nullptr) {
__wq_run(w); __wq_run(w);
popcli(); //popcli();
return 1; return 1;
} }
} }
popcli(); //popcli();
return 0; return 0;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define ALLOC_MEMSET DEBUG #define ALLOC_MEMSET DEBUG
#define KSHAREDSIZE (32 << 10) #define KSHAREDSIZE (32 << 10)
#define WQSHIFT 7 #define WQSHIFT 7
#define CILKENABLE 0
#if defined(HW_josmp) #if defined(HW_josmp)
#define NCPU 16 // maximum number of CPUs #define NCPU 16 // maximum number of CPUs
#define MTRACE 0 #define MTRACE 0
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论