Memory Allocator
struct {
struct spinlock lock;
struct run *freelist;
int num;//当前freelist中数量
} kmem[NCPU];
const int name_size = sizeof("kmem cpu 0");
char kmem_lk_name[NCPU][sizeof("kmem cpu 0")];
void
kinit()
{
initlock(&stealLock, "stealLock");
for(int i = 0;i < NCPU; i++){
snprintf(kmem_lk_name[i], name_size, "kmem cpu %d", i);
initlock(&kmem[i].lock, kmem_lk_name[i]);
kmem[i].num = 0;
}
freerange(end, (void*)PHYSTOP);
}
void
kfree(void *pa)
{
struct run *r;
push_off();
int cpu_id = cpuid();
pop_off();
if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP)
panic("kfree");
// Fill with junk to catch dangling refs.
memset(pa, 1, PGSIZE);
r = (struct run*)pa;
acquire(&kmem[cpu_id].lock);
r->next = kmem[cpu_id].freelist;
kmem[cpu_id].freelist = r;
kmem[cpu_id].num++;
release(&kmem[cpu_id].lock);
}
只有一个cpu能进行steal
struct spinlock stealLock;
void *
kalloc(void)
{
struct run *r;
push_off();
int cpu_id = cpuid();
pop_off();
acquire(&kmem[cpu_id].lock);
r = kmem[cpu_id].freelist;
if(!r){
acquire(&stealLock);
int maxMem_id = -1;
int maxMem = 0;
//找到剩余最多内存cpu
for(int i = 0; i < NCPU; i++){
if(kmem[i].num > maxMem){
maxMem_id = i;
maxMem = kmem[i].num;
}
}
//steal
if(maxMem_id != -1){
acquire(&kmem[maxMem_id].lock);
struct run* temp = kmem[cpu_id].freelist;
kmem[cpu_id].freelist = kmem[maxMem_id].freelist;
kmem[maxMem_id].freelist = kmem[maxMem_id].freelist->next;
kmem[cpu_id].freelist->next = temp;
kmem[cpu_id].num++;
kmem[maxMem_id].num--;
release(&kmem[maxMem_id].lock);
}
release(&stealLock);
r = kmem[cpu_id].freelist;
}
if(r){
kmem[cpu_id].freelist = r->next;
kmem[cpu_id].num--;
}
release(&kmem[cpu_id].lock);
if(r)
memset((char*)r, 5, PGSIZE); // fill with junk
return (void*)r;
}
$ kalloctest
start test1
test1 results:
--- lock kmem/bcache stats
lock: kmem cpu 0: #test-and-set 0 #acquire() 88387
lock: kmem cpu 1: #test-and-set 0 #acquire() 169542
lock: kmem cpu 2: #test-and-set 0 #acquire() 175017
lock: bcache.bucket: #test-and-set 0 #acquire() 3
lock: bcache.bucket: #test-and-set 0 #acquire() 17
lock: bcache.bucket: #test-and-set 0 #acquire() 11
lock: bcache.bucket: #test-and-set 0 #acquire() 8
lock: bcache.bucket: #test-and-set 0 #acquire() 3
lock: bcache.bucket: #test-and-set 0 #acquire() 7
lock: bcache.bucket: #test-and-set 0 #acquire() 284
lock: bcache.bucket: #test-and-set 0 #acquire() 11
lock: bcache.bucket: #test-and-set 0 #acquire() 3
lock: bcache.bucket: #test-and-set 0 #acquire() 3
lock: bcache.bucket: #test-and-set 0 #acquire() 3
lock: bcache.bucket: #test-and-set 0 #acquire() 11
lock: bcache: #test-and-set 0 #acquire() 18
--- top 5 contended locks:
lock: proc: #test-and-set 71279 #acquire() 270072
lock: proc: #test-and-set 68672 #acquire() 270072
lock: proc: #test-and-set 65642 #acquire() 270072
lock: proc: #test-and-set 51996 #acquire() 270072
lock: proc: #test-and-set 51493 #acquire() 270072
tot= 0
test1 OK
Buffer cache(有问题)
struct {
struct spinlock lock;
struct buf head;
} hash[BUCKET];
void
binit(void)
{
// struct buf *b;
for(int i = 0; i < BUCKET; i++){
snprintf(hash_lk_name[i], name_size2, "bcache.bucket %d", i);
initlock(&hash[i].lock, hash_lk_name[i]);
}
initlock(&bcache.lock, "bcache");
}
static struct buf*
bget(uint dev, uint blockno)
{
struct buf *b;
int index = HASH(dev, blockno);//获取索引号
acquire(&hash[index].lock);
//是否已经在缓存区
for(b = hash[index].head.next; b; b = b->next){
if(b->dev == dev && b->blockno == blockno){
b->refcnt++;
acquire(&tickslock);
b->ticks = ticks;
release(&tickslock);
release(&hash[index].lock);
acquiresleep(&b->lock);
return b;
}
}
//不在缓存区
release(&hash[index].lock); //释放自己的锁
acquire(&bcache.lock);
acquire(&hash[index].lock);
// 这时候另一个进程调用了 bget() 函数,并且 blockno 还是同一个。
// 在两个进程都找到了空闲缓存后,它们会把两个缓存都加到当前 blockno 的桶中,
// 这样一个 blockno 对应的缓存就有了两个。
for(b = hash[index].head.next; b; b = b->next){
if(b->dev == dev && b->blockno == blockno){
b->refcnt++;
acquire(&tickslock);
b->ticks = ticks;
release(&tickslock);
release(&hash[index].lock);
release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
}
for(int i = 0; i < NBUF; i++){
if(bcache.buf[i].ticks == 0 && bcache.buf[i].refcnt == 0){
b = &bcache.buf[i];
//未使用块缓存
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
acquire(&tickslock);
b->ticks = ticks;
release(&tickslock);
struct buf *temp = hash[index].head.next;
hash[index].head.next = b;
b->prev = &hash[index].head;
b->next = temp;
if(temp){
temp->prev = b;
}
release(&hash[index].lock);
release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
}
//无空闲:驱逐
acquire(&tickslock);
uint ticks_now = ticks;
release(&tickslock);
int time = -1;
int targetBuf = -1;
int targetBucket = -1;
for(int i = 0; i < NBUF; i++){
int index_now = HASH(bcache.buf[i].dev, bcache.buf[i].blockno);
// if(bcache.buf[i].refcnt != 0 )
// continue;
// if(index_now != index && index_now != targetBucket){
// acquire(&hash[index_now].lock);
// }
if(index_now != index && index_now != targetBucket){
acquire(&hash[index_now].lock);
}
if(bcache.buf[i].refcnt != 0){
if(index_now != index && index_now != targetBucket){
release(&hash[index_now].lock);
}
continue;
}
int interval = ticks_now - bcache.buf[i].ticks;
if(interval > time){
if(targetBucket != -1 && targetBucket != index_now && targetBucket != index){
release(&hash[targetBucket].lock);
}
targetBuf = i;
targetBucket = index_now;
time = interval;
}
else{
if(index_now != index && index_now != targetBucket){
release(&hash[index_now].lock);
}
}
}
if(targetBuf == -1 || targetBucket == -1){
panic("bget: no buffers");
}
//获得要变换的锁
if(targetBucket == index){
b = &bcache.buf[targetBuf];
//未使用块缓存
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
acquire(&tickslock);
b->ticks = ticks;
release(&tickslock);
release(&hash[targetBucket].lock);
release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
else{
b = &bcache.buf[targetBuf];
//将b逐出原来bucket
b->prev->next = b->next;
if(b->next)
b->next->prev = b->prev;
release(&hash[targetBucket].lock);
//将b放入当前bucket
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->refcnt = 1;
acquire(&tickslock);
b->ticks = ticks;
release(&tickslock);
struct buf *temp = hash[index].head.next;
hash[index].head.next = b;
b->prev = &hash[index].head;
b->next = temp;
if(temp){
temp->prev = b;
}
release(&hash[index].lock);
release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
panic("bget: no buffers");
}
void
brelse(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("brelse");
releasesleep(&b->lock);
int index = HASH(b->dev, b->blockno);//获取索引号
acquire(&hash[index].lock);
b->refcnt--;
if (b->refcnt == 0) {
acquire(&tickslock);
b->ticks = ticks;
release(&tickslock);
}
release(&hash[index].lock);
}