shithub: riscv

Download patch

ref: 61a062ee9ff7bbd489baba6dd7c6adb1978e246b
parent: c6f7989176b9da3b977f397ac4f20bc2f86dec1b
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 26 15:54:46 EDT 2020

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.

--- a/sys/src/9/port/devswap.c
+++ b/sys/src/9/port/devswap.c
@@ -137,12 +137,12 @@
 	ulong np;
 
 	for(;;){
-		if((np = pagereclaim(&fscache, 1000)) > 0) {
-			if(0) print("reclaim: %lud fscache\n", np);
-		} else if((np = pagereclaim(&swapimage, 1000)) > 0) {
+		if((np = pagereclaim(&fscache) + imagereclaim(0)) > 0){
+			if(0) print("reclaim: %lud fscache + inactive image\n", np);
+		} else if((np = pagereclaim(&swapimage)) > 0) {
 			if(0) print("reclaim: %lud swap\n", np);
-		} else if((np = imagereclaim(1000)) > 0) {
-			if(0) print("reclaim: %lud image\n", np);
+		} else if((np = imagereclaim(1)) > 0) {
+			if(0) print("reclaim: %lud active image\n", np);
 		}
 		if(!needpages(nil))
 			return 1;	/* have pages, done */
--- a/sys/src/9/port/page.c
+++ b/sys/src/9/port/page.c
@@ -93,15 +93,12 @@
 }
 
 ulong
-pagereclaim(Image *i, ulong pages)
+pagereclaim(Image *i)
 {
 	Page **h, **l, **x, *p;
 	Page *fh, *ft;
 	ulong np;
 
-	if(pages == 0)
-		return 0;
-
 	lock(i);
 	if(i->pgref == 0){
 		unlock(i);
@@ -127,8 +124,6 @@
 		p->next = nil;
 		p->image = nil;
 		p->daddr = ~0;
-		i->pgref--;
-		decref(i);
 
 		if(fh == nil)
 			fh = p;
@@ -135,10 +130,12 @@
 		else
 			ft->next = p;
 		ft = p;
-		if(++np >= pages)
+		np++;
+
+		decref(i);
+		if(--i->pgref == 0)
 			break;
 	}
-	unlock(i);
 	putimage(i);
 
 	if(np > 0){
@@ -297,7 +294,6 @@
 			p->image = nil;
 			p->daddr = ~0;
 			i->pgref--;
-			unlock(i);
 			putimage(i);
 			return;
 		}
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -134,7 +134,7 @@
 void		interrupted(void);
 void		iunlock(Lock*);
 ulong		imagecached(void);
-ulong		imagereclaim(ulong);
+ulong		imagereclaim(int);
 long		incref(Ref*);
 void		init0(void);
 void		initseg(void);
@@ -213,7 +213,7 @@
 void		pagechaindone(void);
 void		pagechainhead(Page*);
 void		pageinit(void);
-ulong		pagereclaim(Image*, ulong);
+ulong		pagereclaim(Image*);
 void		panic(char*, ...);
 Cmdbuf*		parsecmd(char *a, int n);
 void		pathclose(Path*);
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -102,7 +102,6 @@
 		}
 		if(i->s == s)
 			i->s = nil;
-		unlock(i);
 		putimage(i);
 	} else if(decref(s) != 0)
 		return;
@@ -260,7 +259,7 @@
 	/* dump pages of inactive images to free image structures */
 	while((i = imagealloc.free) == nil) {
 		unlock(&imagealloc);
-		if(imagereclaim(1000) == 0 && imagealloc.free == nil){
+		if(imagereclaim(0) == 0 && imagealloc.free == nil){
 			freebroken();		/* can use the memory */
 			resrcwait("no image after reclaim");
 		}
@@ -288,7 +287,6 @@
 	if(i->s == nil) {
 		incref(i);
 		if(waserror()) {
-			unlock(i);
 			putimage(i);
 			nexterror();
 		}
@@ -316,15 +314,12 @@
 }
 
 ulong
-imagereclaim(ulong pages)
+imagereclaim(int active)
 {
 	static Image *i, *ie;
-	ulong np;
 	int j;
+	ulong np;
 
-	if(pages == 0)
-		return 0;
-
 	eqlock(&imagealloc.ireclaim);
 	if(i == nil){
 		i = imagealloc.list;
@@ -334,23 +329,19 @@
 	for(j = 0; j < conf.nimage; j++, i++){
 		if(i >= ie)
 			i = imagealloc.list;
-		if(i->ref == 0)
+		if(i->ref == 0 || (i->ref != i->pgref) == !active)
 			continue;
-		/*
-		 * if there are no free image structures, only
-		 * reclaim pages from inactive images.
-		 */
-		if(imagealloc.free != nil || i->ref == i->pgref){
-			np += pagereclaim(i, pages - np);
-			if(np >= pages)
-				break;
-		}
+		np += pagereclaim(i);
+		if(np >= 1000)
+			goto Done;
 	}
+Done:
 	qunlock(&imagealloc.ireclaim);
 
 	return np;
 }
 
+/* putimage(): called with image locked and unlocks */
 void
 putimage(Image *i)
 {
@@ -358,14 +349,13 @@
 	Chan *c;
 	long r;
 
+	r = decref(i);
 	if(i->notext){
-		decref(i);
+		unlock(i);
 		return;
 	}
 
 	c = nil;
-	lock(i);
-	r = decref(i);
 	if(r == i->pgref){
 		/*
 		 * all remaining references to this image are from the