提交 359dab4a 创建 作者: Frans Kaashoek's avatar Frans Kaashoek

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

...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Q ?= @ Q ?= @
TOOLPREFIX ?= x86_64-jos-elf- TOOLPREFIX ?= x86_64-jos-elf-
QEMU ?= qemu-system-x86_64 QEMU ?= qemu-system-x86_64
QEMUSMP ?= 4 QEMUSMP ?= 8
QEMUSRC ?= ../mtrace QEMUSRC ?= ../mtrace
MTRACE ?= $(QEMU) MTRACE ?= $(QEMU)
HW ?= qemu HW ?= qemu
......
...@@ -78,6 +78,9 @@ main(int ac, char **av) ...@@ -78,6 +78,9 @@ main(int ac, char **av)
pthread_t tid; pthread_t tid;
pthread_create(&tid, 0, op, (void*) i); pthread_create(&tid, 0, op, (void*) i);
} }
for (u64 i = 0; i < ncore; i++)
wait();
mtdisable("xv6-asharing"); mtdisable("xv6-asharing");
} }
} }
...@@ -3,12 +3,19 @@ ...@@ -3,12 +3,19 @@
#include "user.h" #include "user.h"
#include "lib.h" #include "lib.h"
#include "fcntl.h" #include "fcntl.h"
#include "wq.hh"
static int branch;
static void static void
dolevel(int fd, int branch, int depth) dolevel(int fd, int depth)
{ {
if (depth > 0) { if (depth > 0) {
for (int i = 0; i < branch; i++) { int it = 0;
wq_for_serial<int>(it,
[](int &it)->bool { return it < branch; },
[&fd, &depth](int i)->void
{
char name[] = "a"; char name[] = "a";
*name += i; *name += i;
if (mkdirat(fd, name) < 0) if (mkdirat(fd, name) < 0)
...@@ -16,9 +23,9 @@ dolevel(int fd, int branch, int depth) ...@@ -16,9 +23,9 @@ dolevel(int fd, int branch, int depth)
int nfd = openat(fd, name, O_RDONLY); int nfd = openat(fd, name, O_RDONLY);
if (nfd < 0) if (nfd < 0)
die("openat"); die("openat: %s at %u", name, depth);
dolevel(nfd, branch, depth-1); dolevel(nfd, depth-1);
} });
} }
close(fd); close(fd);
...@@ -30,8 +37,10 @@ main(int ac, char **av) ...@@ -30,8 +37,10 @@ main(int ac, char **av)
if (ac < 4) if (ac < 4)
die("usage: %s dir branch depth", av[0]); die("usage: %s dir branch depth", av[0]);
initwq();
const char *dir = av[1]; const char *dir = av[1];
int branch = atoi(av[2]); branch = atoi(av[2]);
int depth = atoi(av[3]); int depth = atoi(av[3]);
if (mkdir(dir)) if (mkdir(dir))
...@@ -41,5 +50,5 @@ main(int ac, char **av) ...@@ -41,5 +50,5 @@ main(int ac, char **av)
if (fd < 0) if (fd < 0)
die("open"); die("open");
dolevel(fd, branch, depth); dolevel(fd, depth);
} }
...@@ -127,6 +127,5 @@ main(int ac, char **av) ...@@ -127,6 +127,5 @@ main(int ac, char **av)
test0(); test0();
testfork(); testfork();
execwork::test(); execwork::test();
exitwq();
return 0; return 0;
} }
...@@ -51,15 +51,12 @@ du(int fd) ...@@ -51,15 +51,12 @@ du(int fd)
[](dirit &i)->bool { return !i.end(); }, [](dirit &i)->bool { return !i.end(); },
[&size, &fd](const char *name)->void [&size, &fd](const char *name)->void
{ {
if (!strcmp(name, ".") || !strcmp(name, "..")) { if (!strcmp(name, ".") || !strcmp(name, ".."))
free((void*)name);
return; return;
}
int nfd = openat(fd, name, 0); int nfd = openat(fd, name, 0);
if (nfd >= 0) if (nfd >= 0)
size += du(nfd); // should go into work queue size += du(nfd); // should go into work queue
free((void*)name);
}); });
} else { } else {
close(fd); close(fd);
...@@ -79,6 +76,5 @@ main(int ac, char **av) ...@@ -79,6 +76,5 @@ main(int ac, char **av)
perf_stop(); perf_stop();
printf("%ld\n", s); printf("%ld\n", s);
wq_dump(); wq_dump();
exitwq();
return 0; return 0;
} }
...@@ -67,14 +67,12 @@ ls(const char *path) ...@@ -67,14 +67,12 @@ ls(const char *path)
struct stat st; struct stat st;
if (xfstatat(fd, name, &st) < 0){ if (xfstatat(fd, name, &st) < 0){
printf("ls: cannot stat %s\n", name); printf("ls: cannot stat %s\n", name);
free((void*)name);
return; return;
} }
if (!silent) if (!silent)
printf("%u %10lu %10lu %s\n", printf("%u %10lu %10lu %s\n",
ST_TYPE(st), ST_INO(st), ST_SIZE(st), name); ST_TYPE(st), ST_INO(st), ST_SIZE(st), name);
free((void*)name);
}); });
} else { } else {
close(fd); close(fd);
...@@ -99,6 +97,5 @@ main(int argc, char *argv[]) ...@@ -99,6 +97,5 @@ main(int argc, char *argv[])
perf_stop(); perf_stop();
wq_dump(); wq_dump();
exitwq();
return 0; return 0;
} }
...@@ -13,14 +13,6 @@ public: ...@@ -13,14 +13,6 @@ public:
return *this; return *this;
} }
const char * copy_value() {
char *buf = (char*)malloc(256);
return name(buf, 256);
}
bool end() const { return end_; }
private:
char *name(char *buf, size_t n) const { char *name(char *buf, size_t n) const {
n = MIN(DIRSIZ+1, n); n = MIN(DIRSIZ+1, n);
memmove(buf, de_.name, n-1); memmove(buf, de_.name, n-1);
...@@ -28,6 +20,9 @@ private: ...@@ -28,6 +20,9 @@ private:
return buf; return buf;
} }
bool end() const { return end_; }
private:
void refill(void) { void refill(void) {
int r; int r;
...@@ -45,3 +40,16 @@ private: ...@@ -45,3 +40,16 @@ private:
bool end_; bool end_;
struct dirent de_; struct dirent de_;
}; };
static inline const char*
copy_value(dirit &it)
{
char *buf = (char*)malloc(256);
return it.name(buf, 256);
}
static inline void
free_value(dirit &it, const char *name)
{
free((void*)name);
}
...@@ -4,3 +4,7 @@ ...@@ -4,3 +4,7 @@
#define O_CREATE 0x200 #define O_CREATE 0x200
#define AT_FDCWD -100 #define AT_FDCWD -100
#define FORK_SHARE_VMAP (1<<0)
#define FORK_SHARE_FD (1<<1)
...@@ -91,6 +91,7 @@ struct inode* ialloc(u32, short); ...@@ -91,6 +91,7 @@ struct inode* ialloc(u32, short);
struct inode* namei(inode *cwd, const char*); struct inode* namei(inode *cwd, const char*);
void iput(struct inode*); void iput(struct inode*);
struct inode* iget(u32 dev, u32 inum); struct inode* iget(u32 dev, u32 inum);
struct inode* igetnoref(u32 dev, u32 inum);
void ilock(struct inode*, int writer); void ilock(struct inode*, int writer);
void iunlockput(struct inode*); void iunlockput(struct inode*);
void iupdate(struct inode*); void iupdate(struct inode*);
......
...@@ -52,6 +52,7 @@ struct klockstat; ...@@ -52,6 +52,7 @@ struct klockstat;
#define LOCKSTAT_KALLOC 1 #define LOCKSTAT_KALLOC 1
#define LOCKSTAT_KMALLOC 1 #define LOCKSTAT_KMALLOC 1
#define LOCKSTAT_NET 1 #define LOCKSTAT_NET 1
#define LOCKSTAT_NS 1
#define LOCKSTAT_PIPE 1 #define LOCKSTAT_PIPE 1
#define LOCKSTAT_PROC 1 #define LOCKSTAT_PROC 1
#define LOCKSTAT_SCHED 1 #define LOCKSTAT_SCHED 1
......
#pragma once #pragma once
#include "gc.hh" #include "gc.hh"
#include "percpu.hh"
// name spaces // name spaces
// XXX maybe use open hash table, no chain, better cache locality // XXX maybe use open hash table, no chain, better cache locality
...@@ -15,11 +16,19 @@ template<class K, class V> ...@@ -15,11 +16,19 @@ template<class K, class V>
class xelem : public rcu_freed { class xelem : public rcu_freed {
public: public:
V val; V val;
std::atomic<int> next_lock;
std::atomic<xelem<K, V>*> volatile next;
K key; K key;
xelem(const K &k, const V &v) : rcu_freed("xelem"), val(v), next_lock(0), next(0), key(k) {} std::atomic<int> next_lock;
std::atomic<xelem<K, V>*> next;
int percore_c;
std::atomic<xelem<K, V>*> percore_next;
std::atomic<xelem<K, V>*>* percore_pprev;
xelem(const K &k, const V &v)
: rcu_freed("xelem"), val(v), key(k),
next_lock(0), next(0),
percore_next(0), percore_pprev(0) {}
virtual void do_gc() { virtual void do_gc() {
delete this; delete this;
} }
...@@ -39,6 +48,8 @@ class xns : public rcu_freed { ...@@ -39,6 +48,8 @@ class xns : public rcu_freed {
bool allowdup; bool allowdup;
std::atomic<u64> nextkey; std::atomic<u64> nextkey;
xbucket<K, V> table[NHASH]; xbucket<K, V> table[NHASH];
std::atomic<xelem<K, V>*> percore[NCPU];
spinlock percore_lock[NCPU];
public: public:
xns(bool dup) : rcu_freed("xns") { xns(bool dup) : rcu_freed("xns") {
...@@ -46,6 +57,10 @@ class xns : public rcu_freed { ...@@ -46,6 +57,10 @@ class xns : public rcu_freed {
nextkey = 1; nextkey = 1;
for (int i = 0; i < NHASH; i++) for (int i = 0; i < NHASH; i++)
table[i].chain = 0; table[i].chain = 0;
for (int i = 0; i < NCPU; i++) {
percore[i] = nullptr;
initlock(&percore_lock[i], "xns_lock", LOCKSTAT_NS);
}
} }
~xns() { ~xns() {
...@@ -86,10 +101,20 @@ class xns : public rcu_freed { ...@@ -86,10 +101,20 @@ class xns : public rcu_freed {
} }
e->next = root.load(); e->next = root.load();
if (cmpxch(&table[i].chain, e->next.load(), e)) if (cmpxch(&table[i].chain, e->next.load(), e)) {
int c = mycpuid();
acquire(&percore_lock[c]);
e->percore_c = c;
e->percore_next = percore[c].load();
if (percore[c])
percore[c].load()->percore_pprev = &e->percore_next;
e->percore_pprev = &percore[c];
percore[c] = e;
release(&percore_lock[c]);
return 0; return 0;
} }
} }
}
V lookup(const K &key) { V lookup(const K &key) {
u64 i = h(key); u64 i = h(key);
...@@ -134,6 +159,13 @@ class xns : public rcu_freed { ...@@ -134,6 +159,13 @@ class xns : public rcu_freed {
break; break;
} }
int c = e->percore_c;
acquire(&percore_lock[c]);
*e->percore_pprev = e->percore_next.load();
if (e->percore_next)
e->percore_next.load()->percore_pprev = e->percore_pprev;
release(&percore_lock[c]);
*pelock = 0; *pelock = 0;
gc_delayed(e); gc_delayed(e);
return true; return true;
...@@ -148,12 +180,13 @@ class xns : public rcu_freed { ...@@ -148,12 +180,13 @@ class xns : public rcu_freed {
template<class CB> template<class CB>
void enumerate(CB cb) { void enumerate(CB cb) {
scoped_gc_epoch gc; scoped_gc_epoch gc;
for (int i = 0; i < NHASH; i++) { int cpuoffset = mycpuid();
auto e = table[i].chain.load(); for (int i = 0; i < NCPU; i++) {
auto e = percore[(i + cpuoffset) % NCPU].load();
while (e) { while (e) {
if (cb(e->key, e->val)) if (cb(e->key, e->val))
return; return;
e = e->next; e = e->percore_next;
} }
} }
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
* A page-table-like structure for mapping fixed-length keys to void* ptrs. * A page-table-like structure for mapping fixed-length keys to void* ptrs.
*/ */
#include "gc.hh"
#include "markptr.hh" #include "markptr.hh"
enum { bits_per_level = 9 }; enum { bits_per_level = 9 };
......
...@@ -54,7 +54,7 @@ void free(void*); ...@@ -54,7 +54,7 @@ void free(void*);
int atoi(const char*); int atoi(const char*);
// uthread.S // uthread.S
int forkt(void *sp, void *pc, void *arg); int forkt(void *sp, void *pc, void *arg, int forkflags);
void forkt_setup(u64 pid); void forkt_setup(u64 pid);
// printf.c // printf.c
......
...@@ -13,7 +13,7 @@ struct forwork : public work { ...@@ -13,7 +13,7 @@ struct forwork : public work {
: it_(it), cond_(cond), body_(body), frame_(frame) {} : it_(it), cond_(cond), body_(body), frame_(frame) {}
virtual void run() { virtual void run() {
decltype(it_.copy_value()) v = it_.copy_value(); decltype(copy_value(it_)) v = copy_value(it_);
++it_; ++it_;
if (cond_(it_)) { if (cond_(it_)) {
forwork<IT, BODY> *w = new forwork<IT, BODY>(it_, cond_, body_, frame_); forwork<IT, BODY> *w = new forwork<IT, BODY>(it_, cond_, body_, frame_);
...@@ -21,6 +21,7 @@ struct forwork : public work { ...@@ -21,6 +21,7 @@ struct forwork : public work {
wq_push(w); wq_push(w);
} }
body_(v); body_(v);
free_value(it_, v);
frame_.dec(); frame_.dec();
delete this; delete this;
} }
...@@ -48,15 +49,48 @@ wq_for(IT &init, bool (*cond)(IT &it), BODY body) ...@@ -48,15 +49,48 @@ wq_for(IT &init, bool (*cond)(IT &it), BODY body)
// XXX(sbw) should be able to coarsen loop // XXX(sbw) should be able to coarsen loop
decltype(init.copy_value()) v = init.copy_value(); if (!cond(init))
return;
decltype(copy_value(init)) v = copy_value(init);
++init; ++init;
if (cond(init)) { if (cond(init)) {
forwork<IT, BODY> *w = new forwork<IT, BODY>(init, cond, body, frame); forwork<IT, BODY> *w = new forwork<IT, BODY>(init, cond, body, frame);
frame.inc(); frame.inc();
wq_push(w); wq_push(w);
} }
body(v); body(v);
free_value(init, v);
while (!frame.zero()) while (!frame.zero())
wq_trywork(); wq_trywork();
} }
// For debugging
// Same API as wq_for but serially executes body
template <typename IT, typename BODY>
static inline void
wq_for_serial(IT &init, bool (*cond)(IT &it), BODY body)
{
for (; cond(init); ++init) {
decltype(copy_value(init)) v = copy_value(init);
body(v);
free_value(init, v);
}
}
// Default copy_value
template <typename T>
static inline T
copy_value(T &it)
{
return it;
}
// Default free_value
template <typename T>
static inline void
free_value(T &it, T &v)
{
}
...@@ -43,9 +43,4 @@ wqarch_init(void) ...@@ -43,9 +43,4 @@ wqarch_init(void)
{ {
} }
static inline void
wqarch_exit(void)
{
}
#define xprintf cprintf #define xprintf cprintf
...@@ -92,12 +92,6 @@ wqarch_init(void) ...@@ -92,12 +92,6 @@ wqarch_init(void)
pthread_setspecific(idkey, (void*)(u64)id); pthread_setspecific(idkey, (void*)(u64)id);
} }
static inline void
wqarch_exit(void)
{
exiting = 1;
}
#define xprintf printf #define xprintf printf
#define pushcli() #define pushcli()
#define popcli() #define popcli()
...@@ -46,11 +46,11 @@ static struct buf* ...@@ -46,11 +46,11 @@ static struct buf*
bget(u32 dev, u64 sector, int *writer) bget(u32 dev, u64 sector, int *writer)
{ {
struct buf *b; struct buf *b;
scoped_gc_epoch e;
loop: loop:
// Try for cached block. // Try for cached block.
// XXX ignore dev // XXX ignore dev
gc_begin_epoch();
b = bufns->lookup(mkpair(dev, sector)); b = bufns->lookup(mkpair(dev, sector));
if (b) { if (b) {
if (b->dev != dev || b->sector != sector) if (b->dev != dev || b->sector != sector)
...@@ -60,7 +60,6 @@ bget(u32 dev, u64 sector, int *writer) ...@@ -60,7 +60,6 @@ bget(u32 dev, u64 sector, int *writer)
if (b->flags & B_BUSY) { if (b->flags & B_BUSY) {
cv_sleep(&b->cv, &b->lock); cv_sleep(&b->cv, &b->lock);
release(&b->lock); release(&b->lock);
gc_end_epoch();
goto loop; goto loop;
} }
...@@ -72,45 +71,15 @@ bget(u32 dev, u64 sector, int *writer) ...@@ -72,45 +71,15 @@ bget(u32 dev, u64 sector, int *writer)
// rcu_end_read() happens in brelse // rcu_end_read() happens in brelse
return b; return b;
} }
gc_end_epoch();
// Allocate fresh block. // Allocate fresh block.
struct buf *victim = 0;
bufns->enumerate([&victim](const pair<u32, u64>&, buf *eb)->bool {
acquire(&eb->lock);
if ((eb->flags & (B_BUSY | B_DIRTY | B_VALID)) == 0) {
victim = eb;
return true;
}
release(&eb->lock);
return false;
});
if (victim == 0)
bufns->enumerate([&victim](const pair<u32, u64>&, buf *eb)->bool {
acquire(&eb->lock);
if ((eb->flags & (B_BUSY | B_DIRTY)) == 0) {
victim = eb;
return true;
}
release(&eb->lock);
return false;
});
if (victim == 0)
panic("bget all busy");
victim->flags |= B_BUSY;
bufns->remove(mkpair(victim->dev, victim->sector), &victim);
release(&victim->lock);
gc_delayed(victim);
b = new buf(dev, sector); b = new buf(dev, sector);
b->flags = B_BUSY; b->flags = B_BUSY;
*writer = 1; *writer = 1;
gc_begin_epoch();
if (bufns->insert(mkpair(b->dev, b->sector), b) < 0) { if (bufns->insert(mkpair(b->dev, b->sector), b) < 0) {
gc_delayed(b); gc_delayed(b);
goto loop; goto loop;
} }
// rcu_end_read() happens in brelse
return b; return b;
} }
...@@ -152,8 +121,6 @@ brelse(struct buf *b, int writer) ...@@ -152,8 +121,6 @@ brelse(struct buf *b, int writer)
b->flags &= ~B_BUSY; b->flags &= ~B_BUSY;
cv_wakeup(&b->cv); cv_wakeup(&b->cv);
} }
// rcu_begin_read() happens in bread
gc_end_epoch();
} }
void void
......
...@@ -10,6 +10,22 @@ ...@@ -10,6 +10,22 @@
// routines. The (higher-level) system call implementations // routines. The (higher-level) system call implementations
// are in sysfile.c. // are in sysfile.c.
/*
* inode cache will be RCU-managed:
*
* - to evict, mark inode as a victim
* - lookups that encounter a victim inode must return an error (-E_RETRY)
* - E_RETRY rolls back to the beginning of syscall/pagefault and retries
* - out-of-memory error should be treated like -E_RETRY
* - once an inode is marked as victim, it can be gc_delayed()
* - the do_gc() method should remove inode from the namespace & free it
*
* - inodes have a refcount that lasts beyond a GC epoch
* - to bump refcount, first bump, then check victim flag
* - if victim flag is set, reduce the refcount and -E_RETRY
*
*/
#include "types.h" #include "types.h"
#include "stat.h" #include "stat.h"
#include "mmu.h" #include "mmu.h"
...@@ -185,7 +201,7 @@ ialloc(u32 dev, short type) ...@@ -185,7 +201,7 @@ ialloc(u32 dev, short type)
//cprintf("ialloc oops %d\n", inum); // XXX harmless //cprintf("ialloc oops %d\n", inum); // XXX harmless
} }
} }
cprintf("ialloc: no inodes\n"); cprintf("ialloc: 0/%u inodes\n", sb.ninodes);
return nullptr; return nullptr;
} }
...@@ -239,21 +255,21 @@ inode::~inode() ...@@ -239,21 +255,21 @@ inode::~inode()
struct inode* struct inode*
iget(u32 dev, u32 inum) iget(u32 dev, u32 inum)
{ {
struct inode *ip; struct inode *ip = igetnoref(dev, inum);
if (ip)
idup(ip);
return ip;
}
struct inode*
igetnoref(u32 dev, u32 inum)
{
retry: retry:
// Try for cached inode. // Try for cached inode.
gc_begin_epoch(); {
ip = ins->lookup(mkpair(dev, inum)); scoped_gc_epoch e;
struct inode *ip = ins->lookup(mkpair(dev, inum));
if (ip) { if (ip) {
// tricky: first bump ref, then check free flag
ip->ref++;
if (ip->flags & I_FREE) {
gc_end_epoch();
ip->ref--;
goto retry;
}
gc_end_epoch();
if (!(ip->flags & I_VALID)) { if (!(ip->flags & I_VALID)) {
acquire(&ip->lock); acquire(&ip->lock);
while((ip->flags & I_VALID) == 0) while((ip->flags & I_VALID) == 0)
...@@ -262,49 +278,13 @@ iget(u32 dev, u32 inum) ...@@ -262,49 +278,13 @@ iget(u32 dev, u32 inum)
} }
return ip; return ip;
} }
gc_end_epoch();
// Allocate fresh inode cache slot.
retry_evict:
(void) 0;
u32 cur_free = icache_free[mycpu()->id].x;
if (cur_free == 0) {
struct inode *victim = 0;
ins->enumerate([&victim](const pair<u32, u32>&, inode* eip)->bool{
if (eip->ref || eip->type == T_DIR)
return false;
acquire(&eip->lock);
if (eip->ref == 0 && eip->type != T_DIR &&
!(eip->flags & (I_FREE | I_BUSYR | I_BUSYW))) {
victim = eip;
return true;
} }
release(&eip->lock); // Allocate fresh inode cache slot.
return false; struct inode *ip = new inode();
});
if (!victim)
panic("iget out of space");
// tricky: first flag as free, then check refcnt, then remove from ns
victim->flags |= I_FREE;
if (victim->ref > 0) {
victim->flags &= ~(I_FREE);
release(&victim->lock);
goto retry_evict;
}
release(&victim->lock);
ins->remove(mkpair(victim->dev, victim->inum), &victim);
gc_delayed(victim);
} else {
if (!cmpxch(&icache_free[mycpu()->id].x, cur_free, cur_free-1))
goto retry_evict;
}
ip = new inode();
ip->dev = dev; ip->dev = dev;
ip->inum = inum; ip->inum = inum;
ip->ref = 1; ip->ref = 0;
ip->flags = I_BUSYR | I_BUSYW; ip->flags = I_BUSYR | I_BUSYW;
ip->readbusy = 1; ip->readbusy = 1;
snprintf(ip->lockname, sizeof(ip->lockname), "cv:ino:%d", ip->inum); snprintf(ip->lockname, sizeof(ip->lockname), "cv:ino:%d", ip->inum);
...@@ -366,7 +346,7 @@ ilock(struct inode *ip, int writer) ...@@ -366,7 +346,7 @@ ilock(struct inode *ip, int writer)
void void
iunlock(struct inode *ip) iunlock(struct inode *ip)
{ {
if(ip == 0 || !(ip->flags & (I_BUSYR | I_BUSYW)) || ip->ref < 1) if(ip == 0 || !(ip->flags & (I_BUSYR | I_BUSYW)))
panic("iunlock"); panic("iunlock");
acquire(&ip->lock); acquire(&ip->lock);
...@@ -407,6 +387,9 @@ iput(struct inode *ip) ...@@ -407,6 +387,9 @@ iput(struct inode *ip)
ip->flags |= (I_BUSYR | I_BUSYW); ip->flags |= (I_BUSYR | I_BUSYW);
ip->readbusy++; ip->readbusy++;
// XXX: use gc_delayed() to truncate the inode later.
// flag it as a victim in the meantime.
release(&ip->lock); release(&ip->lock);
itrunc(ip); itrunc(ip);
...@@ -619,7 +602,10 @@ namecmp(const char *s, const char *t) ...@@ -619,7 +602,10 @@ namecmp(const char *s, const char *t)
u64 u64
namehash(const strbuf<DIRSIZ> &n) namehash(const strbuf<DIRSIZ> &n)
{ {
return n._buf[0]; /* XXX */ u64 h = 0;
for (int i = 0; i < DIRSIZ && n._buf[i]; i++)
h = ((h << 8) ^ n._buf[i]) % 0xdeadbeef;
return h;
} }
void void
...@@ -751,12 +737,12 @@ namex(inode *cwd, const char *path, int nameiparent, char *name) ...@@ -751,12 +737,12 @@ namex(inode *cwd, const char *path, int nameiparent, char *name)
{ {
struct inode *ip, *next; struct inode *ip, *next;
int r; int r;
scoped_gc_epoch e;
gc_begin_epoch();
if(*path == '/') if(*path == '/')
ip = iget(ROOTDEV, ROOTINO); ip = igetnoref(ROOTDEV, ROOTINO);
else else
ip = idup(cwd); ip = cwd;
while((r = skipelem(&path, name)) == 1){ while((r = skipelem(&path, name)) == 1){
// XXX Doing this here requires some annoying reasoning about all // XXX Doing this here requires some annoying reasoning about all
...@@ -773,32 +759,30 @@ namex(inode *cwd, const char *path, int nameiparent, char *name) ...@@ -773,32 +759,30 @@ namex(inode *cwd, const char *path, int nameiparent, char *name)
if(next == 0){ if(next == 0){
if(ip->type == 0) if(ip->type == 0)
panic("namex"); panic("namex");
if(ip->type != T_DIR){ if(ip->type != T_DIR)
iput(ip);
gc_end_epoch();
return 0; return 0;
}
if(nameiparent && *path == '\0'){ if(nameiparent && *path == '\0'){
// Stop one level early. // Stop one level early.
gc_end_epoch(); idup(ip);
return ip; return ip;
} }
if((next = dirlookup(ip, name)) == 0){ if((next = dirlookup(ip, name)) == 0)
iput(ip);
gc_end_epoch();
return 0; return 0;
} }
iput(ip);
}
ip = next; ip = next;
} }
if(r == -1 || nameiparent){
iput(ip); if(r == -1 || nameiparent)
gc_end_epoch();
return 0; return 0;
}
mtreadavar("inode:%x.%x", ip->dev, ip->inum); // XXX write is necessary because of idup. not logically required,
gc_end_epoch(); // so we should replace this with mtreadavar() eventually, perhaps
// once we implement sloppy counters for long-term inode refs.
// mtreadavar("inode:%x.%x", ip->dev, ip->inum);
mtwriteavar("inode:%x.%x", ip->dev, ip->inum);
idup(ip);
return ip; return ip;
} }
......
...@@ -142,17 +142,11 @@ cpunum(void) ...@@ -142,17 +142,11 @@ cpunum(void)
{ {
// Cannot call cpu when interrupts are enabled: // Cannot call cpu when interrupts are enabled:
// result not guaranteed to last long enough to be used! // result not guaranteed to last long enough to be used!
// Would prefer to panic but even printing is chancy here:
// almost everything, including cprintf and panic, calls cpu,
// often indirectly through acquire and release.
if(readrflags()&FL_IF){ if(readrflags()&FL_IF){
static int n __mpalign__; cli();
if(n == 0) { panic("cpunum() called from %p with interrupts enabled\n",
n++;
cprintf("cpu called from %p with interrupts enabled\n",
__builtin_return_address(0)); __builtin_return_address(0));
} }
}
if(lapic) if(lapic)
return lapic[ID]>>24; return lapic[ID]>>24;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "kalloc.hh" #include "kalloc.hh"
#include "vm.hh" #include "vm.hh"
#include "ns.hh" #include "ns.hh"
#include "fcntl.h"
u64 u64
proc_hash(const u32 &p) proc_hash(const u32 &p)
...@@ -344,7 +345,10 @@ fork(int flags) ...@@ -344,7 +345,10 @@ fork(int flags)
if((np = proc::alloc()) == 0) if((np = proc::alloc()) == 0)
return -1; return -1;
if(flags == 0) { if(flags & FORK_SHARE_VMAP) {
np->vmap = myproc()->vmap;
np->vmap->ref++;
} else {
// Copy process state from p. // Copy process state from p.
if((np->vmap = myproc()->vmap->copy(cow)) == 0){ if((np->vmap = myproc()->vmap->copy(cow)) == 0){
ksfree(slab_stack, np->kstack); ksfree(slab_stack, np->kstack);
...@@ -354,9 +358,6 @@ fork(int flags) ...@@ -354,9 +358,6 @@ fork(int flags)
freeproc(np); freeproc(np);
return -1; return -1;
} }
} else {
np->vmap = myproc()->vmap;
np->vmap->ref++;
} }
np->parent = myproc(); np->parent = myproc();
...@@ -366,16 +367,16 @@ fork(int flags) ...@@ -366,16 +367,16 @@ fork(int flags)
// Clear %eax so that fork returns 0 in the child. // Clear %eax so that fork returns 0 in the child.
np->tf->rax = 0; np->tf->rax = 0;
if (flags == 0) { if (flags & FORK_SHARE_FD) {
myproc()->ftable->incref();
np->ftable = myproc()->ftable;
} else {
np->ftable = new filetable(*myproc()->ftable); np->ftable = new filetable(*myproc()->ftable);
if (np->ftable == nullptr) { if (np->ftable == nullptr) {
// XXX(sbw) leaking? // XXX(sbw) leaking?
freeproc(np); freeproc(np);
return -1; return -1;
} }
} else {
myproc()->ftable->incref();
np->ftable = myproc()->ftable;
} }
np->cwd = idup(myproc()->cwd); np->cwd = idup(myproc()->cwd);
......
#include "types.h" #include "crange_arch.hh"
#include "atomic.hh"
#include "spinlock.h"
#include "kernel.hh"
#include "cpputil.hh"
#include "radix.hh" #include "radix.hh"
// Returns the level we stopped at. // Returns the level we stopped at.
......
...@@ -215,6 +215,9 @@ create(inode *cwd, const char *path, short type, short major, short minor) ...@@ -215,6 +215,9 @@ create(inode *cwd, const char *path, short type, short major, short minor)
{ {
struct inode *ip, *dp; struct inode *ip, *dp;
char name[DIRSIZ]; char name[DIRSIZ];
mt_ascope ascope("%s(%d.%d,%s,%d,%d,%d)",
__func__, cwd->dev, cwd->inum,
path, type, major, minor);
retry: retry:
if((dp = nameiparent(cwd, path, name)) == 0) if((dp = nameiparent(cwd, path, name)) == 0)
...@@ -239,6 +242,8 @@ create(inode *cwd, const char *path, short type, short major, short minor) ...@@ -239,6 +242,8 @@ create(inode *cwd, const char *path, short type, short major, short minor)
ip->nlink = 1; ip->nlink = 1;
iupdate(ip); iupdate(ip);
mtwriteavar("inode:%x.%x", ip->dev, ip->inum);
if(type == T_DIR){ // Create . and .. entries. if(type == T_DIR){ // Create . and .. entries.
dp->nlink++; // for ".." dp->nlink++; // for ".."
iupdate(dp); iupdate(dp);
...@@ -291,6 +296,10 @@ sys_openat(int dirfd, const char *path, int omode) ...@@ -291,6 +296,10 @@ sys_openat(int dirfd, const char *path, int omode)
if(omode & O_CREATE){ if(omode & O_CREATE){
if((ip = create(cwd, path, T_FILE, 0, 0)) == 0) if((ip = create(cwd, path, T_FILE, 0, 0)) == 0)
return -1; return -1;
// XXX necessary because the mtwriteavar() to the same abstract variable
// does not propagate to our scope, since create() has its own inner scope.
mtwriteavar("inode:%x.%x", ip->dev, ip->inum);
} else { } else {
retry: retry:
if((ip = namei(cwd, path)) == 0) if((ip = namei(cwd, path)) == 0)
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "pthread.h" #include "pthread.h"
#include "user.h" #include "user.h"
#include "atomic.hh" #include "atomic.hh"
#include "fcntl.h"
enum { stack_size = 8192 }; enum { stack_size = 8192 };
static std::atomic<int> nextkey; static std::atomic<int> nextkey;
...@@ -22,7 +23,7 @@ pthread_create(pthread_t* tid, const pthread_attr_t* attr, ...@@ -22,7 +23,7 @@ pthread_create(pthread_t* tid, const pthread_attr_t* attr,
void* (*start)(void*), void* arg) void* (*start)(void*), void* arg)
{ {
char* base = (char*) sbrk(stack_size); char* base = (char*) sbrk(stack_size);
int t = forkt(base + stack_size, (void*) start, arg); int t = forkt(base + stack_size, (void*) start, arg, FORK_SHARE_VMAP | FORK_SHARE_FD);
if (t < 0) if (t < 0)
return t; return t;
......
...@@ -12,7 +12,7 @@ forkt: ...@@ -12,7 +12,7 @@ forkt:
movq %rdx, 0x00(%r12) # arg movq %rdx, 0x00(%r12) # arg
movq %rsi, 0x08(%r12) # function ptr movq %rsi, 0x08(%r12) # function ptr
movq $1, %rdi # flag for sys_fork movq %rcx, %rdi # flag for sys_fork
movq $SYS_fork, %rax movq $SYS_fork, %rax
syscall syscall
......
...@@ -79,12 +79,6 @@ initwq(void) ...@@ -79,12 +79,6 @@ initwq(void)
wqarch_init(); wqarch_init();
} }
void
exitwq(void)
{
wqarch_exit();
}
// //
// wq // wq
// //
......
...@@ -11,8 +11,8 @@ ...@@ -11,8 +11,8 @@
#include "include/stat.h" #include "include/stat.h"
int nblocks = 4067; int nblocks = 4067;
int ninodes = 200; int ninodes = 800;
int size = 4096; int size = 4172;
int fsfd; int fsfd;
struct superblock sb; struct superblock sb;
......
CXXFLAGS := -iquote user $(filter-out -nostdinc++ -Istdinc, $(CXXFLAGS)) -msse CXXFLAGS := -iquote user $(filter-out -nostdinc++ -Istdinc -Inet, $(CXXFLAGS)) -msse
$(O)/utest: $(O)/kernel/crange.o \ $(O)/utest: $(O)/kernel/crange.o \
$(O)/kernel/gc.o \ $(O)/kernel/gc.o \
$(O)/kernel/rnd.o \ $(O)/kernel/rnd.o \
$(O)/kernel/radix.o \
$(O)/user/umain.o $(O)/user/umain.o
@echo " LD $@" @echo " LD $@"
$(Q)mkdir -p $(@D) $(Q)mkdir -p $(@D)
......
...@@ -133,6 +133,12 @@ mycpu() ...@@ -133,6 +133,12 @@ mycpu()
return (cpu*) &cpus[myproc()->cpuid]; return (cpu*) &cpus[myproc()->cpuid];
} }
static inline int
mycpuid()
{
return mycpu()->id;
}
static inline void pushcli() {} static inline void pushcli() {}
static inline void popcli() {} static inline void popcli() {}
......
#include <unistd.h> #include <unistd.h>
#include <signal.h> #include <signal.h>
#include <getopt.h> #include <getopt.h>
#include <string.h>
#include "crange_arch.hh" #include "crange_arch.hh"
#include "gc.hh" #include "gc.hh"
#include "crange.hh" #include "crange.hh"
#include "radix.hh"
#include "atomic_util.hh" #include "atomic_util.hh"
#include "ns.hh" #include "ns.hh"
#include "uscopedperf.hh" #include "uscopedperf.hh"
...@@ -80,8 +82,13 @@ threadpin(void (*fn)(void*), void *arg, const char *name, int cpu) ...@@ -80,8 +82,13 @@ threadpin(void (*fn)(void*), void *arg, const char *name, int cpu)
makeproc(p); makeproc(p);
} }
struct my_range : public range { struct my_crange_range : public range {
my_range(crange *cr, u64 k, u64 sz) : range(cr, k, sz) {} my_crange_range(crange *cr, u64 k, u64 sz) : range(cr, k, sz) {}
virtual void do_gc() { delete this; }
};
struct my_radix_range : public radix_elem {
my_radix_range(radix *cr, u64 k, u64 sz) {}
virtual void do_gc() { delete this; } virtual void do_gc() { delete this; }
}; };
...@@ -92,7 +99,7 @@ enum { crange_items = 1024 }; ...@@ -92,7 +99,7 @@ enum { crange_items = 1024 };
enum { random_keys = 0 }; enum { random_keys = 0 };
static void static void
worker(void *arg) worker_crange(void *arg)
{ {
crange *cr = (crange*) arg; crange *cr = (crange*) arg;
...@@ -106,7 +113,7 @@ worker(void *arg) ...@@ -106,7 +113,7 @@ worker(void *arg)
span.replace(0); span.replace(0);
} else { } else {
ANON_REGION("worker add", &perfgroup); ANON_REGION("worker add", &perfgroup);
span.replace(new my_range(cr, k, 1)); span.replace(new my_crange_range(cr, k, 1));
} }
} }
...@@ -114,16 +121,48 @@ worker(void *arg) ...@@ -114,16 +121,48 @@ worker(void *arg)
} }
static void static void
populate(void *arg) populate_crange(void *arg)
{ {
crange *cr = (crange*) arg; crange *cr = (crange*) arg;
for (u32 i = 0; i < crange_items; i++) for (u32 i = 0; i < crange_items; i++)
cr->search_lock(1 + 2*i, 1).replace(new my_range(cr, 1+2*i, 1)); cr->search_lock(1 + 2*i, 1).replace(new my_crange_range(cr, 1+2*i, 1));
pthread_barrier_wait(&populate_b);
}
static void
worker_radix(void *arg)
{
radix *cr = (radix*) arg;
for (u32 i = 0; i < iter_total / ncpu; i++) {
ANON_REGION("worker op", &perfgroup);
u64 rval = random_keys ? rnd<u32>() : myproc()->cpuid;
u64 k = 1 + rval % (crange_items * 2);
auto span = cr->search_lock(k, 1);
if (rnd<u8>() & 1) {
ANON_REGION("worker del", &perfgroup);
span.replace(k, 1, 0);
} else {
ANON_REGION("worker add", &perfgroup);
span.replace(k, 1, new my_radix_range(cr, k, 1));
}
}
pthread_barrier_wait(&worker_b);
}
static void
populate_radix(void *arg)
{
radix *cr = (radix*) arg;
for (u32 i = 0; i < crange_items; i++)
cr->search_lock(1 + 2*i, 1).replace(1+2*i, 1, new my_radix_range(cr, 1+2*i, 1));
pthread_barrier_wait(&populate_b); pthread_barrier_wait(&populate_b);
} }
static const struct option long_opts[] = { static const struct option long_opts[] = {
{ "ncpu", required_argument, 0, 'n' }, { "ncpu", required_argument, 0, 'n' },
{ "tree-type", required_argument, 0, 't' },
{ 0, no_argument, 0, 0 } { 0, no_argument, 0, 0 }
}; };
...@@ -140,14 +179,17 @@ l2(u64 v) ...@@ -140,14 +179,17 @@ l2(u64 v)
return l; return l;
} }
enum { type_crange, type_radix };
int int
main(int ac, char **av) main(int ac, char **av)
{ {
ncpu = NCPU; ncpu = NCPU;
int treetype = type_crange;
for (;;) { for (;;) {
int long_idx; int long_idx;
int opt = getopt_long(ac, av, "n:", long_opts, &long_idx); int opt = getopt_long(ac, av, "n:t:", long_opts, &long_idx);
if (opt == -1) if (opt == -1)
break; break;
...@@ -157,6 +199,15 @@ main(int ac, char **av) ...@@ -157,6 +199,15 @@ main(int ac, char **av)
assert(ncpu <= NCPU); assert(ncpu <= NCPU);
break; break;
case 't':
if (!strcmp(optarg, "crange"))
treetype = type_crange;
else if (!strcmp(optarg, "radix"))
treetype = type_radix;
else
assert(0);
break;
case '?': case '?':
printf("Options:\n"); printf("Options:\n");
for (u32 i = 0; long_opts[i].name; i++) for (u32 i = 0; long_opts[i].name; i++)
...@@ -178,15 +229,25 @@ main(int ac, char **av) ...@@ -178,15 +229,25 @@ main(int ac, char **av)
initgc(); initgc();
pthread_barrier_init(&populate_b, 0, 2); pthread_barrier_init(&populate_b, 0, 2);
crange cr(l2(crange_items)); crange cr(l2(crange_items));
threadpin(populate, &cr, "populate", 0); radix rr(0);
if (treetype == type_crange)
threadpin(populate_crange, &cr, "populate", 0);
else if (treetype == type_radix)
threadpin(populate_radix, &rr, "populate", 0);
pthread_barrier_wait(&populate_b); pthread_barrier_wait(&populate_b);
pthread_barrier_init(&worker_b, 0, ncpu+1); pthread_barrier_init(&worker_b, 0, ncpu+1);
for (u32 i = 0; i < ncpu; i++) { for (u32 i = 0; i < ncpu; i++) {
char buf[32]; char buf[32];
sprintf(buf, "worker%d", i); sprintf(buf, "worker%d", i);
threadpin(worker, &cr, buf, i); if (treetype == type_crange)
threadpin(worker_crange, &cr, buf, i);
else if (treetype == type_radix)
threadpin(worker_radix, &rr, buf, i);
} }
pthread_barrier_wait(&worker_b); pthread_barrier_wait(&worker_b);
......
...@@ -83,11 +83,6 @@ wqarch_init(void) ...@@ -83,11 +83,6 @@ wqarch_init(void)
} }
} }
static inline void
wqarch_exit(void)
{
}
#define xprintf printf #define xprintf printf
#define pushcli() #define pushcli()
#define popcli() #define popcli()
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论