提交 c132eade 创建 作者: 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

#include "types.h"
#include "stat.h"
#include "user.h"
#include "fs.h"
const char*
fmtname(const char *path)
{
static char buf[DIRSIZ+1];
const char *p;
// Find first character after last slash.
for(p=path+strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if(strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));
return buf;
}
void
ls(const char *path)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if((fd = open(path, 0)) < 0){
fprintf(2, "ls: cannot open %s\n", path);
return;
}
if(fstat(fd, &st) < 0){
fprintf(2, "ls: cannot stat %s\n", path);
close(fd);
return;
}
switch(st.type){
case T_FILE:
fprintf(1, "%s %d %d %d\n", fmtname(path), st.type, st.ino, st.size);
break;
case T_DIR:
if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
fprintf(1, "ls: path too long\n");
break;
}
strcpy(buf, path);
p = buf+strlen(buf);
*p++ = '/';
while(read(fd, &de, sizeof(de)) == sizeof(de)){
if(de.inum == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if(stat(buf, &st) < 0){
fprintf(1, "ls: cannot stat %s\n", buf);
continue;
}
fprintf(1, "%s %d %d %d\n", fmtname(buf), st.type, st.ino, st.size);
}
break;
}
close(fd);
}
void
work(void *arg)
{
u64 tid = (u64)arg;
// grab and push work (may divide into blocks? and call ls on a block)?
// maybe implement getdirent sys call that gives you some unread dir entry
}
int
main(int argc, char *argv[])
{
int i;
int nthread = 4;
for(int i = 0; i < nthread; i++) {
sbrk(8192);
void *tstack = sbrk(0);
// fprintf(1, "tstack %lx\n", tstack);
int tid = forkt(tstack, (void*) thr, (void *)(u64)i);
if (0) fprintf(1, "pls[%d]: child %d\n", getpid(), tid);
}
// push work wq.cc
if(argc < 2){
ls(".");
exit();
}
for(i=1; i<argc; i++)
ls(argv[i]);
for(int i = 0; i < nthread; i++)
wait();
exit();
}
......@@ -263,54 +263,27 @@ struct work * allocwork(void);
void freework(struct work *w);
// cilk.c
void initcilkframe(struct cilkframe*);
#if CILKENABLE
void cilk_push(void (*fn)(uptr, uptr), u64 arg0, u64 arg1);
void cilk_start(void);
void cilk_end(void);
u64 cilk_end(void);
void cilk_dump(void);
int cilk_trywork(void);
void initcilkframe(struct cilkframe *wq);
void cilk_abort(u64 val);
#else
#define cilk_push(rip, arg0, arg1) do { \
void (*fn)(uptr, uptr) = rip; \
fn(arg0, arg1); \
} while(0)
#define cilk_start() do { } while(0)
#define cilk_end() do { } while(0)
#define cilk_end() (myproc()->cilkframe.abort)
#define cilk_dump() do { } while(0)
#define cilk_trywork() 0
#define initcilkframe(x) do { } while (0)
#define cilk_abort(val) do { \
cmpxch(&myproc()->cilkframe.abort, (u64)0, (u64)val); \
} while (0)
#endif
// various init functions
void initpic(void);
void initioapic(void);
void inituart(void);
void initcga(void);
void initconsole(void);
void initpg(void);
void initmp(void);
void initlapic(void);
void inittls(void);
void initnmi(void);
void inittrap(void);
void initseg(void);
void initkalloc(u64 mbaddr);
void initrcu(void);
void initproc(void);
void initbio(void);
void initinode(void);
void initdisk(void);
void inituser(void);
void initcilk(void);
void initsamp(void);
void initpci(void);
void initnet(void);
void initsched(void);
void initlockstat(void);
void initwq(void);
void initsperf(void);
// other exported/imported functions
void cmain(u64 mbmagic, u64 mbaddr);
void mpboot(void);
......
......@@ -24,6 +24,7 @@
#define PGROUNDUP(sz) (((sz)+PGSIZE-1) & ~(PGSIZE-1))
#define PGROUNDDOWN(a) ((__typeof__(a))((((uptr)(a)) & ~(PGSIZE-1))))
#define PGOFFSET(a) ((a) & ((1<<PGSHIFT)-1))
// Address in page table or page directory entry
#define PTE_ADDR(pte) ((uptr)(pte) & ~0xFFF)
......
......@@ -19,6 +19,7 @@ struct context {
// Work queue frame
struct cilkframe {
volatile std::atomic<u64> ref;
volatile std::atomic<u64> abort;
};
// Per-process, per-stack meta data for mtrace
......
// cilk style run queue
// A work queue is built from NCPU per-core wqueues.
// A core pushes work to the head of its per-core wqueue.
// A core pops work from the head of its per-core wqueue.
// cilk style run queue built on wq.cc:
// A core pushes work to the head of its per-core wq.
// A core pops work from the head of its per-core wq.
// A core pops work from the tail of another core's per-core wqueue.
//
// Usage:
......@@ -25,7 +24,6 @@
// cprintf("%c %c\n", arg[0], arg[1]);
// }
#if CILKENABLE
#include "types.h"
#include "kernel.hh"
#include "amd64.h"
......@@ -35,37 +33,18 @@
#include "condvar.h"
#include "queue.h"
#include "proc.hh"
#if CILKENABLE
#include "mtrace.h"
#include "wq.hh"
#define NSLOTS (1 << CILKSHIFT)
struct cilkqueue {
struct cilkthread *thread[NSLOTS];
volatile int head __mpalign__;
struct spinlock lock;
volatile int tail;
__padout__;
} __mpalign__;
struct cilkthread {
u64 rip;
u64 arg0;
u64 arg1;
struct cilkframe *frame; // parent cilkframe
__padout__;
} __mpalign__;
#include "percpu.hh"
struct cilkstat {
u64 push;
u64 full;
u64 steal;
__padout__;
} __mpalign__;
static struct cilkqueue queue[NCPU] __mpalign__;
static struct cilkstat stat[NCPU] __mpalign__;
};
static percpu<cilkstat> stat;
static struct cilkframe *
cilk_frame(void)
......@@ -73,12 +52,6 @@ cilk_frame(void)
return mycpu()->cilkframe;
}
static struct cilkstat *
cilk_stat(void)
{
return &stat[mycpu()->id];
}
static void
__cilk_run(struct work *w, void *xfn, void *arg0, void *arg1, void *xframe)
{
......@@ -87,9 +60,10 @@ __cilk_run(struct work *w, void *xfn, void *arg0, void *arg1, void *xframe)
struct cilkframe *old = mycpu()->cilkframe;
if (old != frame)
cilk_stat()->steal++;
stat->steal++;
mycpu()->cilkframe = frame;
if (frame->abort == 0)
fn((uptr)arg0, (uptr)arg1);
mycpu()->cilkframe = old;
frame->ref--;
......@@ -117,10 +91,10 @@ cilk_push(void (*fn)(uptr, uptr), u64 arg0, u64 arg1)
if (wq_push(w)) {
freework(w);
fn(arg0, arg1);
cilk_stat()->full++;
stat->full++;
} else {
cilk_frame()->ref++;
cilk_stat()->push++;
stat->push++;
}
}
......@@ -138,14 +112,26 @@ cilk_start(void)
// End of the current work queue frame.
// The core works while the reference count of the current
// work queue frame is not 0.
void
u64
cilk_end(void)
{
u64 r;
while (cilk_frame()->ref != 0)
wq_trywork();
r = cilk_frame()->abort;
mycpu()->cilkframe = 0;
popcli();
return r;
}
void
cilk_abort(u64 val)
{
cmpxch(&cilk_frame()->abort, (u64)0, val);
}
void
......@@ -189,19 +175,11 @@ testcilk(void)
}
popcli();
}
#endif // CILKENABLE
void
initcilkframe(struct cilkframe *cilk)
{
memset(cilk, 0, sizeof(*cilk));
}
void
initcilk(void)
{
int i;
for (i = 0; i < NCPU; i++)
initlock(&queue[i].lock, "queue lock", LOCKSTAT_CILK);
cilk->ref = 0;
cilk->abort = 0;
}
#endif // CILKENABLE
......@@ -34,6 +34,10 @@ dosegment(uptr a0, u64 a1)
u64 off = a1;
struct vmnode *vmn = nullptr;
struct proghdr ph;
uptr va_start, va_end;
uptr in_off;
uptr in_sz;
int npg;
prof_start(dosegment_prof);
if(readi(args->ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
......@@ -42,33 +46,30 @@ dosegment(uptr a0, u64 a1)
goto bad;
if(ph.memsz < ph.filesz)
goto bad;
// XXX(sbw) vaddr doesn't have to be page aligned..
if(ph.vaddr % PGSIZE) {
cprintf("unaligned ph.va\n");
if (ph.offset < PGOFFSET(ph.vaddr))
goto bad;
}
{
uptr va_start = PGROUNDDOWN(ph.vaddr);
uptr va_end = PGROUNDUP(ph.vaddr + ph.memsz);
va_start = PGROUNDDOWN(ph.vaddr);
va_end = PGROUNDUP(ph.vaddr + ph.memsz);
in_off = ph.offset - PGOFFSET(ph.vaddr);
in_sz = ph.filesz + PGOFFSET(ph.vaddr);
int npg = (va_end - va_start) / PGSIZE;
npg = (va_end - va_start) / PGSIZE;
if ((vmn = new vmnode(npg, odp ? ONDEMAND : EAGER,
args->ip, ph.offset, ph.filesz)) == 0)
args->ip, in_off, in_sz)) == 0)
goto bad;
if(args->vmap->insert(vmn, ph.vaddr, 1) < 0)
if(args->vmap->insert(vmn, va_start, 1) < 0)
goto bad;
prof_end(dosegment_prof);
return;
}
bad:
panic("dosegment: Oops");
cilk_abort(-1);
}
static void dostack(uptr a0, u64 a1)
static void __attribute__((unused)) dostack(uptr a0, u64 a1)
{
struct vmnode *vmn = nullptr;
struct eargs *args = (eargs*) a0;
......@@ -110,18 +111,19 @@ static void dostack(uptr a0, u64 a1)
for(last=s=args->path; *s; s++)
if(*s == '/')
last = s+1;
safestrcpy(args->proc->name, last, sizeof(args->proc->name));
// XXX(sbw) Oops, don't want to do this, unless we have abort
safestrcpy(args->proc->name, last, sizeof(args->proc->name));
args->proc->tf->rsp = sp;
prof_end(dostack_prof);
return;
bad:
panic("dostack: Oops");
cilk_abort(-1);
}
static void doheap(uptr a0, u64 a1)
static void __attribute__((unused)) doheap(uptr a0, u64 a1)
{
struct vmnode *vmn = nullptr;
struct eargs *args = (eargs*) a0;
......@@ -138,7 +140,7 @@ static void doheap(uptr a0, u64 a1)
return;
bad:
panic("doheap: Oops");
cilk_abort(-1);
}
int
......@@ -204,7 +206,8 @@ exec(const char *path, char **argv)
//cilk_push(dostack, (uptr)&args, (uptr)0);
dostack((uptr)&args, (uptr)0);
cilk_end();
if (cilk_end())
goto bad;
// Commit to the user image.
oldvmap = myproc()->vmap;
......
......@@ -9,8 +9,34 @@
#include "condvar.h"
#include "proc.hh"
extern void initidle(void);
extern void idleloop(void);
void initpic(void);
void initioapic(void);
void inituart(void);
void initcga(void);
void initconsole(void);
void initpg(void);
void initmp(void);
void initlapic(void);
void inittls(void);
void initnmi(void);
void inittrap(void);
void initseg(void);
void initkalloc(u64 mbaddr);
void initrcu(void);
void initproc(void);
void initbio(void);
void initinode(void);
void initdisk(void);
void inituser(void);
void initsamp(void);
void initpci(void);
void initnet(void);
void initsched(void);
void initlockstat(void);
void initwq(void);
void initsperf(void);
void initidle(void);
void idleloop(void);
static volatile int bstate;
......@@ -89,9 +115,6 @@ cmain(u64 mbmagic, u64 mbaddr)
initinode(); // inode cache
initdisk(); // disk
initwq();
#if CILKENABLE
initcilk();
#endif
initsamp();
initlockstat();
initpci();
......
......@@ -109,10 +109,18 @@ wq_push2(void (*fn)(struct work*, void*, void*), void *a0, void *a1)
return 0;
}
static struct work *
static void
__wq_run(struct work *w)
{
void (*fn)(struct work*, void*, void*, void*, void*, void*) =
(void(*)(work*,void*,void*,void*,void*,void*))w->rip;
fn(w, w->arg0, w->arg1, w->arg2, w->arg3, w->arg4);
freework(w);
}
static inline struct work *
__wq_pop(int c)
{
// Called with cli
struct wqueue *wq = &queue[c];
struct work *w;
int i;
......@@ -136,10 +144,9 @@ __wq_pop(int c)
return w;
}
static struct work *
static inline struct work *
__wq_steal(int c)
{
// Called with cli
struct wqueue *wq = &queue[c];
struct work *w;
int i;
......@@ -160,42 +167,34 @@ __wq_steal(int c)
return w;
}
static void
__wq_run(struct work *w)
{
void (*fn)(struct work*, void*, void*, void*, void*, void*) =
(void(*)(work*,void*,void*,void*,void*,void*))w->rip;
fn(w, w->arg0, w->arg1, w->arg2, w->arg3, w->arg4);
freework(w);
}
int
wq_trywork(void)
{
struct work *w;
int i;
int i, k;
// A "random" victim CPU
k = rdtsc();
//pushcli();
w = __wq_pop(mycpu()->id);
if (w != nullptr) {
__wq_run(w);
//popcli();
return 1;
}
// XXX(sbw) should be random
for (i = 0; i < NCPU; i++) {
if (i == mycpu()->id)
int j = (i+k) % NCPU;
if (j == mycpu()->id)
continue;
w = __wq_steal(i);
w = __wq_steal(j);
if (w != nullptr) {
__wq_run(w);
//popcli();
return 1;
}
}
//popcli();
return 0;
}
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论