segment: speed up fixedseg() doing single pass over freelist

walking the freelist for every page is too slow. as we
are freeing a range, we can do a single pass unlinking all
pages in our range and at the end, check if all pages
where freed, if not put the pages that we did free back
and retry, otherwise we'r done.
This commit is contained in:
cinap_lenrek 2015-04-12 18:08:06 +02:00
parent 98a7eae9c0
commit a43321946e

View file

@ -580,8 +580,8 @@ fixedseg(uintptr va, ulong len)
{
KMap *k;
Segment *s;
Page **f, *p;
ulong n, i, j;
Page **f, *p, *l, *h;
ulong n, i;
int color;
s = newseg(SG_FIXED, va, len);
@ -591,32 +591,44 @@ fixedseg(uintptr va, ulong len)
}
lock(&palloc);
i = 0;
p = palloc.pages;
l = palloc.pages;
color = getpgcolor(va);
for(n = palloc.user; n >= len; n--, p++){
if(p->ref != 0 || i != 0 && (p[-1].pa+BY2PG) != p->pa || i == 0 && p->color != color){
for(n = palloc.user; n >= len; n--, l++){
if(l->ref != 0 || i != 0 && (l[-1].pa+BY2PG) != l->pa || i == 0 && l->color != color){
Retry:
i = 0;
continue;
}
if(++i < len)
continue;
for(j = 0; j < i; j++, p--){
for(f = &palloc.head; *f != nil; f = &((*f)->next)){
if(*f == p){
i = 0;
h = nil;
f = &palloc.head;
while((p = *f) != nil){
if(p > &l[-len] && p <= l){
*f = p->next;
goto Freed;
p->next = h;
h = p;
if(++i < len)
continue;
break;
}
f = &p->next;
}
palloc.freecount -= i;
if(i != len){
while((p = h) != nil){
h = h->next;
pagechainhead(p);
}
while(j-- > 0)
pagechainhead(++p);
goto Retry;
Freed:
palloc.freecount--;
}
unlock(&palloc);
while(i-- > 0){
p = &l[-len];
do {
p++;
p->ref = 1;
p->va = va;
@ -629,7 +641,7 @@ fixedseg(uintptr va, ulong len)
segpage(s, p);
va += BY2PG;
}
} while(p != l);
poperror();
return s;
}