On pagefault, allocate one page, zero if necessary, and load one page

if necessary The give a ~15% improvement in forkexecbench and makes xv6 a bit more comparable to Linux.
上级 9059c14f
...@@ -19,6 +19,7 @@ enum vmntype { EAGER, ONDEMAND }; ...@@ -19,6 +19,7 @@ enum vmntype { EAGER, ONDEMAND };
struct vmnode { struct vmnode {
const u64 npages; const u64 npages;
atomic<bool> empty;
atomic<char*> page[128]; atomic<char*> page[128];
const enum vmntype type; const enum vmntype type;
struct inode *const ip; struct inode *const ip;
...@@ -31,10 +32,13 @@ struct vmnode { ...@@ -31,10 +32,13 @@ struct vmnode {
void decref(); void decref();
void incref(); void incref();
u64 ref(); u64 ref();
int allocpg(bool zero = true); int allocall(bool zero = true);
int allocpg(int idx, bool zero = true);
int loadall();
int loadpg(off_t off);
vmnode* copy(); vmnode* copy();
int demand_load();
NEW_DELETE_OPS(vmnode); NEW_DELETE_OPS(vmnode);
private: private:
atomic<u64> ref_; atomic<u64> ref_;
......
...@@ -26,14 +26,15 @@ enum { tlb_lazy = 1 }; ...@@ -26,14 +26,15 @@ enum { tlb_lazy = 1 };
*/ */
vmnode::vmnode(u64 npg, vmntype ntype, inode *i, u64 off, u64 s) vmnode::vmnode(u64 npg, vmntype ntype, inode *i, u64 off, u64 s)
: npages(npg), type(ntype), ip(i), offset(off), sz(s), ref_(0) : npages(npg), empty(true), type(ntype),
ip(i), offset(off), sz(s), ref_(0)
{ {
if (npg > NELEM(page)) if (npg > NELEM(page))
panic("vmnode too big\n"); panic("vmnode too big\n");
memset(page, 0, npg * sizeof(page[0])); memset(page, 0, npg * sizeof(page[0]));
if (type == EAGER && ip) { if (type == EAGER && ip) {
assert(allocpg(false) == 0); assert(allocall(false) == 0);
assert(demand_load() == 0); assert(loadall() == 0);
} }
} }
...@@ -66,28 +67,40 @@ vmnode::ref(void) ...@@ -66,28 +67,40 @@ vmnode::ref(void)
} }
int int
vmnode::allocpg(bool zero) vmnode::allocpg(int idx, bool zero)
{ {
for(u64 i = 0; i < npages; i++) { char* p;
if (page[i])
continue; if (page[idx])
return 0;
if (zero)
p = zalloc("(vmnode::allocall)");
else
p = kalloc("(vmnode::allocall)");
if (p == nullptr)
return -1;
char *p; if(!cmpxch(&page[idx], (char*) 0, p)) {
if (zero) if (zero)
p = zalloc("(vmnode::allocpg)"); zfree(p);
else else
p = kalloc("(vmnode::allocpg)"); kfree(p);
} else if (empty) {
empty = false;
}
if (!p) { return 0;
cprintf("allocpg: OOM -- leaving half-filled vmnode\n"); }
return -1;
}
if(!cmpxch(&page[i], (char*) 0, p)) { int
if (zero) vmnode::allocall(bool zero)
zfree(p); {
else for(u64 i = 0; i < npages; i++) {
kfree(p); if (allocpg(i, zero) < 0) {
cprintf("allocall: OOM -- leaving half-filled vmnode\n");
return -1;
} }
} }
return 0; return 0;
...@@ -102,10 +115,10 @@ vmnode::copy() ...@@ -102,10 +115,10 @@ vmnode::copy()
if(c == 0) if(c == 0)
return 0; return 0;
if (!page[0]) // If first page is absent, all pages are absent if (empty)
return c; return c;
if (c->allocpg(false) < 0) { if (c->allocall(false) < 0) {
cprintf("vmn_copy: out of memory\n"); cprintf("vmn_copy: out of memory\n");
delete c; delete c;
return 0; return 0;
...@@ -118,27 +131,38 @@ vmnode::copy() ...@@ -118,27 +131,38 @@ vmnode::copy()
} }
int int
vmnode::demand_load() vmnode::loadpg(off_t off)
{ {
#ifdef MTRACE #ifdef MTRACE
mtreadavar("inode:%x.%x", ip->dev, ip->inum); mtreadavar("inode:%x.%x", ip->dev, ip->inum);
mtwriteavar("vmnode:%016x", this); mtwriteavar("vmnode:%016x", this);
#endif #endif
for (u64 i = 0; i < sz; i += PGSIZE) { char *p = page[off/PGSIZE];
char *p = page[i / PGSIZE]; s64 n;
s64 n; if (sz - off < PGSIZE)
if (sz - i < PGSIZE) n = sz - off;
n = sz - i; else
else n = PGSIZE;
n = PGSIZE;
//
// Possible race condition with concurrent loadpg() calls,
// if the underlying inode's contents change..
//
if (readi(ip, p, offset+off, n) != n)
return -1;
// XXX(sbw) we might leave the begining of page[0] and the
// end of page[npages-1] with some random content.
return 0;
}
/* int
* Possible race condition with concurrent demand_load() calls, vmnode::loadall()
* if the underlying inode's contents change.. {
*/ for (off_t o = 0; o < sz; o += PGSIZE)
if (readi(ip, p, offset+i, n) != n) if (loadpg(o) < 0)
return -1; return -1;
}
return 0; return 0;
} }
...@@ -584,12 +608,18 @@ vmap::pagefault(uptr va, u32 err) ...@@ -584,12 +608,18 @@ vmap::pagefault(uptr va, u32 err)
err, va, m->va_type, m->n->ref(), myproc()->pid); err, va, m->va_type, m->n->ref(), myproc()->pid);
if (m->n && !m->n->page[npg]) if (m->n && !m->n->page[npg])
if (m->n->allocpg() < 0) // m->n->ip != nullptr implies we'll copy over the page
panic("pagefault: couldn't allocate pages"); // with loadpg before returning
if (m->n->allocpg(npg, m->n->ip == nullptr) < 0) {
cprintf("pagefault: couldn't allocate pages\n");
return -1;
}
if (m->n && m->n->type == ONDEMAND) if (m->n && m->n->type == ONDEMAND)
if (m->n->demand_load() < 0) if (m->n->loadpg(npg*PGSIZE) < 0) {
panic("pagefault: couldn't load"); cprintf("pagefault: couldn't load\n");
return -1;
}
if (m->va_type == COW && (err & FEC_WR)) { if (m->va_type == COW && (err & FEC_WR)) {
if (pagefault_wcow(m) < 0) if (pagefault_wcow(m) < 0)
...@@ -647,7 +677,7 @@ vmap::copyout(uptr va, void *p, u64 len) ...@@ -647,7 +677,7 @@ vmap::copyout(uptr va, void *p, u64 len)
if(vma == 0) if(vma == 0)
return -1; return -1;
vma->n->allocpg(); vma->n->allocall();
uptr pn = (va0 - vma->vma_start) / PGSIZE; uptr pn = (va0 - vma->vma_start) / PGSIZE;
char *p0 = vma->n->page[pn]; char *p0 = vma->n->page[pn];
if(p0 == 0) if(p0 == 0)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
extern "C" void zpage(void*); extern "C" void zpage(void*);
extern "C" void zrun_nc(run*); extern "C" void zrun_nc(run*);
static const bool prezero = true;
struct zallocator { struct zallocator {
run* run; run* run;
kmem kmem; kmem kmem;
...@@ -52,7 +54,7 @@ struct zwork : public work { ...@@ -52,7 +54,7 @@ struct zwork : public work {
void void
zallocator::tryrefill(void) zallocator::tryrefill(void)
{ {
if (kmem.nfree < 16 && frame.zero()) { if (prezero && kmem.nfree < 16 && frame.zero()) {
zwork* w = new zwork(&frame, this); zwork* w = new zwork(&frame, this);
if (wq_push(w) < 0) if (wq_push(w) < 0)
delete w; delete w;
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论