Module Name: src
Committed By: ad
Date: Sun Jan 5 20:26:56 UTC 2020
Modified Files:
src/sys/kern: kern_runq.c
src/sys/sys: sched.h
Log Message:
- Another tweak for SMT: if a new LWP is starting life, try to make it run
on a different CPU in the same CPU core as the parent, because both parent
and child share lots of state. (I want to come back later and do
something different for _lwp_create() and maybe execve().)
- Remove the runqueue evcnts, which are racy and impose a penalty for very
little payoff.
- Break out of the loop in sched_takecpu() as soon as we have a CPU that can
run the LWP. There's no need to look at all CPUs.
- SPCF_IDLE in sched_enqueue() so we know the CPU is not idle sooner.
To generate a diff of this commit:
cvs rdiff -u -r1.54 -r1.55 src/sys/kern/kern_runq.c
cvs rdiff -u -r1.82 -r1.83 src/sys/sys/sched.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/kern_runq.c
diff -u src/sys/kern/kern_runq.c:1.54 src/sys/kern/kern_runq.c:1.55
--- src/sys/kern/kern_runq.c:1.54 Sat Jan 4 22:46:01 2020
+++ src/sys/kern/kern_runq.c Sun Jan 5 20:26:56 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: kern_runq.c,v 1.54 2020/01/04 22:46:01 ad Exp $ */
+/* $NetBSD: kern_runq.c,v 1.55 2020/01/05 20:26:56 ad Exp $ */
/*-
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -56,7 +56,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_runq.c,v 1.54 2020/01/04 22:46:01 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_runq.c,v 1.55 2020/01/05 20:26:56 ad Exp $");
#include "opt_dtrace.h"
@@ -178,15 +178,6 @@ sched_cpuattach(struct cpu_info *ci)
spc->spc_mutex = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SCHED);
for (i = 0; i < PRI_COUNT; i++)
TAILQ_INIT(&spc->spc_queue[i]);
-
- evcnt_attach_dynamic(&spc->spc_ev_pull, EVCNT_TYPE_MISC, NULL,
- cpu_name(ci), "runqueue pull");
- evcnt_attach_dynamic(&spc->spc_ev_push, EVCNT_TYPE_MISC, NULL,
- cpu_name(ci), "runqueue push");
- evcnt_attach_dynamic(&spc->spc_ev_stay, EVCNT_TYPE_MISC, NULL,
- cpu_name(ci), "runqueue stay");
- evcnt_attach_dynamic(&spc->spc_ev_localize, EVCNT_TYPE_MISC, NULL,
- cpu_name(ci), "runqueue localize");
}
/*
@@ -235,6 +226,7 @@ sched_enqueue(struct lwp *l)
} else {
TAILQ_INSERT_TAIL(q_head, l, l_runq);
}
+ spc->spc_flags &= ~SPCF_IDLE;
spc->spc_count++;
if ((l->l_pflag & LP_BOUND) == 0)
spc->spc_mcount++;
@@ -474,15 +466,33 @@ sched_takecpu(struct lwp *l)
spc = &ci->ci_schedstate;
eprio = lwp_eprio(l);
+ /*
+ * For new LWPs (LSIDL), l_cpu was inherited from the parent when
+ * the LWP was created (and is probably still curcpu at this point).
+ * The child will initially be in close communication with the
+ * parent and share VM context and cache state. Look for an idle
+ * SMT sibling to run it, and failing that run on the same CPU as
+ * the parent.
+ */
+ if (l->l_stat == LSIDL) {
+ tci = ci->ci_sibling[CPUREL_CORE];
+ while (tci != ci) {
+ ici_spc = &tci->ci_schedstate;
+ if (l->l_psid == ici_spc->spc_psid &&
+ (ici_spc->spc_flags & SPCF_IDLE) != 0) {
+ return tci;
+ }
+ tci = tci->ci_sibling[CPUREL_CORE];
+ }
+ if (spc->spc_psid == l->l_psid) {
+ return ci;
+ }
+ }
+
/* If SMT primary is idle, send it back there. */
tci = ci->ci_smt_primary;
if ((tci->ci_schedstate.spc_flags & SPCF_IDLE) != 0 &&
sched_migratable(l, tci)) {
- if (tci != ci) {
- spc->spc_ev_push.ev_count++;
- } else {
- spc->spc_ev_stay.ev_count++;
- }
return tci;
}
@@ -490,23 +500,11 @@ sched_takecpu(struct lwp *l)
if (__predict_true(spc->spc_psid == l->l_psid)) {
/* If CPU of this thread is idling - run there */
if (spc->spc_count == 0) {
- spc->spc_ev_stay.ev_count++;
return ci;
}
- /*
- * New LWPs must start on the same CPU as the parent (l_cpu
- * was inherited when the LWP was created). Doing otherwise
- * is bad for performance and repeatability, and agitates
- * buggy programs. Also, we want the child to have a good
- * chance of reusing the VM context from the parent.
- */
- if (l->l_stat == LSIDL) {
- spc->spc_ev_stay.ev_count++;
- return ci;
- }
+
/* Stay if thread is cache-hot */
if (lwp_cache_hot(l) && eprio >= spc->spc_curpriority) {
- spc->spc_ev_stay.ev_count++;
return ci;
}
}
@@ -515,8 +513,6 @@ sched_takecpu(struct lwp *l)
ci = curcpu();
spc = &ci->ci_schedstate;
if (eprio > spc->spc_curpriority && sched_migratable(l, ci)) {
- /* XXXAD foreign CPU not locked */
- spc->spc_ev_localize.ev_count++;
return ci;
}
@@ -543,7 +539,7 @@ sched_takecpu(struct lwp *l)
if (pri == lpri) {
/* Pick the least busy CPU. */
- if (spc->spc_count < ici_spc->spc_count)
+ if (spc->spc_count <= ici_spc->spc_count)
continue;
/* Prefer SMT primaries over secondaries. */
@@ -555,11 +551,13 @@ sched_takecpu(struct lwp *l)
lpri = pri;
tci = ci;
spc = ici_spc;
- } while (ci = next, ci != pivot);
-
- /* XXXAD remote CPU, unlocked */
- tci->ci_schedstate.spc_ev_push.ev_count++;
+ /* If this CPU is idle and an SMT primary, we're done. */
+ if ((spc->spc_flags & (SPCF_IDLE | SPCF_SMTPRIMARY)) ==
+ (SPCF_IDLE | SPCF_SMTPRIMARY)) {
+ break;
+ }
+ } while (ci = next, ci != pivot);
return tci;
}
@@ -626,7 +624,6 @@ sched_catchlwp(struct cpu_info *ci)
SPINLOCK_BACKOFF(count);
}
l->l_cpu = curci;
- spc->spc_ev_pull.ev_count++;
lwp_unlock_to(l, curspc->spc_mutex);
sched_enqueue(l);
return l;
Index: src/sys/sys/sched.h
diff -u src/sys/sys/sched.h:1.82 src/sys/sys/sched.h:1.83
--- src/sys/sys/sched.h:1.82 Sat Dec 21 11:54:04 2019
+++ src/sys/sys/sched.h Sun Jan 5 20:26:56 2020
@@ -1,4 +1,4 @@
-/* $NetBSD: sched.h,v 1.82 2019/12/21 11:54:04 ad Exp $ */
+/* $NetBSD: sched.h,v 1.83 2020/01/05 20:26:56 ad Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2007, 2008, 2019
@@ -144,7 +144,6 @@ __END_DECLS
#include <sys/mutex.h>
#include <sys/time.h>
-#include <sys/evcnt.h>
/*
* Per-CPU scheduler state. Field markings and the corresponding locks:
@@ -174,10 +173,6 @@ struct schedstate_percpu {
u_int spc_mcount; /* m: count of migratable threads */
uint32_t spc_bitmap[8]; /* m: bitmap of active queues */
TAILQ_HEAD(,lwp) *spc_queue; /* m: queue for each priority */
- struct evcnt spc_ev_pull; /* m: event counters */
- struct evcnt spc_ev_push;
- struct evcnt spc_ev_stay;
- struct evcnt spc_ev_localize;
};
/* spc_flags */