git: 9front

Download patch

ref: eda435c1e31824fab7d8cb8d818f2b3c5c707d02
parent: 291b625ed502556484891ff431b924adfa127ead
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Dec 6 21:13:51 EST 2019

kernel: avoid useless mmu flushes, implement better wait condition for procflushmmu()

procflushmmu() returns once all *OTHER* processors that had
matching processes running on them flushed ther tlb/mmu state.
the caller of procflush...() takes care of flushing "up" by
calling flushmmu() later.

if the current process matched, then that means m->flushmmu
would be set, and hzclock() would call flushmmu() again.

to avoid this, we now check up->newtlb in addition to m->flushmmu
in hzclock() before calling flushmmu().

we also maintain information on which process on what processor
to wait for locally, which helps making progress when multiple
procflushmmu()'s are running concurrently.

in addition, this makes the wait condition for procflushmmu()
more sophisticated, by validating if the processor still runs
the selected process and only if it matchatches, considers
the MACHP(nm)->flushmmu flag.

--- a/sys/src/9/port/portclock.c
+++ b/sys/src/9/port/portclock.c
@@ -148,7 +148,7 @@
 		m->proc->pc = ur->pc;
 
 	if(m->flushmmu){
-		if(up)
+		if(up && up->newtlb)
 			flushmmu();
 		m->flushmmu = 0;
 	}
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -1331,6 +1331,7 @@
 static void
 procflushmmu(int (*match)(Proc*, void*), void *a)
 {
+	Proc *await[MAXMACH];
 	int i, nm, nwait;
 	Proc *p;
 
@@ -1337,30 +1338,42 @@
 	/*
 	 *  tell all matching processes to flush their mmu's
 	 */
+	memset(await, 0, conf.nmach*sizeof(await[0]));
 	nwait = 0;
-	for(i=0; i<conf.nproc; i++) {
+	for(i = 0; i < conf.nproc; i++){
 		p = &procalloc.arena[i];
 		if(p->state != Dead && (*match)(p, a)){
 			p->newtlb = 1;
 			for(nm = 0; nm < conf.nmach; nm++){
 				if(MACHP(nm)->proc == p){
+					coherence();
 					MACHP(nm)->flushmmu = 1;
-					nwait++;
+					if(await[nm] == nil)
+						nwait++;
+					await[nm] = p;
 				}
 			}
 		}
 	}
 
-	if(nwait == 0)
-		return;
-
 	/*
 	 *  wait for all other processors to take a clock interrupt
 	 *  and flush their mmu's
 	 */
-	for(nm = 0; nm < conf.nmach; nm++)
-		while(m->machno != nm && MACHP(nm)->flushmmu)
-			sched();
+	for(;;){
+		if(nwait == 0 || nwait == 1 && await[m->machno] != nil)
+			break;
+
+		sched();
+
+		for(nm = 0; nm < conf.nmach; nm++){
+			p = await[nm];
+			if(p != nil && (MACHP(nm)->proc != p || MACHP(nm)->flushmmu == 0)){
+				await[nm] = nil;
+				nwait--;
+			}
+		}
+	}
 }
 
 static int
--