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);