kernel: improve page reclaimation strategy and locking

when reclaiming pages from an image, always reclaim all
the hash chains equally. that way, we avoid being biased
towards the chains at the start of the Image.pghash[] array.

images can be in two states: active or inactive. inactive
images are the ones which are not used by program while
active ones aare.

when reclaiming pages, we should try to reclaim pages
from inactive images first and only if that set becomes
exhausted attempt to release text pages and attempt to
reclaim pages from active images.

when we run out of Image structures, it makes only sense
to reclaim pages from inactive images, as reclaiming pages
from active ones will never free any Image structures.

change putimage() to require a image already locked and
make it unlock the image. this avoids many pointless
unlock()/lock() sequences as all callers of putimage()
already had the image locked.
This commit is contained in:
cinap_lenrek 2020-04-26 19:54:46 +02:00
parent c6f7989176
commit 61a062ee9f
4 changed files with 23 additions and 37 deletions

View file

@ -137,12 +137,12 @@ reclaim(void)
ulong np; ulong np;
for(;;){ for(;;){
if((np = pagereclaim(&fscache, 1000)) > 0) { if((np = pagereclaim(&fscache) + imagereclaim(0)) > 0){
if(0) print("reclaim: %lud fscache\n", np); if(0) print("reclaim: %lud fscache + inactive image\n", np);
} else if((np = pagereclaim(&swapimage, 1000)) > 0) { } else if((np = pagereclaim(&swapimage)) > 0) {
if(0) print("reclaim: %lud swap\n", np); if(0) print("reclaim: %lud swap\n", np);
} else if((np = imagereclaim(1000)) > 0) { } else if((np = imagereclaim(1)) > 0) {
if(0) print("reclaim: %lud image\n", np); if(0) print("reclaim: %lud active image\n", np);
} }
if(!needpages(nil)) if(!needpages(nil))
return 1; /* have pages, done */ return 1; /* have pages, done */

View file

@ -93,15 +93,12 @@ freepages(Page *head, Page *tail, ulong np)
} }
ulong ulong
pagereclaim(Image *i, ulong pages) pagereclaim(Image *i)
{ {
Page **h, **l, **x, *p; Page **h, **l, **x, *p;
Page *fh, *ft; Page *fh, *ft;
ulong np; ulong np;
if(pages == 0)
return 0;
lock(i); lock(i);
if(i->pgref == 0){ if(i->pgref == 0){
unlock(i); unlock(i);
@ -127,18 +124,18 @@ pagereclaim(Image *i, ulong pages)
p->next = nil; p->next = nil;
p->image = nil; p->image = nil;
p->daddr = ~0; p->daddr = ~0;
i->pgref--;
decref(i);
if(fh == nil) if(fh == nil)
fh = p; fh = p;
else else
ft->next = p; ft->next = p;
ft = p; ft = p;
if(++np >= pages) np++;
decref(i);
if(--i->pgref == 0)
break; break;
} }
unlock(i);
putimage(i); putimage(i);
if(np > 0){ if(np > 0){
@ -297,7 +294,6 @@ uncachepage(Page *p)
p->image = nil; p->image = nil;
p->daddr = ~0; p->daddr = ~0;
i->pgref--; i->pgref--;
unlock(i);
putimage(i); putimage(i);
return; return;
} }

View file

@ -134,7 +134,7 @@ void ilock(Lock*);
void interrupted(void); void interrupted(void);
void iunlock(Lock*); void iunlock(Lock*);
ulong imagecached(void); ulong imagecached(void);
ulong imagereclaim(ulong); ulong imagereclaim(int);
long incref(Ref*); long incref(Ref*);
void init0(void); void init0(void);
void initseg(void); void initseg(void);
@ -213,7 +213,7 @@ Block* padblock(Block*, int);
void pagechaindone(void); void pagechaindone(void);
void pagechainhead(Page*); void pagechainhead(Page*);
void pageinit(void); void pageinit(void);
ulong pagereclaim(Image*, ulong); ulong pagereclaim(Image*);
void panic(char*, ...); void panic(char*, ...);
Cmdbuf* parsecmd(char *a, int n); Cmdbuf* parsecmd(char *a, int n);
void pathclose(Path*); void pathclose(Path*);

View file

@ -102,7 +102,6 @@ putseg(Segment *s)
} }
if(i->s == s) if(i->s == s)
i->s = nil; i->s = nil;
unlock(i);
putimage(i); putimage(i);
} else if(decref(s) != 0) } else if(decref(s) != 0)
return; return;
@ -260,7 +259,7 @@ attachimage(int type, Chan *c, uintptr base, ulong len)
/* dump pages of inactive images to free image structures */ /* dump pages of inactive images to free image structures */
while((i = imagealloc.free) == nil) { while((i = imagealloc.free) == nil) {
unlock(&imagealloc); unlock(&imagealloc);
if(imagereclaim(1000) == 0 && imagealloc.free == nil){ if(imagereclaim(0) == 0 && imagealloc.free == nil){
freebroken(); /* can use the memory */ freebroken(); /* can use the memory */
resrcwait("no image after reclaim"); resrcwait("no image after reclaim");
} }
@ -288,7 +287,6 @@ found:
if(i->s == nil) { if(i->s == nil) {
incref(i); incref(i);
if(waserror()) { if(waserror()) {
unlock(i);
putimage(i); putimage(i);
nexterror(); nexterror();
} }
@ -316,14 +314,11 @@ imagecached(void)
} }
ulong ulong
imagereclaim(ulong pages) imagereclaim(int active)
{ {
static Image *i, *ie; static Image *i, *ie;
ulong np;
int j; int j;
ulong np;
if(pages == 0)
return 0;
eqlock(&imagealloc.ireclaim); eqlock(&imagealloc.ireclaim);
if(i == nil){ if(i == nil){
@ -334,23 +329,19 @@ imagereclaim(ulong pages)
for(j = 0; j < conf.nimage; j++, i++){ for(j = 0; j < conf.nimage; j++, i++){
if(i >= ie) if(i >= ie)
i = imagealloc.list; i = imagealloc.list;
if(i->ref == 0) if(i->ref == 0 || (i->ref != i->pgref) == !active)
continue; continue;
/* np += pagereclaim(i);
* if there are no free image structures, only if(np >= 1000)
* reclaim pages from inactive images. goto Done;
*/
if(imagealloc.free != nil || i->ref == i->pgref){
np += pagereclaim(i, pages - np);
if(np >= pages)
break;
}
} }
Done:
qunlock(&imagealloc.ireclaim); qunlock(&imagealloc.ireclaim);
return np; return np;
} }
/* putimage(): called with image locked and unlocks */
void void
putimage(Image *i) putimage(Image *i)
{ {
@ -358,14 +349,13 @@ putimage(Image *i)
Chan *c; Chan *c;
long r; long r;
r = decref(i);
if(i->notext){ if(i->notext){
decref(i); unlock(i);
return; return;
} }
c = nil; c = nil;
lock(i);
r = decref(i);
if(r == i->pgref){ if(r == i->pgref){
/* /*
* all remaining references to this image are from the * all remaining references to this image are from the