Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern - sched_idle(): if a migration took place, rather t...



details:   https://anonhg.NetBSD.org/src/rev/2718340c1404
branches:  trunk
changeset: 970830:2718340c1404
user:      ad <ad%NetBSD.org@localhost>
date:      Sat Apr 04 20:17:58 2020 +0000

description:
- sched_idle(): if a migration took place, rather than going idle briefly
  to avoid stealing back the LWP, remember the target CPU and avoid it.

- sched_preempted(): only choose a totally idle CPU; in the interests of
  overall throughput it's better to make use of SMT / slow CPUs.

diffstat:

 sys/kern/kern_runq.c |  54 +++++++++++++++++++++++++++++----------------------
 1 files changed, 31 insertions(+), 23 deletions(-)

diffs (167 lines):

diff -r ddd65bbe236b -r 2718340c1404 sys/kern/kern_runq.c
--- a/sys/kern/kern_runq.c      Sat Apr 04 19:50:53 2020 +0000
+++ b/sys/kern/kern_runq.c      Sat Apr 04 20:17:58 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_runq.c,v 1.64 2020/03/26 19:25:07 ad Exp $        */
+/*     $NetBSD: kern_runq.c,v 1.65 2020/04/04 20:17:58 ad Exp $        */
 
 /*-
  * Copyright (c) 2019, 2020 The NetBSD Foundation, Inc.
@@ -56,7 +56,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_runq.c,v 1.64 2020/03/26 19:25:07 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_runq.c,v 1.65 2020/04/04 20:17:58 ad Exp $");
 
 #include "opt_dtrace.h"
 
@@ -340,17 +340,17 @@
        }
 
        /*
-        * Things start as soon as we touch ci_want_resched: x86 for example
-        * has an instruction that monitors the memory cell it's in.  We
-        * want to drop the schedstate lock in advance, otherwise the remote
-        * CPU can awaken and immediately block on the lock.
+        * Things can start as soon as ci_want_resched is touched: x86 has
+        * an instruction that monitors the memory cell it's in.  Drop the
+        * schedstate lock in advance, otherwise the remote CPU can awaken
+        * and immediately block on the lock.
         */
        if (__predict_true(unlock)) {
                spc_unlock(ci);
        }
 
        /*
-        * The caller will always have a second scheduler lock held: either
+        * The caller almost always has a second scheduler lock held: either
         * the running LWP lock (spc_lwplock), or a sleep queue lock.  That
         * keeps preemption disabled, which among other things ensures all
         * LWPs involved won't be freed while we're here (see lwp_dtor()).
@@ -361,8 +361,10 @@
                n = atomic_cas_uint(&ci->ci_want_resched, o, o | f);
                if (__predict_true(o == n)) {
                        /*
-                        * We're the first.  If we're in process context on
-                        * the same CPU, we can avoid the visit to trap().
+                        * We're the first to set a resched on the CPU.  Try
+                        * to avoid causing a needless trip through trap()
+                        * to handle an AST fault, if it's known the LWP
+                        * will either block or go through userret() soon.
                         */
                        if (l != curlwp || cpu_intr_p()) {
                                cpu_need_resched(ci, l, f);
@@ -680,9 +682,10 @@
 }
 
 /*
- * Called from sched_idle() to handle migration.
+ * Called from sched_idle() to handle migration.  Return the CPU that we
+ * pushed the LWP to (may be NULL).
  */
-static void
+static struct cpu_info *
 sched_idle_migrate(void)
 {
        struct cpu_info *ci = curcpu(), *tci = NULL;
@@ -748,13 +751,14 @@
                sched_resched_lwp(l, true);
                /* tci now unlocked */
                spc_unlock(ci);
-               return;
+               return tci;
        }
        if (dlock == true) {
                KASSERT(tci != NULL);
                spc_unlock(tci);
        }
        spc_unlock(ci);
+       return NULL;
 }
 
 /*
@@ -785,21 +789,22 @@
 void
 sched_idle(void)
 {
-       struct cpu_info *ci = curcpu(), *inner, *outer, *first, *tci = NULL;
+       struct cpu_info *ci, *inner, *outer, *first, *tci, *mci;
        struct schedstate_percpu *spc, *tspc;
        struct lwp *l;
 
+       ci = curcpu();
        spc = &ci->ci_schedstate;
+       tci = NULL;
+       mci = NULL;
 
        /*
         * Handle LWP migrations off this CPU to another.  If there a is
-        * migration to do then go idle afterwards (we'll wake again soon),
-        * as we don't want to instantly steal back the LWP we just moved
-        * out.
+        * migration to do then remember the CPU the LWP was sent to, and
+        * don't steal the LWP back from that CPU below.
         */
        if (spc->spc_migrating != NULL) {
-               sched_idle_migrate();
-               return;
+               mci = sched_idle_migrate();
        }
 
        /* If this CPU is offline, or we have an LWP to run, we're done. */
@@ -812,7 +817,7 @@
                /* Try to help our siblings out. */
                tci = ci->ci_sibling[CPUREL_CORE];
                while (tci != ci) {
-                       if (sched_steal(ci, tci)) {
+                       if (tci != mci && sched_steal(ci, tci)) {
                                return;
                        }
                        tci = tci->ci_sibling[CPUREL_CORE];
@@ -849,7 +854,8 @@
                do {
                        /* Don't hit the locks unless needed. */
                        tspc = &inner->ci_schedstate;
-                       if (ci == inner || spc->spc_psid != tspc->spc_psid ||
+                       if (ci == inner || ci == mci ||
+                           spc->spc_psid != tspc->spc_psid ||
                            tspc->spc_mcount < min_catch) {
                                continue;
                        }
@@ -874,6 +880,7 @@
 void
 sched_preempted(struct lwp *l)
 {
+       const int flags = SPCF_IDLE | SPCF_1STCLASS;
        struct schedstate_percpu *tspc;
        struct cpu_info *ci, *tci;
 
@@ -903,7 +910,6 @@
         */
        tci = ci->ci_sibling[CPUREL_CORE];
        while (tci != ci) {
-               const int flags = SPCF_IDLE | SPCF_1STCLASS;
                tspc = &tci->ci_schedstate;
                if ((tspc->spc_flags & flags) == flags &&
                    sched_migratable(l, tci)) {
@@ -928,7 +934,9 @@
        } else {
                /*
                 * Try to find a better CPU to take it, but don't move to
-                * another 2nd class CPU; there's not much point.
+                * another 2nd class CPU, and don't move to a non-idle CPU,
+                * because that would prevent SMT being used to maximise
+                * throughput.
                 *
                 * Search in the current CPU package in order to try and
                 * keep L2/L3 cache locality, but expand to include the
@@ -936,7 +944,7 @@
                 */
                tci = sched_bestcpu(l, l->l_cpu);
                if (tci != ci &&
-                   (tci->ci_schedstate.spc_flags & SPCF_1STCLASS) != 0) {
+                   (tci->ci_schedstate.spc_flags & flags) == flags) {
                        l->l_target_cpu = tci;
                }
        }



Home | Main Index | Thread Index | Old Index