The start of a simple lockstat implementation

上级 52e99f8a
...@@ -91,7 +91,8 @@ UPROGS= \ ...@@ -91,7 +91,8 @@ UPROGS= \
_time \ _time \
_sleep \ _sleep \
_dirbench \ _dirbench \
_usertests _usertests \
_lockstat
UPROGS := $(addprefix $(O)/, $(UPROGS)) UPROGS := $(addprefix $(O)/, $(UPROGS))
all: $(O)/kernel all: $(O)/kernel
......
...@@ -48,6 +48,7 @@ struct devsw { ...@@ -48,6 +48,7 @@ struct devsw {
extern struct devsw devsw[]; extern struct devsw devsw[];
#define CONSOLE 1 #define CONSOLE 1
#define NETIF 2 #define NETIF 2
#define SAMPLER 3 #define SAMPLER 3
#define DEVLOCKSTAT 4
...@@ -44,10 +44,13 @@ main(void) ...@@ -44,10 +44,13 @@ main(void)
dup(0); // stdout dup(0); // stdout
dup(0); // stderr dup(0); // stderr
if (mknod("netif", 2, 1) < 0) mkdir("dev");
if (mknod("/dev/netif", 2, 1) < 0)
printf(2, "init: mknod netif failed\n"); printf(2, "init: mknod netif failed\n");
if (mknod("sampler", 3, 1) < 0) if (mknod("/dev/sampler", 3, 1) < 0)
printf(2, "init: mknod sampler failed\n"); printf(2, "init: mknod sampler failed\n");
if (mknod("/dev/lockstat", 4, 1) < 0)
printf(2, "init: mknod lockstat failed\n");
for (int i = 0; i < NELEM(app_argv); i++) for (int i = 0; i < NELEM(app_argv); i++)
startone(app_argv[i]); startone(app_argv[i]);
......
...@@ -270,6 +270,8 @@ int tryacquire(struct spinlock*); ...@@ -270,6 +270,8 @@ int tryacquire(struct spinlock*);
int holding(struct spinlock*); int holding(struct spinlock*);
void initlock(struct spinlock*, const char*); void initlock(struct spinlock*, const char*);
void release(struct spinlock*); void release(struct spinlock*);
void lockstat_init(struct spinlock *lk);
void lockstat_stop(struct spinlock *lk);
// syscall.c // syscall.c
int argint64(int, u64*); int argint64(int, u64*);
......
#include "types.h"
#include "stat.h"
#include "user.h"
#include "fcntl.h"
#include "amd64.h"
#include "lockstat.h"
static void
xwrite(int fd, char c)
{
if (write(fd, &c, 1) != 1)
die("lockstat: write failed");
}
static void
stats(void)
{
static const u64 sz = sizeof(struct lockstat);
struct lockstat ls;
int fd;
int r;
fd = open("/dev/lockstat", O_RDONLY);
if (fd < 0)
die("lockstat: open failed");
printf(1, "## name cycles acquires\n");
while (1) {
r = read(fd, &ls, sz);
if (r < 0)
die("lockstat: read failed");
if (r == 0)
break;
if (r != sz)
die("lockstat: unexpected read");
u64 cycles = 0, acquires = 0;
for (int i = 0; i < NCPU; i++) {
cycles += ls.cpu[i].cycles;
acquires += ls.cpu[i].acquires;
}
printf(1, "%s %lu %lu\n", ls.name, cycles, acquires);
}
}
int
main(int ac, char *av[])
{
int fd = open("/dev/lockstat", O_RDWR);
if (fd < 0)
die("lockstat: open failed");
xwrite(fd, '2');
xwrite(fd, '3');
int pid = fork(0);
if (pid < 0)
die("lockstat: fork failed");
if (pid == 0) {
xwrite(fd, '1');
exec(av[1], av+1);
die("lockstat: exec failed");
}
wait();
xwrite(fd, '2');
stats();
xwrite(fd, '3');
exit();
}
#include "queue.h"
struct cpulockstat {
u64 acquires;
u64 cycles;
__padout__;
} __mpalign__;
struct lockstat {
char name[16];
struct cpulockstat cpu[NCPU] __mpalign__;
};
struct klockstat {
u8 active;
LIST_ENTRY(klockstat) link;
struct lockstat s;
};
#define LOCKSTAT_START 1
#define LOCKSTAT_STOP 2
#define LOCKSTAT_CLEAR 3
...@@ -28,6 +28,7 @@ extern void initsamp(void); ...@@ -28,6 +28,7 @@ extern void initsamp(void);
extern void initpci(void); extern void initpci(void);
extern void initnet(void); extern void initnet(void);
extern void initsched(void); extern void initsched(void);
extern void initlockstat(void);
static volatile int bstate; static volatile int bstate;
...@@ -106,6 +107,7 @@ cmain(u64 mbmagic, u64 mbaddr) ...@@ -106,6 +107,7 @@ cmain(u64 mbmagic, u64 mbaddr)
initwq(); // work queues initwq(); // work queues
#endif #endif
initsamp(); initsamp();
initlockstat();
initpci(); initpci();
initnet(); initnet();
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#define VICTIMAGE 1000000 // cycles a proc executes before an eligible victim #define VICTIMAGE 1000000 // cycles a proc executes before an eligible victim
#define VERBOSE 0 // print kernel diagnostics #define VERBOSE 0 // print kernel diagnostics
#define SPINLOCK_DEBUG 1 // Debug spin locks #define SPINLOCK_DEBUG 1 // Debug spin locks
#define LOCKSTAT 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
......
...@@ -171,6 +171,13 @@ exit(void) ...@@ -171,6 +171,13 @@ exit(void)
panic("zombie exit"); panic("zombie exit");
} }
static void
freeproc(struct proc *p)
{
lockstat_stop(&p->lock);
gc_delayed(p, kmfree);
}
// Look in the process table for an UNUSED proc. // Look in the process table for an UNUSED proc.
// If found, change state to EMBRYO and initialize // If found, change state to EMBRYO and initialize
// state required to run in the kernel. // state required to run in the kernel.
...@@ -198,6 +205,7 @@ allocproc(void) ...@@ -198,6 +205,7 @@ allocproc(void)
snprintf(p->lockname, sizeof(p->lockname), "cv:proc:%d", p->pid); snprintf(p->lockname, sizeof(p->lockname), "cv:proc:%d", p->pid);
initlock(&p->lock, p->lockname+3); initlock(&p->lock, p->lockname+3);
lockstat_init(&p->lock);
initcondvar(&p->cv, p->lockname); initcondvar(&p->cv, p->lockname);
initwqframe(&p->wqframe); initwqframe(&p->wqframe);
...@@ -208,7 +216,7 @@ allocproc(void) ...@@ -208,7 +216,7 @@ allocproc(void)
if((p->kstack = ksalloc(slab_stack)) == 0){ if((p->kstack = ksalloc(slab_stack)) == 0){
if (ns_remove(nspid, KI(p->pid), p) == 0) if (ns_remove(nspid, KI(p->pid), p) == 0)
panic("allocproc: ns_remove"); panic("allocproc: ns_remove");
gc_delayed(p, kmfree); freeproc(p);
return 0; return 0;
} }
sp = p->kstack + KSTACKSIZE; sp = p->kstack + KSTACKSIZE;
...@@ -560,7 +568,7 @@ fork(int flags) ...@@ -560,7 +568,7 @@ fork(int flags)
np->state = UNUSED; np->state = UNUSED;
if (ns_remove(nspid, KI(np->pid), np) == 0) if (ns_remove(nspid, KI(np->pid), np) == 0)
panic("fork: ns_remove"); panic("fork: ns_remove");
gc_delayed(np, kmfree); freeproc(np);
return -1; return -1;
} }
} else { } else {
...@@ -626,7 +634,7 @@ wait(void) ...@@ -626,7 +634,7 @@ wait(void)
p->parent = 0; p->parent = 0;
p->name[0] = 0; p->name[0] = 0;
p->killed = 0; p->killed = 0;
gc_delayed(p, kmfree); freeproc(p);
return pid; return pid;
} }
release(&p->lock); release(&p->lock);
...@@ -665,7 +673,7 @@ threadalloc(void (*fn)(void *), void *arg) ...@@ -665,7 +673,7 @@ threadalloc(void (*fn)(void *), void *arg)
p->vmap = vmap_alloc(); p->vmap = vmap_alloc();
if (p->vmap == NULL) { if (p->vmap == NULL) {
gc_delayed(p, kmfree); freeproc(p);
return NULL; return NULL;
} }
......
...@@ -7,6 +7,13 @@ ...@@ -7,6 +7,13 @@
#include "bits.h" #include "bits.h"
#include "spinlock.h" #include "spinlock.h"
#include "mtrace.h" #include "mtrace.h"
#include "condvar.h"
#include "fs.h"
#include "file.h"
#if LOCKSTAT
static int lockstat_enable;
#endif
static inline void static inline void
locking(struct spinlock *lk) locking(struct spinlock *lk)
...@@ -31,6 +38,12 @@ locked(struct spinlock *lk) ...@@ -31,6 +38,12 @@ locked(struct spinlock *lk)
lk->cpu = mycpu(); lk->cpu = mycpu();
getcallerpcs(&lk, lk->pcs, NELEM(lk->pcs)); getcallerpcs(&lk, lk->pcs, NELEM(lk->pcs));
#endif #endif
#if LOCKSTAT
if (lockstat_enable && lk->stat != NULL) {
lk->stat->s.cpu[cpunum()].acquires++;
}
#endif
} }
static inline void static inline void
...@@ -67,6 +80,9 @@ initlock(struct spinlock *lk, const char *name) ...@@ -67,6 +80,9 @@ initlock(struct spinlock *lk, const char *name)
lk->name = name; lk->name = name;
lk->cpu = 0; lk->cpu = 0;
#endif #endif
#if LOCKSTAT
lk->stat = NULL;
#endif
lk->locked = 0; lk->locked = 0;
} }
...@@ -119,3 +135,134 @@ release(struct spinlock *lk) ...@@ -119,3 +135,134 @@ release(struct spinlock *lk)
popcli(); popcli();
} }
#if LOCKSTAT
LIST_HEAD(lockstat_list, klockstat);
static struct lockstat_list lockstat_list = LIST_HEAD_INITIALIZER(lockstat_list);
static struct spinlock lockstat_lock = {
.locked = 0,
#if SPINLOCK_DEBUG
.name = "lockstat",
.cpu = NULL,
#endif
};
void
lockstat_init(struct spinlock *lk)
{
if (lk->stat != NULL)
panic("initlockstat");
lk->stat = kmalloc(sizeof(*lk->stat));
if (lk->stat == NULL)
return;
memset(lk->stat, 0, sizeof(*lk->stat));
lk->stat->active = 1;
safestrcpy(lk->stat->s.name, lk->name, sizeof(lk->stat->s.name));
acquire(&lockstat_lock);
LIST_INSERT_HEAD(&lockstat_list, lk->stat, link);
release(&lockstat_lock);
}
void
lockstat_stop(struct spinlock *lk)
{
if (lk->stat != NULL) {
lk->stat->active = 0;
lk->stat = NULL;
}
}
void
lockstat_clear(void)
{
struct klockstat *stat, *tmp;
acquire(&lockstat_lock);
LIST_FOREACH_SAFE(stat, &lockstat_list, link, tmp) {
if (stat->active == 0) {
LIST_REMOVE(stat, link);
kmfree(stat);
} else {
memset(&stat->s.cpu, 0, sizeof(stat->s.cpu));
}
}
release(&lockstat_lock);
}
static int
lockstat_read(struct inode *ip, char *dst, u32 off, u32 n)
{
static const u64 sz = sizeof(struct lockstat);
struct klockstat *stat;
u32 cur;
if (off % sz || n < sz)
return -1;
cur = 0;
acquire(&lockstat_lock);
LIST_FOREACH(stat, &lockstat_list, link) {
struct lockstat *ls = &stat->s;
if (n < sizeof(*ls))
break;
if (cur >= off) {
memmove(dst, ls, sz);
dst += sz;
n -= sz;
}
cur += sz;
}
release(&lockstat_lock);
return cur >= off ? cur - off : 0;
}
static int
lockstat_write(struct inode *ip, char *buf, u32 off, u32 n)
{
int cmd = buf[0] - '0';
switch(cmd) {
case LOCKSTAT_START:
lockstat_enable = 1;
break;
case LOCKSTAT_STOP:
lockstat_enable = 0;
break;
case LOCKSTAT_CLEAR:
lockstat_clear();
break;
default:
return -1;
}
return n;
}
void
initlockstat(void)
{
devsw[DEVLOCKSTAT].write = lockstat_write;
devsw[DEVLOCKSTAT].read = lockstat_read;
}
#else
void
lockstat_init(struct spinlock *lk)
{
}
void
lockstat_stop(struct spinlock *lk)
{
}
void
initlockstat(void)
{
}
#endif
#pragma once #pragma once
#include "lockstat.h"
// Mutual exclusion lock. // Mutual exclusion lock.
struct spinlock { struct spinlock {
...@@ -11,6 +12,10 @@ struct spinlock { ...@@ -11,6 +12,10 @@ struct spinlock {
uptr pcs[10]; // The call stack (an array of program counters) uptr pcs[10]; // The call stack (an array of program counters)
// that locked the lock. // that locked the lock.
#endif #endif
#if LOCKSTAT
struct klockstat *stat;
#endif
}; };
#if SPINLOCK_DEBUG #if SPINLOCK_DEBUG
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论