Hi,
This is part 2 of previous diff sent earlier and includes it also: "sync
quantum for a proc with its per-CPU tracking".
While a proc is running, try not to disturb its running. Only change proc
priority just before adding to runqueue. This reduces SCHED_LOCK occurences in
kernel by a tiny bit: between 1.5 - 2% in speedup in testing on a kernel bsd.mp
build. If a proc runs for less than 3 ticks, then its priority is left
undisturbed. Otherwise it is adjusted just like in schedclock() in the
equivalent function decay_prio_ifrun().
In this diff, I made changes to non-AMD64 arch without having any access to it,
I believe it should compile and run.
Thanks
Index: arch/alpha/alpha/interrupt.c
===================================================================
RCS file: /cvs/src/sys/arch/alpha/alpha/interrupt.c,v
retrieving revision 1.40
diff -u -p -u -p -r1.40 interrupt.c
--- arch/alpha/alpha/interrupt.c 21 Jan 2017 05:42:03 -0000 1.40
+++ arch/alpha/alpha/interrupt.c 13 Feb 2020 01:10:03 -0000
@@ -234,14 +234,6 @@ interrupt(unsigned long a0, unsigned lon
* will also deal with time-of-day stuff.
*/
(*platform.clockintr)((struct clockframe *)framep);
-
- /*
- * If it's time to call the scheduler clock,
- * do so.
- */
- if ((++ci->ci_schedstate.spc_schedticks & 0x3f) == 0 &&
- schedhz != 0)
- schedclock(ci->ci_curproc);
}
break;
Index: arch/sparc64/sparc64/clock.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/sparc64/clock.c,v
retrieving revision 1.59
diff -u -p -u -p -r1.59 clock.c
--- arch/sparc64/sparc64/clock.c 30 Apr 2017 16:45:45 -0000 1.59
+++ arch/sparc64/sparc64/clock.c 13 Feb 2020 01:10:04 -0000
@@ -879,8 +879,6 @@ int
schedintr(arg)
void *arg;
{
- if (curproc)
- schedclock(curproc);
return (1);
}
Index: kern/kern_clock.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_clock.c,v
retrieving revision 1.101
diff -u -p -u -p -r1.101 kern_clock.c
--- kern/kern_clock.c 21 Jan 2020 16:16:23 -0000 1.101
+++ kern/kern_clock.c 13 Feb 2020 01:10:04 -0000
@@ -397,14 +397,6 @@ statclock(struct clockframe *frame)
if (p != NULL) {
p->p_cpticks++;
- /*
- * If no schedclock is provided, call it here at ~~12-25 Hz;
- * ~~16 Hz is best
- */
- if (schedhz == 0) {
- if ((++spc->spc_schedticks & 3) == 0)
- schedclock(p);
- }
}
}
Index: kern/sched_bsd.c
===================================================================
RCS file: /cvs/src/sys/kern/sched_bsd.c,v
retrieving revision 1.62
diff -u -p -u -p -r1.62 sched_bsd.c
--- kern/sched_bsd.c 30 Jan 2020 08:51:27 -0000 1.62
+++ kern/sched_bsd.c 13 Feb 2020 01:10:04 -0000
@@ -62,6 +62,7 @@ int rrticks_init; /* # of hardclock tic
struct __mp_lock sched_lock;
#endif
+void decay_prio_ifrun(struct proc*);
void schedcpu(void *);
uint32_t decay_aftersleep(uint32_t, uint32_t);
@@ -90,21 +91,13 @@ roundrobin(struct cpu_info *ci)
{
struct schedstate_percpu *spc = &ci->ci_schedstate;
- spc->spc_rrticks = rrticks_init;
-
if (ci->ci_curproc != NULL) {
- if (spc->spc_schedflags & SPCF_SEENRR) {
- /*
- * The process has already been through a roundrobin
- * without switching and may be hogging the CPU.
- * Indicate that the process should yield.
- */
- atomic_setbits_int(&spc->spc_schedflags,
- SPCF_SHOULDYIELD);
- } else {
- atomic_setbits_int(&spc->spc_schedflags,
- SPCF_SEENRR);
- }
+ /*
+ * The thread has now completed its full time quantum
+ * without being moved off the CPU and may be hogging the CPU.
+ * Indicate that the process should yield.
+ */
+ atomic_setbits_int(&spc->spc_schedflags, SPCF_SHOULDYIELD);
}
if (spc->spc_nrun)
@@ -291,6 +284,27 @@ decay_aftersleep(uint32_t estcpu, uint32
return (newcpu);
}
+/* Adjust priority depending on how much curproc actually ran */
+void
+decay_prio_ifrun(struct proc *p)
+{
+ struct schedstate_percpu *spc = &p->p_cpu->ci_schedstate;
+ if (p != spc->spc_idleproc) {
+ int j = (rrticks_init - spc->spc_rrticks)/3;
+
+ /*
+ * If proc did not get a chance to run, don't touch its
+ * priority
+ */
+
+ if (j == 0)
+ return;
+
+ uint32_t newcpu = ESTCPULIM(p->p_estcpu + j);
+ setpriority(p, newcpu, p->p_p->ps_nice);
+ }
+}
+
/*
* General yield call. Puts the current process back on its run queue and
* performs a voluntary context switch.
@@ -304,6 +318,7 @@ yield(void)
NET_ASSERT_UNLOCKED();
SCHED_LOCK(s);
+ decay_prio_ifrun(p);
setrunqueue(p->p_cpu, p, p->p_usrpri);
p->p_ru.ru_nvcsw++;
mi_switch();
@@ -323,6 +338,7 @@ preempt(void)
int s;
SCHED_LOCK(s);
+ decay_prio_ifrun(p);
setrunqueue(p->p_cpu, p, p->p_usrpri);
p->p_ru.ru_nivcsw++;
mi_switch();
@@ -385,6 +401,16 @@ mi_switch(void)
*/
atomic_clearbits_int(&spc->spc_schedflags, SPCF_SWITCHCLEAR);
+ /*
+ * We start afresh here, sync the proc and the per-cpu state
+ * to match exactly on how much time to allow the proc to run.
+ * This gives a chance to a proc to get its full quantum, and
+ * not worry if there is a chance to have it taken off the CPU
+ * at way less than its alloted quantum or have this proc
+ * take way more than its alloted quantum.
+ */
+ spc->spc_rrticks = rrticks_init;
+
nextproc = sched_chooseproc();
if (p != nextproc) {
@@ -511,22 +537,6 @@ setpriority(struct proc *p, uint32_t new
* processes which haven't run much recently, and to round-robin among other
* processes.
*/
-void
-schedclock(struct proc *p)
-{
- struct cpu_info *ci = curcpu();
- struct schedstate_percpu *spc = &ci->ci_schedstate;
- uint32_t newcpu;
- int s;
-
- if (p == spc->spc_idleproc || spc->spc_spinning)
- return;
-
- SCHED_LOCK(s);
- newcpu = ESTCPULIM(p->p_estcpu + 1);
- setpriority(p, newcpu, p->p_p->ps_nice);
- SCHED_UNLOCK(s);
-}
void (*cpu_setperf)(int);
Index: sys/sched.h
===================================================================
RCS file: /cvs/src/sys/sys/sched.h,v
retrieving revision 1.56
diff -u -p -u -p -r1.56 sched.h
--- sys/sched.h 21 Oct 2019 10:24:01 -0000 1.56
+++ sys/sched.h 13 Feb 2020 01:10:04 -0000
@@ -101,7 +101,6 @@ struct schedstate_percpu {
LIST_HEAD(,proc) spc_deadproc;
struct timespec spc_runtime; /* time curproc started running */
volatile int spc_schedflags; /* flags; see below */
- u_int spc_schedticks; /* ticks for schedclock() */
u_int64_t spc_cp_time[CPUSTATES]; /* CPU state statistics */
u_char spc_curpriority; /* usrpri of curproc */
int spc_rrticks; /* ticks until roundrobin() */
@@ -131,9 +130,8 @@ struct cpustats {
#ifdef _KERNEL
/* spc_flags */
-#define SPCF_SEENRR 0x0001 /* process has seen roundrobin() */
#define SPCF_SHOULDYIELD 0x0002 /* process should yield the CPU */
-#define SPCF_SWITCHCLEAR (SPCF_SEENRR|SPCF_SHOULDYIELD)
+#define SPCF_SWITCHCLEAR (SPCF_SHOULDYIELD)
#define SPCF_SHOULDHALT 0x0004 /* CPU should be vacated */
#define SPCF_HALTED 0x0008 /* CPU has been halted */
@@ -145,7 +143,6 @@ extern int schedhz; /* ideally: 16 */
extern int rrticks_init; /* ticks per roundrobin() */
struct proc;
-void schedclock(struct proc *);
struct cpu_info;
void roundrobin(struct cpu_info *);
void scheduler_start(void);