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

Reply via email to