提交 a2c48700 创建 作者: Silas Boyd-Wickizer's avatar Silas Boyd-Wickizer

Try to parallelize exec.c with the work queue.

上级 3bc0f1e2
......@@ -15,6 +15,59 @@
#include "vm.h"
#define USTACKPAGES 2
#define BRK (USERTOP >> 1)
static const int odp = 1;
struct eargs {
struct inode *ip;
struct vmap *vmap;
};
static void
dosegment(uptr a0, u64 a1)
{
struct eargs *args = (void*) a0;
u64 off = a1;
struct vmnode *vmn = NULL;
struct proghdr ph;
if(readi(args->ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph))
goto bad;
if(ph.type != ELF_PROG_LOAD) {
return;
}
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");
goto bad;
}
uptr va_start = PGROUNDDOWN(ph.vaddr);
uptr va_end = PGROUNDUP(ph.vaddr + ph.memsz);
int npg = (va_end - va_start) / PGSIZE;
if (odp) {
if ((vmn = vmn_alloc(npg, ONDEMAND)) == 0)
goto bad;
} else {
if ((vmn = vmn_allocpg(npg)) == 0)
goto bad;
}
if(vmn_load(vmn, args->ip, ph.offset, ph.filesz) < 0)
goto bad;
if(vmap_insert(args->vmap, vmn, ph.vaddr) < 0)
goto bad;
return;
bad:
panic("dosegment: Oops");
}
int
exec(char *path, char **argv)
......@@ -25,7 +78,127 @@ exec(char *path, char **argv)
struct elfhdr elf;
struct proghdr ph;
uptr brk = 0;
int odp = 1;
u64 off;
int i;
uptr sp;
int argc;
uptr ustack[1+MAXARG+1];
char *s, *last;
struct vmap *oldvmap;
if((ip = namei(path)) == 0)
return -1;
rcu_begin_read();
// Check ELF header
if(ip->type != T_FILE)
goto bad;
if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
goto bad;
if(elf.magic != ELF_MAGIC)
goto bad;
if((vmap = vmap_alloc()) == 0)
goto bad;
struct eargs args;
args.ip = ip;
args.vmap = vmap;
wq_start();
for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){
wq_push(dosegment, (uptr)&args, (uptr)off);
}
if (odp) {
// iunlock(ip);
} else {
// iunlockput(ip);
iput(ip);
ip = 0;
}
brk = BRK;
// Allocate a vmnode for the heap.
// XXX pre-allocate 32 pages..
if((vmn = vmn_allocpg(32)) == 0)
goto bad;
if(vmap_insert(vmap, vmn, brk) < 0)
goto bad;
vmn = 0;
// Allocate a one-page stack at the top of the (user) address space
if((vmn = vmn_allocpg(USTACKPAGES)) == 0)
goto bad;
if(vmap_insert(vmap, vmn, USERTOP-(USTACKPAGES*PGSIZE)) < 0)
goto bad;
vmn = 0;
wq_end();
// Push argument strings, prepare rest of stack in ustack.
sp = USERTOP;
for(argc = 0; argv[argc]; argc++) {
if(argc >= MAXARG)
goto bad;
sp -= strlen(argv[argc]) + 1;
sp &= ~7;
if(copyout(vmap, sp, argv[argc], strlen(argv[argc]) + 1) < 0)
goto bad;
ustack[1+argc] = sp;
}
ustack[1+argc] = 0;
ustack[0] = 0xffffffffffffffffull; // fake return PC
myproc()->tf->rdi = argc;
myproc()->tf->rsi = sp - (argc+1)*8;
sp -= (1+argc+1) * 8;
if(copyout(vmap, sp, ustack, (1+argc+1)*8) < 0)
goto bad;
// Save program name for debugging.
for(last=s=path; *s; s++)
if(*s == '/')
last = s+1;
safestrcpy(myproc()->name, last, sizeof(myproc()->name));
// Commit to the user image.
oldvmap = myproc()->vmap;
myproc()->vmap = vmap;
myproc()->brk = brk + 8; // XXX so that brk-1 points within heap vma..
myproc()->tf->rip = elf.entry; // main
myproc()->tf->rsp = sp;
switchuvm(myproc());
vmap_decref(oldvmap);
migrate(myproc());
rcu_end_read();
return 0;
bad:
cprintf("exec failed\n");
if(vmap)
vmap_decref(vmap);
if(vmn)
vmn_free(vmn);
rcu_end_read();
return 0;
}
#if 0
int
exec(char *path, char **argv)
{
struct inode *ip = NULL;
struct vmap *vmap = NULL;
struct vmnode *vmn = NULL;
struct elfhdr elf;
struct proghdr ph;
uptr brk = 0;
u64 off;
int i;
uptr sp;
......@@ -84,6 +257,7 @@ exec(char *path, char **argv)
goto bad;
vmn = 0;
}
if (odp) {
// iunlock(ip);
} else {
......@@ -92,6 +266,8 @@ exec(char *path, char **argv)
ip = 0;
}
brk = BRK;
// Allocate a vmnode for the heap.
// XXX pre-allocate 32 pages..
if((vmn = vmn_allocpg(32)) == 0)
......@@ -159,3 +335,4 @@ exec(char *path, char **argv)
return 0;
}
#endif
......@@ -274,8 +274,21 @@ void updatepages(pml4e_t*, void*, void*, int);
struct vmap * vmap_copy(struct vmap *, int);
// wq.c
#if WQENABLE
void wq_push(void *rip, u64 arg0, u64 arg1);
void wq_start(void);
void wq_end(void);
void wq_dump(void);
int wq_trywork(void);
void initwqframe(struct wqframe *wq);
#else
#define wq_push(rip, arg0, arg1) do { \
void (*fn)(uptr, uptr) = rip; \
fn(arg0, arg1); \
} while(0)
#define wq_start() do { } while(0)
#define wq_end() do { } while(0)
#define wq_dump() do { } while(0)
#define wq_trywork() 0
#define initwqframe(x) do { } while (0)
#endif
......@@ -96,7 +96,9 @@ cmain(void)
initbio(); // buffer cache
initinode(); // inode cache
initdisk(); // disk
#if WQENABLE
initwq(); // work queues
#endif
cprintf("ncpu %d %lu MHz\n", ncpu, cpuhz / 1000000);
......
......@@ -18,3 +18,4 @@
#define CPUKSTACKS (NPROC + NCPU)
#define QUANTUN 10 // scheduling time quantum and tick length (in msec)
#define WQSHIFT 4 // 2^WORKSHIFT work queue slots
#define WQENABLE 0 // Enable work queue
......@@ -316,8 +316,8 @@ scheduler(void)
myproc()->cpu_pin = 1;
// Test the work queue
extern void testwq(void);
testwq();
//extern void testwq(void);
//testwq();
// Enabling mtrace calls in scheduler generates many mtrace_call_entrys.
// mtrace_call_set(1, cpu->id);
......@@ -381,8 +381,13 @@ scheduler(void)
}
if (idle[mycpu()->id]) {
int worked;
do {
worked = wq_trywork();
} while(worked);
sti();
hlt();
if (!WQENABLE)
hlt();
}
}
}
......
#if WQENABLE
#include "types.h"
#include "kernel.h"
#include "param.h"
#include "amd64.h"
#include "cpu.h"
#include "bits.h"
......@@ -119,6 +119,7 @@ __wq_run(struct wqthread *th)
void (*fn)(uptr arg0, uptr arg1) = (void*)th->rip;
fn(th->arg0, th->arg1);
subfetch(th->ref, 1);
kfree(th);
}
// Add the (rip, arg0, arg1) work to the local work queue.
......@@ -140,9 +141,10 @@ wq_push(void *rip, u64 arg0, u64 arg1)
th->arg1 = arg1;
th->ref = &wq_frame()->ref;
if (__wq_push(wq_cur(), th))
if (__wq_push(wq_cur(), th)) {
kfree(th);
fn(arg0, arg1);
else
} else
fetchadd(&wq_frame()->ref, 1);
}
......@@ -265,3 +267,4 @@ initwq(void)
initlock(&queue[i].lock, "queue lock");
}
}
#endif // WQENABLE
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论