#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/queue.h>
#include <sys/proc.h>
#include <sys/rtprio.h>
#include <sys/uio.h>
#include <sys/sysctl.h>
#include <sys/resourcevar.h>
#include <sys/spinlock.h>
#include <sys/cpu_topology.h>
#include <sys/thread2.h>
#include <sys/spinlock2.h>
#include <sys/ktr.h>
#include <machine/cpu.h>
#include <machine/smp.h>
#include <sys/usched_dfly.h>
static void dfly_release_curproc(struct lwp *lp);
static void dfly_select_curproc(globaldata_t gd);
static void dfly_setrunqueue(struct lwp *lp);
static void dfly_setrunqueue_dd(dfly_pcpu_t rdd, struct lwp *lp);
static void dfly_schedulerclock(struct lwp *lp, sysclock_t period,
sysclock_t cpstamp);
static void dfly_recalculate_estcpu(struct lwp *lp);
static void dfly_resetpriority(struct lwp *lp);
static void dfly_forking(struct lwp *plp, struct lwp *lp);
static void dfly_exiting(struct lwp *lp, struct proc *);
static void dfly_uload_update(struct lwp *lp);
static void dfly_yield(struct lwp *lp);
static void dfly_changeqcpu_locked(struct lwp *lp,
dfly_pcpu_t dd, dfly_pcpu_t rdd);
static dfly_pcpu_t dfly_choose_best_queue(struct lwp *lp);
static dfly_pcpu_t dfly_choose_worst_queue(dfly_pcpu_t dd, int forceit);
static dfly_pcpu_t dfly_choose_queue_simple(dfly_pcpu_t dd, struct lwp *lp);
static void dfly_need_user_resched_remote(void *dummy);
static struct lwp *dfly_chooseproc_locked(dfly_pcpu_t rdd, dfly_pcpu_t dd,
struct lwp *chklp, int worst);
static void dfly_remrunqueue_locked(dfly_pcpu_t dd, struct lwp *lp);
static void dfly_setrunqueue_locked(dfly_pcpu_t dd, struct lwp *lp);
static void dfly_changedcpu(struct lwp *lp);
struct usched usched_dfly = {
{ NULL },
"dfly", "Original DragonFly Scheduler",
NULL,
NULL,
dfly_acquire_curproc,
dfly_release_curproc,
dfly_setrunqueue,
dfly_schedulerclock,
dfly_recalculate_estcpu,
dfly_resetpriority,
dfly_forking,
dfly_exiting,
dfly_uload_update,
NULL,
dfly_yield,
dfly_changedcpu
};
static cpumask_t dfly_curprocmask = CPUMASK_INITIALIZER_ALLONES;
static cpumask_t dfly_rdyprocmask;
static struct usched_dfly_pcpu dfly_pcpu[MAXCPU];
static struct sysctl_ctx_list usched_dfly_sysctl_ctx;
static struct sysctl_oid *usched_dfly_sysctl_tree;
static struct lock usched_dfly_config_lk = LOCK_INITIALIZER("usdfs", 0, 0);
static int usched_dfly_debug = -1;
SYSCTL_INT(_debug, OID_AUTO, dfly_scdebug, CTLFLAG_RW,
&usched_dfly_debug, 0,
"Print debug information for this pid");
static int usched_dfly_pid_debug = -1;
SYSCTL_INT(_debug, OID_AUTO, dfly_pid_debug, CTLFLAG_RW,
&usched_dfly_pid_debug, 0,
"Print KTR debug information for this pid");
static int usched_dfly_chooser = 0;
SYSCTL_INT(_debug, OID_AUTO, dfly_chooser, CTLFLAG_RW,
&usched_dfly_chooser, 0,
"Print KTR debug information for this pid");
static int usched_dfly_forkbias = 1;
SYSCTL_INT(_debug, OID_AUTO, dfly_forkbias, CTLFLAG_RW,
&usched_dfly_forkbias, 0,
"Fork bias for estcpu in whole queues");
__read_mostly static int usched_dfly_smt = 0;
__read_mostly static int usched_dfly_cache_coherent = 0;
__read_mostly static int usched_dfly_weight1 = 30;
__read_mostly static int usched_dfly_weight2 = 180;
__read_mostly static int usched_dfly_weight3 = 10;
__read_mostly static int usched_dfly_weight4 = 120;
__read_mostly static int usched_dfly_weight5 = 50;
__read_mostly static int usched_dfly_weight6 = 0;
__read_mostly static int usched_dfly_weight7 = -100;
__read_mostly static int usched_dfly_features = 0x2f;
__read_mostly static int usched_dfly_fast_resched = PPQ / 2;
__read_mostly static int usched_dfly_swmask = ~PPQMASK;
__read_mostly static int usched_dfly_rrinterval = (ESTCPUFREQ + 9) / 10;
__read_mostly static int usched_dfly_decay = 8;
__read_mostly static int usched_dfly_ipc_smt = -1;
__read_mostly static int usched_dfly_ipc_same = -1;
__read_mostly static int usched_dfly_poll_ticks = 1;
__read_mostly static long usched_dfly_node_mem;
KTR_INFO_MASTER(usched);
#if !defined(KTR_USCHED_DFLY)
#define KTR_USCHED_DFLY KTR_ALL
#endif
KTR_INFO(KTR_USCHED_DFLY, usched, chooseproc, 0,
"USCHED_DFLY(chooseproc: pid %d, old_cpuid %d, curr_cpuid %d)",
pid_t pid, int old_cpuid, int curr);
void
dfly_acquire_curproc(struct lwp *lp)
{
globaldata_t gd;
dfly_pcpu_t dd;
dfly_pcpu_t rdd;
thread_t td;
int force_resched;
td = lp->lwp_thread;
gd = mycpu;
dd = &dfly_pcpu[gd->gd_cpuid];
if (__predict_true((td->td_flags & TDF_TSLEEPQ) == 0 &&
!sched_action_wanted_gd(gd) &&
dd->uschedcp == lp)) {
return;
}
crit_enter_quick(td);
if (td->td_flags & TDF_TSLEEPQ)
tsleep_remove(td);
dfly_recalculate_estcpu(lp);
force_resched = 0;
if (user_resched_wanted()) {
if (dd->uschedcp == lp)
force_resched = 1;
clear_user_resched();
dfly_release_curproc(lp);
}
if (dd->uschedcp == lp)
lwkt_yield_quick();
while (dd->uschedcp != lp) {
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf(" pid %d acquire curcpu %d (force %d) ",
lp->lwp_proc->p_pid, gd->gd_cpuid,
force_resched);
spin_lock(&dd->spin);
if (__predict_false(
CPUMASK_TESTBIT(lp->lwp_cpumask, gd->gd_cpuid) == 0) &&
(rdd = dfly_choose_best_queue(lp)) != dd) {
dfly_changeqcpu_locked(lp, dd, rdd);
spin_unlock(&dd->spin);
lwkt_deschedule(lp->lwp_thread);
dfly_setrunqueue_dd(rdd, lp);
lwkt_switch();
gd = mycpu;
dd = &dfly_pcpu[gd->gd_cpuid];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-A cpu %d\n", gd->gd_cpuid);
continue;
}
if (force_resched &&
(usched_dfly_features & 0x08) &&
(u_int)sched_ticks / 8 % ncpus == gd->gd_cpuid) {
if ((rdd = dfly_choose_best_queue(lp)) != dd) {
dfly_changeqcpu_locked(lp, dd, rdd);
spin_unlock(&dd->spin);
lwkt_deschedule(lp->lwp_thread);
dfly_setrunqueue_dd(rdd, lp);
lwkt_switch();
gd = mycpu;
dd = &dfly_pcpu[gd->gd_cpuid];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-B cpu %d\n", gd->gd_cpuid);
continue;
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("(SEL-B same cpu) ");
}
if (dd->uschedcp == NULL) {
atomic_clear_int(&lp->lwp_thread->td_mpflags,
TDF_MP_DIDYIELD);
if ((dd->flags & DFLY_PCPU_CURMASK) == 0) {
ATOMIC_CPUMASK_ORBIT(dfly_curprocmask,
gd->gd_cpuid);
dd->flags |= DFLY_PCPU_CURMASK;
}
dd->uschedcp = lp;
dd->upri = lp->lwp_priority;
KKASSERT(lp->lwp_qcpu == dd->cpuid);
spin_unlock(&dd->spin);
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-C cpu %d (same cpu)\n",
gd->gd_cpuid);
break;
}
if (dd->uschedcp &&
(dd->upri & ~PPQMASK) >
(lp->lwp_priority & ~PPQMASK) + usched_dfly_fast_resched) {
dd->uschedcp = lp;
dd->upri = lp->lwp_priority;
KKASSERT(lp->lwp_qcpu == dd->cpuid);
need_user_resched();
spin_unlock(&dd->spin);
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-D cpu %d (same cpu)\n",
gd->gd_cpuid);
break;
}
if (lp->lwp_thread->td_mpflags & TDF_MP_DIDYIELD) {
spin_unlock(&dd->spin);
lp->lwp_rrcount = usched_dfly_rrinterval;
lp->lwp_rqindex = (lp->lwp_priority & PRIMASK) / PPQ;
lwkt_deschedule(lp->lwp_thread);
dfly_setrunqueue_dd(dd, lp);
atomic_clear_int(&lp->lwp_thread->td_mpflags,
TDF_MP_DIDYIELD);
lwkt_switch();
gd = mycpu;
dd = &dfly_pcpu[gd->gd_cpuid];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-E cpu %d (requeue)\n",
gd->gd_cpuid);
continue;
}
if ((usched_dfly_features & 0x02) &&
force_resched == 0 &&
(rdd = dfly_choose_best_queue(lp)) != dd) {
dfly_changeqcpu_locked(lp, dd, rdd);
spin_unlock(&dd->spin);
lwkt_deschedule(lp->lwp_thread);
dfly_setrunqueue_dd(rdd, lp);
lwkt_switch();
gd = mycpu;
dd = &dfly_pcpu[gd->gd_cpuid];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-F cpu %d (requeue new cpu)\n",
gd->gd_cpuid);
continue;
}
spin_unlock(&dd->spin);
lwkt_deschedule(lp->lwp_thread);
dfly_setrunqueue_dd(dd, lp);
lwkt_switch();
gd = mycpu;
dd = &dfly_pcpu[gd->gd_cpuid];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("SEL-G cpu %d (fallback setrunq)\n",
gd->gd_cpuid);
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf(" pid %d acquire DONE cpu %d\n",
lp->lwp_proc->p_pid, gd->gd_cpuid);
crit_exit_quick(td);
KKASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0);
}
static void
dfly_release_curproc(struct lwp *lp)
{
globaldata_t gd = mycpu;
dfly_pcpu_t dd = &dfly_pcpu[gd->gd_cpuid];
if (dd->uschedcp == lp) {
KKASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0);
spin_lock(&dd->spin);
if (dd->uschedcp == lp) {
dd->uschedcp = NULL;
dd->upri = PRIBASE_NULL;
if ((lp->lwp_thread->td_mpflags & TDF_MP_DIDYIELD) == 0) {
if (dd->flags & DFLY_PCPU_CURMASK) {
ATOMIC_CPUMASK_NANDBIT(dfly_curprocmask,
gd->gd_cpuid);
dd->flags &= ~DFLY_PCPU_CURMASK;
}
}
spin_unlock(&dd->spin);
dfly_select_curproc(gd);
} else {
spin_unlock(&dd->spin);
}
}
}
static
void
dfly_select_curproc(globaldata_t gd)
{
dfly_pcpu_t dd = &dfly_pcpu[gd->gd_cpuid];
struct lwp *nlp;
int cpuid = gd->gd_cpuid;
crit_enter_gd(gd);
spin_lock(&dd->spin);
nlp = dfly_chooseproc_locked(dd, dd, dd->uschedcp, 0);
if (nlp) {
if ((dd->flags & DFLY_PCPU_CURMASK) == 0) {
ATOMIC_CPUMASK_ORBIT(dfly_curprocmask, cpuid);
dd->flags |= DFLY_PCPU_CURMASK;
}
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
#if 0
dd->rrcount = 0;
#endif
spin_unlock(&dd->spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else {
spin_unlock(&dd->spin);
}
crit_exit_gd(gd);
}
static void
dfly_setrunqueue(struct lwp *lp)
{
dfly_pcpu_t dd;
dfly_pcpu_t rdd;
KASSERT(lp->lwp_stat == LSRUN, ("setrunqueue: lwp not LSRUN"));
KASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0,
("lwp %d/%d already on runq! flag %08x/%08x", lp->lwp_proc->p_pid,
lp->lwp_tid, lp->lwp_proc->p_flags, lp->lwp_flags));
KKASSERT((lp->lwp_thread->td_flags & TDF_RUNQ) == 0);
dd = &dfly_pcpu[lp->lwp_qcpu];
rdd = dd;
KKASSERT(rdd->uschedcp != lp);
if (lp->lwp_forked) {
lp->lwp_forked = 0;
if (usched_dfly_features & 0x20)
rdd = dfly_choose_best_queue(lp);
else if (usched_dfly_features & 0x40)
rdd = &dfly_pcpu[lp->lwp_qcpu];
else if (usched_dfly_features & 0x80)
rdd = dfly_choose_queue_simple(rdd, lp);
else if (dfly_pcpu[lp->lwp_qcpu].runqcount)
rdd = dfly_choose_best_queue(lp);
else
rdd = &dfly_pcpu[lp->lwp_qcpu];
} else {
rdd = dfly_choose_best_queue(lp);
}
if (lp->lwp_qcpu != rdd->cpuid) {
spin_lock(&dd->spin);
dfly_changeqcpu_locked(lp, dd, rdd);
spin_unlock(&dd->spin);
}
dfly_setrunqueue_dd(rdd, lp);
}
static void
dfly_changeqcpu_locked(struct lwp *lp, dfly_pcpu_t dd, dfly_pcpu_t rdd)
{
if (lp->lwp_qcpu != rdd->cpuid) {
spin_lock(&lp->lwp_spin);
if (lp->lwp_mpflags & LWP_MP_ULOAD) {
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ULOAD);
atomic_add_long(&dd->uload, -lp->lwp_uload);
atomic_add_int(&dd->ucount, -1);
}
lp->lwp_qcpu = rdd->cpuid;
spin_unlock(&lp->lwp_spin);
}
}
static void
dfly_setrunqueue_dd(dfly_pcpu_t rdd, struct lwp *lp)
{
globaldata_t rgd;
if ((lp->lwp_thread->td_flags & TDF_MIGRATING) == 0)
lwkt_giveaway(lp->lwp_thread);
rgd = rdd->gd;
spin_lock(&rdd->spin);
dfly_setrunqueue_locked(rdd, lp);
if ((rdd->upri & ~PPQMASK) <= (lp->lwp_priority & ~PPQMASK)) {
spin_unlock(&rdd->spin);
} else if ((rdd->upri & ~PPQMASK) <= (lp->lwp_priority & ~PPQMASK) +
usched_dfly_fast_resched) {
if (rdd->uschedcp &&
rdd->uschedcp->lwp_rrcount < usched_dfly_rrinterval) {
rdd->uschedcp->lwp_rrcount = usched_dfly_rrinterval - 1;
}
spin_unlock(&rdd->spin);
} else if (rgd == mycpu) {
spin_unlock(&rdd->spin);
if (rdd->uschedcp == NULL)
wakeup_mycpu(rdd->helper_thread);
if ((lp->lwp_thread->td_mpflags & TDF_MP_DIDYIELD) == 0)
need_user_resched();
} else {
spin_unlock(&rdd->spin);
lwkt_send_ipiq(rgd, dfly_need_user_resched_remote, NULL);
}
}
static
void
dfly_schedulerclock(struct lwp *lp, sysclock_t period, sysclock_t cpstamp)
{
globaldata_t gd = mycpu;
dfly_pcpu_t dd = &dfly_pcpu[gd->gd_cpuid];
KKASSERT(gd->gd_spinlocks == 0 || dumping);
if (gd->gd_curthread == &gd->gd_idlethread) {
lp = dd->uschedcp;
if (lp && (lp->lwp_thread == NULL ||
lp->lwp_thread->td_contended == 0)) {
lp = NULL;
}
}
if (lp) {
if (++lp->lwp_rrcount >= usched_dfly_rrinterval)
need_user_resched();
if ((lp->lwp_thread->td_mpflags & TDF_MP_BATCH_DEMARC) &&
lp->lwp_rrcount >= usched_dfly_rrinterval / 2) {
need_user_resched();
}
lp->lwp_estcpu = ESTCPULIM(lp->lwp_estcpu +
ESTCPUMAX / ESTCPUFREQ + 1);
dfly_resetpriority(lp);
}
if ((usched_dfly_features & 0x04) &&
((u_int)sched_ticks & 7) == 0 &&
(u_int)sched_ticks / 8 % ncpus == gd->gd_cpuid) {
struct lwp *nlp;
dfly_pcpu_t rdd;
rdd = dfly_choose_worst_queue(dd, 1);
if (rdd && dd->uload + usched_dfly_weight6 / 2 < rdd->uload) {
spin_lock(&dd->spin);
if (spin_trylock(&rdd->spin)) {
nlp = dfly_chooseproc_locked(rdd, dd, NULL, 1);
spin_unlock(&rdd->spin);
if (nlp == NULL)
spin_unlock(&dd->spin);
} else {
spin_unlock(&dd->spin);
nlp = NULL;
}
} else {
nlp = NULL;
}
if (nlp &&
(nlp->lwp_priority & ~PPQMASK) < (dd->upri & ~PPQMASK)) {
if ((dd->flags & DFLY_PCPU_CURMASK) == 0) {
ATOMIC_CPUMASK_ORMASK(dfly_curprocmask,
dd->cpumask);
dd->flags |= DFLY_PCPU_CURMASK;
}
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
#if 0
dd->rrcount = 0;
#endif
spin_unlock(&dd->spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else if (nlp) {
dfly_setrunqueue_locked(dd, nlp);
spin_unlock(&dd->spin);
}
}
}
static
void
dfly_recalculate_estcpu(struct lwp *lp)
{
globaldata_t gd = mycpu;
sysclock_t cpbase;
sysclock_t ttlticks;
int estcpu;
int decay_factor;
int ucount;
cpbase = gd->gd_schedclock.time - gd->gd_schedclock.periodic;
if (lp->lwp_slptime > 1) {
lp->lwp_estcpu = lp->lwp_estcpu >> 1;
dfly_resetpriority(lp);
lp->lwp_cpbase = cpbase;
lp->lwp_cpticks = 0;
lp->lwp_estfast = 0;
} else if (lp->lwp_cpbase != cpbase) {
ttlticks = (cpbase - lp->lwp_cpbase) /
gd->gd_schedclock.periodic;
if ((ssysclock_t)ttlticks < 0) {
ttlticks = 0;
lp->lwp_cpbase = cpbase;
}
if (ttlticks < 4)
return;
updatepcpu(lp, lp->lwp_cpticks, ttlticks);
ucount = dfly_pcpu[lp->lwp_qcpu].ucount;
estcpu = lp->lwp_cpticks * ESTCPUMAX / ttlticks;
if (ttlticks >= hz)
decay_factor = 1;
else
decay_factor = hz - ttlticks;
lp->lwp_estcpu = ESTCPULIM(
(lp->lwp_estcpu * ttlticks + estcpu) /
(ttlticks + 1));
dfly_resetpriority(lp);
lp->lwp_cpbase += ttlticks * gd->gd_schedclock.periodic;
lp->lwp_cpticks = 0;
}
}
static void
dfly_resetpriority(struct lwp *lp)
{
dfly_pcpu_t rdd;
int newpriority;
u_short newrqtype;
int rcpu;
int checkpri;
int estcpu;
int delta_uload;
crit_enter();
for (;;) {
rcpu = lp->lwp_qcpu;
cpu_ccfence();
rdd = &dfly_pcpu[rcpu];
spin_lock(&rdd->spin);
if (rcpu == lp->lwp_qcpu)
break;
spin_unlock(&rdd->spin);
}
newrqtype = lp->lwp_rtprio.type;
switch(newrqtype) {
case RTP_PRIO_REALTIME:
case RTP_PRIO_FIFO:
newpriority = PRIBASE_REALTIME +
(lp->lwp_rtprio.prio & PRIMASK);
break;
case RTP_PRIO_NORMAL:
estcpu = lp->lwp_estcpu;
newpriority = (lp->lwp_proc->p_nice - PRIO_MIN) *
(NICE_QS * PPQ) / PRIO_RANGE;
newpriority += estcpu * PPQ / ESTCPUPPQ;
if (newpriority < 0)
newpriority = 0;
if (newpriority >= MAXPRI)
newpriority = MAXPRI - 1;
newpriority += PRIBASE_NORMAL;
break;
case RTP_PRIO_IDLE:
newpriority = PRIBASE_IDLE + (lp->lwp_rtprio.prio & PRIMASK);
break;
case RTP_PRIO_THREAD:
newpriority = PRIBASE_THREAD + (lp->lwp_rtprio.prio & PRIMASK);
break;
default:
panic("Bad RTP_PRIO %d", newrqtype);
}
lp->lwp_thread->td_upri = -(newpriority & usched_dfly_swmask);
if ((lp->lwp_priority ^ newpriority) & ~PPQMASK) {
if (lp->lwp_priority < newpriority)
lp->lwp_rrcount = 0;
if (lp->lwp_mpflags & LWP_MP_ONRUNQ) {
dfly_remrunqueue_locked(rdd, lp);
lp->lwp_priority = newpriority;
lp->lwp_rqtype = newrqtype;
lp->lwp_rqindex = (newpriority & PRIMASK) / PPQ;
dfly_setrunqueue_locked(rdd, lp);
checkpri = 1;
} else {
lp->lwp_priority = newpriority;
lp->lwp_rqtype = newrqtype;
lp->lwp_rqindex = (newpriority & PRIMASK) / PPQ;
checkpri = 0;
}
} else {
lp->lwp_priority = newpriority;
checkpri = 1;
rcpu = -1;
}
spin_lock(&lp->lwp_spin);
delta_uload = lptouload(lp);
delta_uload -= lp->lwp_uload;
if (lp->lwp_uload + delta_uload < -32767) {
delta_uload = -32768 - lp->lwp_uload;
} else if (lp->lwp_uload + delta_uload > 32767) {
delta_uload = 32767 - lp->lwp_uload;
}
lp->lwp_uload += delta_uload;
if (lp->lwp_mpflags & LWP_MP_ULOAD)
atomic_add_long(&dfly_pcpu[lp->lwp_qcpu].uload, delta_uload);
spin_unlock(&lp->lwp_spin);
if (rcpu >= 0) {
if (CPUMASK_TESTBIT(dfly_rdyprocmask, rcpu) &&
(checkpri == 0 ||
(rdd->upri & ~PRIMASK) >
(lp->lwp_priority & ~PRIMASK))) {
if (rcpu == mycpu->gd_cpuid) {
spin_unlock(&rdd->spin);
need_user_resched();
} else {
spin_unlock(&rdd->spin);
lwkt_send_ipiq(globaldata_find(rcpu),
dfly_need_user_resched_remote,
NULL);
}
} else {
spin_unlock(&rdd->spin);
}
} else {
spin_unlock(&rdd->spin);
}
crit_exit();
}
static
void
dfly_yield(struct lwp *lp)
{
if (lp->lwp_qcpu != mycpu->gd_cpuid)
return;
KKASSERT(lp == curthread->td_lwp);
atomic_set_int(&lp->lwp_thread->td_mpflags, TDF_MP_DIDYIELD);
dfly_release_curproc(lp);
}
static
void
dfly_changedcpu(struct lwp *lp)
{
dfly_pcpu_t dd = &dfly_pcpu[lp->lwp_qcpu];
dfly_pcpu_t rdd = &dfly_pcpu[mycpu->gd_cpuid];
if (dd != rdd) {
spin_lock(&dd->spin);
dfly_changeqcpu_locked(lp, dd, rdd);
spin_unlock(&dd->spin);
}
}
static void
dfly_forking(struct lwp *plp, struct lwp *lp)
{
int estcpu;
lp->lwp_estcpu = ESTCPULIM(plp->lwp_estcpu +
ESTCPUPPQ * usched_dfly_forkbias);
lp->lwp_forked = 1;
lp->lwp_estfast = 0;
#if 0
static uint16_t save_cpu;
lp->lwp_qcpu = ++save_cpu % ncpus;
#else
lp->lwp_qcpu = plp->lwp_qcpu;
if (CPUMASK_TESTBIT(lp->lwp_cpumask, lp->lwp_qcpu) == 0)
lp->lwp_qcpu = BSFCPUMASK(lp->lwp_cpumask);
#endif
estcpu = plp->lwp_estcpu + ESTCPUPPQ / 16;
plp->lwp_estcpu = ESTCPULIM(estcpu);
}
static void
dfly_exiting(struct lwp *lp, struct proc *child_proc)
{
dfly_pcpu_t dd;
spin_lock(&lp->lwp_spin);
dd = &dfly_pcpu[lp->lwp_qcpu];
if (lp->lwp_mpflags & LWP_MP_ULOAD) {
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ULOAD);
atomic_add_long(&dd->uload, -lp->lwp_uload);
atomic_add_int(&dd->ucount, -1);
}
spin_unlock(&lp->lwp_spin);
}
static void
dfly_uload_update(struct lwp *lp)
{
dfly_pcpu_t dd;
if (lp->lwp_thread->td_flags & TDF_RUNQ) {
if ((lp->lwp_mpflags & LWP_MP_ULOAD) == 0) {
spin_lock(&lp->lwp_spin);
dd = &dfly_pcpu[lp->lwp_qcpu];
if ((lp->lwp_mpflags & LWP_MP_ULOAD) == 0) {
atomic_set_int(&lp->lwp_mpflags,
LWP_MP_ULOAD);
atomic_add_long(&dd->uload, lp->lwp_uload);
atomic_add_int(&dd->ucount, 1);
}
spin_unlock(&lp->lwp_spin);
}
} else if (lp->lwp_slptime > 0) {
if (lp->lwp_mpflags & LWP_MP_ULOAD) {
spin_lock(&lp->lwp_spin);
dd = &dfly_pcpu[lp->lwp_qcpu];
if (lp->lwp_mpflags & LWP_MP_ULOAD) {
atomic_clear_int(&lp->lwp_mpflags,
LWP_MP_ULOAD);
atomic_add_long(&dd->uload, -lp->lwp_uload);
atomic_add_int(&dd->ucount, -1);
}
spin_unlock(&lp->lwp_spin);
}
}
}
static
struct lwp *
dfly_chooseproc_locked(dfly_pcpu_t rdd, dfly_pcpu_t dd,
struct lwp *chklp, int worst)
{
struct lwp *lp;
struct rq *q;
u_int32_t *which;
u_int32_t pri;
u_int32_t rtqbits;
u_int32_t tsqbits;
u_int32_t idqbits;
rtqbits = rdd->rtqueuebits;
tsqbits = rdd->queuebits;
idqbits = rdd->idqueuebits;
loopfar:
if (worst) {
if (idqbits) {
pri = bsrl(idqbits);
idqbits &= ~(1U << pri);
q = &rdd->idqueues[pri];
which = &rdd->idqueuebits;
} else if (tsqbits) {
pri = bsrl(tsqbits);
tsqbits &= ~(1U << pri);
q = &rdd->queues[pri];
which = &rdd->queuebits;
} else if (rtqbits) {
pri = bsrl(rtqbits);
rtqbits &= ~(1U << pri);
q = &rdd->rtqueues[pri];
which = &rdd->rtqueuebits;
} else {
return (NULL);
}
lp = TAILQ_LAST(q, rq);
} else {
if (rtqbits) {
pri = bsfl(rtqbits);
rtqbits &= ~(1U << pri);
q = &rdd->rtqueues[pri];
which = &rdd->rtqueuebits;
} else if (tsqbits) {
pri = bsfl(tsqbits);
tsqbits &= ~(1U << pri);
q = &rdd->queues[pri];
which = &rdd->queuebits;
} else if (idqbits) {
pri = bsfl(idqbits);
idqbits &= ~(1U << pri);
q = &rdd->idqueues[pri];
which = &rdd->idqueuebits;
} else {
return (NULL);
}
lp = TAILQ_FIRST(q);
}
KASSERT(lp, ("chooseproc: no lwp on busy queue"));
loopnear:
if (chklp) {
if (chklp->lwp_priority < lp->lwp_priority + PPQ)
return(NULL);
}
if (rdd != dd && CPUMASK_TESTBIT(lp->lwp_cpumask, dd->cpuid) == 0) {
if (worst)
lp = TAILQ_PREV(lp, rq, lwp_procq);
else
lp = TAILQ_NEXT(lp, lwp_procq);
if (lp)
goto loopnear;
goto loopfar;
}
KTR_COND_LOG(usched_chooseproc,
lp->lwp_proc->p_pid == usched_dfly_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
mycpu->gd_cpuid);
KASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) != 0, ("not on runq6!"));
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
TAILQ_REMOVE(q, lp, lwp_procq);
--rdd->runqcount;
if (TAILQ_EMPTY(q))
*which &= ~(1 << pri);
if (rdd != dd) {
spin_lock(&lp->lwp_spin);
if (lp->lwp_mpflags & LWP_MP_ULOAD) {
atomic_add_long(&rdd->uload, -lp->lwp_uload);
atomic_add_int(&rdd->ucount, -1);
}
lp->lwp_qcpu = dd->cpuid;
atomic_add_long(&dd->uload, lp->lwp_uload);
atomic_add_int(&dd->ucount, 1);
atomic_set_int(&lp->lwp_mpflags, LWP_MP_ULOAD);
spin_unlock(&lp->lwp_spin);
}
return lp;
}
static
dfly_pcpu_t
dfly_choose_best_queue(struct lwp *lp)
{
cpumask_t wakemask;
cpumask_t mask;
cpu_node_t *cpup;
cpu_node_t *cpun;
cpu_node_t *cpub;
dfly_pcpu_t dd = &dfly_pcpu[lp->lwp_qcpu];
dfly_pcpu_t rdd;
int wakecpu;
int cpuid;
int n;
int loadav;
long load;
long lowest_load;
if (dd->cpunode == NULL)
return (dfly_choose_queue_simple(dd, lp));
loadav = (averunnable.ldavg[0] + FSCALE / 2) >> FSHIFT;
if ((wakecpu = lp->lwp_thread->td_wakefromcpu) >= 0)
wakemask = dfly_pcpu[wakecpu].cpumask;
else
CPUMASK_ASSZERO(wakemask);
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("choosebest wakefromcpu %d:\n",
lp->lwp_thread->td_wakefromcpu);
cpup = root_cpu_node;
rdd = dd;
while (cpup) {
if (cpup->child_no == 1) {
cpup = cpup->child_node[0];
continue;
}
if (cpup->child_no == 0) {
rdd = &dfly_pcpu[BSFCPUMASK(cpup->members)];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf(" last cpu %d\n", rdd->cpuid);
break;
}
cpub = NULL;
lowest_load = 0x7FFFFFFFFFFFFFFFLL;
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf(" reset lowest_load for scan\n");
for (n = 0; n < cpup->child_no; ++n) {
int count;
cpun = cpup->child_node[n];
mask = cpun->members;
CPUMASK_ANDMASK(mask, usched_global_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, lp->lwp_cpumask);
if (CPUMASK_TESTZERO(mask))
continue;
load = 0;
count = 0;
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf(" mask:");
while (CPUMASK_TESTNZERO(mask)) {
cpuid = BSFCPUMASK(mask);
rdd = &dfly_pcpu[cpuid];
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf(" %d", cpuid);
load += rdd->uload;
load += rdd->ucount *
usched_dfly_weight3;
if ((rdd->upri & ~PPQMASK) >
(lp->lwp_priority & ~PPQMASK)) {
load -= usched_dfly_weight4;
}
#if 0
if (rdd->uschedcp == NULL &&
rdd->runqcount == 0 &&
rdd->gd->gd_tdrunqcount == 0
) {
load += rdd->uload / 2;
load += rdd->ucount *
usched_dfly_weight3 / 2;
} else {
load += rdd->uload;
load += rdd->ucount *
usched_dfly_weight3;
}
#endif
CPUMASK_NANDBIT(mask, cpuid);
++count;
}
if ((lp->lwp_mpflags & LWP_MP_ULOAD) &&
CPUMASK_TESTMASK(dd->cpumask, cpun->members)) {
load -= lp->lwp_uload;
load -= usched_dfly_weight3;
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("\n accum_start c=%d ld=%ld "
"cpu=%d ld/cnt=%ld ",
count, load, rdd->cpuid,
load / count);
load = load / count;
if (CPUMASK_TESTMASK(cpun->members, dd->cpumask))
load -= usched_dfly_weight1;
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("B:%ld ", load);
if (usched_dfly_node_mem) {
load -= cpun->phys_mem * usched_dfly_weight5 /
usched_dfly_node_mem;
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("C:%ld ", load);
if (CPUMASK_TESTMASK(cpun->members, wakemask)) {
if (cpun->child_no) {
if (cpun->type == CORE_LEVEL &&
usched_dfly_ipc_smt < 0 &&
loadav >= (ncpus >> 1)) {
load -= usched_dfly_weight2;
} else if (cpun->type == CORE_LEVEL &&
usched_dfly_ipc_smt == 0) {
load += usched_dfly_weight2;
} else {
load -= usched_dfly_weight2;
}
} else {
if (usched_dfly_ipc_same < 0 &&
loadav >= ncpus) {
load -= usched_dfly_weight2;
} else if (usched_dfly_ipc_same) {
load -= usched_dfly_weight2;
} else {
load += usched_dfly_weight2;
}
}
#if 0
if (cpun->child_no != 0) {
load -= usched_dfly_weight2;
} else {
if (usched_dfly_features & 0x10)
load += usched_dfly_weight2;
else
load -= usched_dfly_weight2;
}
#endif
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("D:%ld ", load);
if (cpub == NULL || lowest_load > load ||
(lowest_load == load &&
CPUMASK_TESTMASK(cpun->members, dd->cpumask))
) {
lowest_load = load;
cpub = cpun;
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("low=%ld]\n", lowest_load);
}
cpup = cpub;
}
if (__predict_false(CPUMASK_TESTBIT(lp->lwp_cpumask, rdd->cpuid) == 0))
rdd = &dfly_pcpu[BSFCPUMASK(lp->lwp_cpumask)];
if (usched_dfly_chooser > 0) {
--usched_dfly_chooser;
kprintf("lp %02d->%02d %s\n",
lp->lwp_qcpu, rdd->cpuid, lp->lwp_proc->p_comm);
}
if (usched_dfly_debug == lp->lwp_proc->p_pid)
kprintf("final cpu %d\n", rdd->cpuid);
return (rdd);
}
static
dfly_pcpu_t
dfly_choose_worst_queue(dfly_pcpu_t dd, int forceit)
{
cpumask_t mask;
cpu_node_t *cpup;
cpu_node_t *cpun;
cpu_node_t *cpub;
dfly_pcpu_t rdd;
int cpuid;
int n;
int highest_runqcount;
long load;
long highest_load;
#if 0
int pri;
int hpri;
#endif
if (dd->cpunode == NULL) {
return (NULL);
}
cpup = root_cpu_node;
rdd = dd;
while (cpup) {
if (cpup->child_no == 1) {
cpup = cpup->child_node[0];
continue;
}
if (cpup->child_no == 0) {
rdd = &dfly_pcpu[BSFCPUMASK(cpup->members)];
break;
}
cpub = NULL;
highest_load = -0x7FFFFFFFFFFFFFFFLL;
for (n = 0; n < cpup->child_no; ++n) {
int count;
int runqcount;
cpun = cpup->child_node[n];
mask = cpun->members;
CPUMASK_ANDMASK(mask, usched_global_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
if (CPUMASK_TESTZERO(mask))
continue;
load = 0;
count = 0;
runqcount = 0;
while (CPUMASK_TESTNZERO(mask)) {
cpuid = BSFCPUMASK(mask);
rdd = &dfly_pcpu[cpuid];
load += rdd->uload;
load += rdd->ucount * usched_dfly_weight3;
#if 0
if (rdd->uschedcp == NULL &&
rdd->runqcount == 0 &&
rdd->gd->gd_tdrunqcount == 0
) {
load += rdd->uload / 2;
load += rdd->ucount *
usched_dfly_weight3 / 2;
} else {
load += rdd->uload;
load += rdd->ucount *
usched_dfly_weight3;
}
#endif
CPUMASK_NANDBIT(mask, cpuid);
++count;
runqcount += rdd->runqcount;
}
load /= count;
if (forceit == 0 &&
CPUMASK_TESTMASK(dd->cpumask, cpun->members)) {
load += usched_dfly_weight1 / 2;
}
if (usched_dfly_node_mem) {
load -= cpun->phys_mem * usched_dfly_weight5 /
usched_dfly_node_mem;
}
if (cpub == NULL ||
(runqcount && (highest_load < load ||
(highest_load == load &&
CPUMASK_TESTMASK(cpun->members,
dd->cpumask)))) ||
(runqcount && highest_runqcount < runqcount + 1)) {
highest_load = load;
highest_runqcount = runqcount;
cpub = cpun;
}
}
cpup = cpub;
}
if (rdd == dd)
return(NULL);
#if 0
hpri = 0;
if (rdd->rtqueuebits && hpri < (pri = bsrl(rdd->rtqueuebits)))
hpri = pri;
if (rdd->queuebits && hpri < (pri = bsrl(rdd->queuebits)))
hpri = pri;
if (rdd->idqueuebits && hpri < (pri = bsrl(rdd->idqueuebits)))
hpri = pri;
hpri *= PPQ;
if (rdd->uload - hpri < dd->uload + hpri)
return(NULL);
#endif
return (rdd);
}
static
dfly_pcpu_t
dfly_choose_queue_simple(dfly_pcpu_t dd, struct lwp *lp)
{
dfly_pcpu_t rdd;
cpumask_t tmpmask;
cpumask_t mask;
int cpubase;
int cpuid;
++dd->scancpu;
mask = dfly_rdyprocmask;
CPUMASK_NANDMASK(mask, dfly_curprocmask);
CPUMASK_ANDMASK(mask, lp->lwp_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, usched_global_cpumask);
cpubase = (int)(dd->scancpu % ncpus);
CPUMASK_ASSBMASK(tmpmask, cpubase);
CPUMASK_INVMASK(tmpmask);
CPUMASK_ANDMASK(tmpmask, mask);
while (CPUMASK_TESTNZERO(tmpmask)) {
cpuid = BSFCPUMASK(tmpmask);
rdd = &dfly_pcpu[cpuid];
if ((rdd->upri & ~PPQMASK) >= (lp->lwp_priority & ~PPQMASK))
goto found;
CPUMASK_NANDBIT(tmpmask, cpuid);
}
CPUMASK_ASSBMASK(tmpmask, cpubase);
CPUMASK_ANDMASK(tmpmask, mask);
while (CPUMASK_TESTNZERO(tmpmask)) {
cpuid = BSFCPUMASK(tmpmask);
rdd = &dfly_pcpu[cpuid];
if ((rdd->upri & ~PPQMASK) >= (lp->lwp_priority & ~PPQMASK))
goto found;
CPUMASK_NANDBIT(tmpmask, cpuid);
}
mask = dfly_rdyprocmask;
CPUMASK_ANDMASK(mask, dfly_curprocmask);
CPUMASK_ANDMASK(mask, lp->lwp_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, usched_global_cpumask);
CPUMASK_ASSBMASK(tmpmask, cpubase);
CPUMASK_INVMASK(tmpmask);
CPUMASK_ANDMASK(tmpmask, mask);
while (CPUMASK_TESTNZERO(tmpmask)) {
cpuid = BSFCPUMASK(tmpmask);
rdd = &dfly_pcpu[cpuid];
if ((rdd->upri & ~PPQMASK) > (lp->lwp_priority & ~PPQMASK))
goto found;
CPUMASK_NANDBIT(tmpmask, cpuid);
}
CPUMASK_ASSBMASK(tmpmask, cpubase);
CPUMASK_ANDMASK(tmpmask, mask);
while (CPUMASK_TESTNZERO(tmpmask)) {
cpuid = BSFCPUMASK(tmpmask);
rdd = &dfly_pcpu[cpuid];
if ((rdd->upri & ~PPQMASK) > (lp->lwp_priority & ~PPQMASK))
goto found;
CPUMASK_NANDBIT(tmpmask, cpuid);
}
cpuid = cpubase;
if (CPUMASK_TESTBIT(lp->lwp_cpumask, cpuid) == 0)
cpuid = BSFCPUMASK(lp->lwp_cpumask);
else if (CPUMASK_TESTBIT(usched_global_cpumask, cpuid) == 0)
cpuid = 0;
rdd = &dfly_pcpu[cpuid];
found:
return (rdd);
}
static
void
dfly_need_user_resched_remote(void *dummy)
{
globaldata_t gd = mycpu;
dfly_pcpu_t dd = &dfly_pcpu[gd->gd_cpuid];
need_user_resched();
if (dd->uschedcp == NULL && (dd->flags & DFLY_PCPU_RDYMASK)) {
ATOMIC_CPUMASK_NANDBIT(dfly_rdyprocmask, gd->gd_cpuid);
dd->flags &= ~DFLY_PCPU_RDYMASK;
wakeup_mycpu(dd->helper_thread);
}
}
static void
dfly_remrunqueue_locked(dfly_pcpu_t rdd, struct lwp *lp)
{
struct rq *q;
u_int32_t *which;
u_int8_t pri;
KKASSERT(rdd->runqcount >= 0);
pri = lp->lwp_rqindex;
switch(lp->lwp_rqtype) {
case RTP_PRIO_NORMAL:
q = &rdd->queues[pri];
which = &rdd->queuebits;
break;
case RTP_PRIO_REALTIME:
case RTP_PRIO_FIFO:
q = &rdd->rtqueues[pri];
which = &rdd->rtqueuebits;
break;
case RTP_PRIO_IDLE:
q = &rdd->idqueues[pri];
which = &rdd->idqueuebits;
break;
default:
panic("remrunqueue: invalid rtprio type");
}
KKASSERT(lp->lwp_mpflags & LWP_MP_ONRUNQ);
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
TAILQ_REMOVE(q, lp, lwp_procq);
--rdd->runqcount;
if (TAILQ_EMPTY(q)) {
KASSERT((*which & (1 << pri)) != 0,
("remrunqueue: remove from empty queue"));
*which &= ~(1 << pri);
}
}
static void
dfly_setrunqueue_locked(dfly_pcpu_t rdd, struct lwp *lp)
{
u_int32_t *which;
struct rq *q;
int pri;
KKASSERT(lp->lwp_qcpu == rdd->cpuid);
spin_lock(&lp->lwp_spin);
if ((lp->lwp_mpflags & LWP_MP_ULOAD) == 0) {
atomic_set_int(&lp->lwp_mpflags, LWP_MP_ULOAD);
atomic_add_long(&rdd->uload, lp->lwp_uload);
atomic_add_int(&rdd->ucount, 1);
}
spin_unlock(&lp->lwp_spin);
pri = lp->lwp_rqindex;
switch(lp->lwp_rqtype) {
case RTP_PRIO_NORMAL:
q = &rdd->queues[pri];
which = &rdd->queuebits;
break;
case RTP_PRIO_REALTIME:
case RTP_PRIO_FIFO:
q = &rdd->rtqueues[pri];
which = &rdd->rtqueuebits;
break;
case RTP_PRIO_IDLE:
q = &rdd->idqueues[pri];
which = &rdd->idqueuebits;
break;
default:
panic("remrunqueue: invalid rtprio type");
}
KKASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0);
atomic_set_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
++rdd->runqcount;
if (lp->lwp_rrcount >= usched_dfly_rrinterval ||
(lp->lwp_rrcount >= usched_dfly_rrinterval / 2 &&
(lp->lwp_thread->td_mpflags & TDF_MP_BATCH_DEMARC))
) {
atomic_clear_int(&lp->lwp_thread->td_mpflags,
TDF_MP_BATCH_DEMARC);
lp->lwp_rrcount = 0;
TAILQ_INSERT_TAIL(q, lp, lwp_procq);
} else {
TAILQ_INSERT_HEAD(q, lp, lwp_procq);
}
*which |= 1 << pri;
}
static void
dfly_helper_thread(void *dummy)
{
globaldata_t gd;
dfly_pcpu_t dd;
dfly_pcpu_t rdd;
struct lwp *nlp;
cpumask_t mask;
int sleepok;
int cpuid;
gd = mycpu;
cpuid = gd->gd_cpuid;
mask = gd->gd_cpumask;
dd = &dfly_pcpu[cpuid];
lockmgr(&usched_dfly_config_lk, LK_SHARED);
lockmgr(&usched_dfly_config_lk, LK_RELEASE);
lwkt_setpri_self(TDPRI_USER_SCHEDULER);
for (;;) {
sleepok = 1;
crit_enter_gd(gd);
tsleep_interlock(dd->helper_thread, 0);
spin_lock(&dd->spin);
if ((dd->flags & DFLY_PCPU_RDYMASK) == 0) {
ATOMIC_CPUMASK_ORMASK(dfly_rdyprocmask, mask);
dd->flags |= DFLY_PCPU_RDYMASK;
}
clear_user_resched();
#if 0
dd->rrcount = 0;
#endif
if (dd->runqcount || dd->uschedcp != NULL) {
nlp = dfly_chooseproc_locked(dd, dd, dd->uschedcp, 0);
if (nlp) {
if ((dd->flags & DFLY_PCPU_CURMASK) == 0) {
ATOMIC_CPUMASK_ORMASK(dfly_curprocmask, mask);
dd->flags |= DFLY_PCPU_CURMASK;
}
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
#if 0
dd->rrcount = 0;
#endif
spin_unlock(&dd->spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else {
spin_unlock(&dd->spin);
}
} else if (usched_dfly_features & 0x01) {
rdd = dfly_choose_worst_queue(dd, 0);
if (rdd && dd->uload + usched_dfly_weight7 < rdd->uload) {
if (rdd->uschedcp && spin_trylock(&rdd->spin)) {
nlp = dfly_chooseproc_locked(rdd, dd, NULL, 1);
spin_unlock(&rdd->spin);
} else {
nlp = NULL;
}
} else {
nlp = NULL;
}
if (nlp) {
if ((dd->flags & DFLY_PCPU_CURMASK) == 0) {
ATOMIC_CPUMASK_ORMASK(dfly_curprocmask, mask);
dd->flags |= DFLY_PCPU_CURMASK;
}
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
#if 0
dd->rrcount = 0;
#endif
spin_unlock(&dd->spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else {
spin_unlock(&dd->spin);
}
} else {
spin_unlock(&dd->spin);
}
crit_exit_gd(gd);
if (sleepok) {
tsleep(dd->helper_thread, PINTERLOCKED, "schslp",
usched_dfly_poll_ticks);
}
}
}
#if 0
static int
sysctl_usched_dfly_stick_to_level(SYSCTL_HANDLER_ARGS)
{
int error, new_val;
new_val = usched_dfly_stick_to_level;
error = sysctl_handle_int(oidp, &new_val, 0, req);
if (error != 0 || req->newptr == NULL)
return (error);
if (new_val > cpu_topology_levels_number - 1 || new_val < 0)
return (EINVAL);
usched_dfly_stick_to_level = new_val;
return (0);
}
#endif
static void
usched_dfly_cpu_init(void)
{
int i;
int j;
int smt_not_supported = 0;
int cache_coherent_not_supported = 0;
if (bootverbose)
kprintf("Start usched_dfly helpers on cpus:\n");
sysctl_ctx_init(&usched_dfly_sysctl_ctx);
usched_dfly_sysctl_tree =
SYSCTL_ADD_NODE(&usched_dfly_sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO,
"usched_dfly", CTLFLAG_RD, 0, "");
usched_dfly_node_mem = get_highest_node_memory();
lockmgr(&usched_dfly_config_lk, LK_EXCLUSIVE);
for (i = 0; i < ncpus; ++i) {
dfly_pcpu_t dd = &dfly_pcpu[i];
cpumask_t mask;
CPUMASK_ASSBIT(mask, i);
if (CPUMASK_TESTMASK(mask, smp_active_mask) == 0)
continue;
spin_init(&dd->spin, "uschedcpuinit");
dd->cpunode = get_cpu_node_by_cpuid(i);
dd->cpuid = i;
dd->gd = globaldata_find(i);
CPUMASK_ASSBIT(dd->cpumask, i);
for (j = 0; j < NQS; j++) {
TAILQ_INIT(&dd->queues[j]);
TAILQ_INIT(&dd->rtqueues[j]);
TAILQ_INIT(&dd->idqueues[j]);
}
ATOMIC_CPUMASK_NANDBIT(dfly_curprocmask, 0);
if (i == 0)
dd->flags &= ~DFLY_PCPU_CURMASK;
if (dd->cpunode == NULL) {
smt_not_supported = 1;
cache_coherent_not_supported = 1;
if (bootverbose)
kprintf (" cpu%d - WARNING: No CPU NODE "
"found for cpu\n", i);
} else {
switch (dd->cpunode->type) {
case THREAD_LEVEL:
if (bootverbose)
kprintf (" cpu%d - HyperThreading "
"available. Core siblings: ",
i);
break;
case CORE_LEVEL:
smt_not_supported = 1;
if (bootverbose)
kprintf (" cpu%d - No HT available, "
"multi-core/physical "
"cpu. Physical siblings: ",
i);
break;
case CHIP_LEVEL:
smt_not_supported = 1;
if (bootverbose)
kprintf (" cpu%d - No HT available, "
"single-core/physical cpu. "
"Package siblings: ",
i);
break;
default:
smt_not_supported = 1;
cache_coherent_not_supported = 1;
if (bootverbose)
kprintf (" cpu%d - Unknown cpunode->"
"type=%u. siblings: ",
i,
(u_int)dd->cpunode->type);
break;
}
if (bootverbose) {
if (dd->cpunode->parent_node != NULL) {
kprint_cpuset(&dd->cpunode->
parent_node->members);
kprintf("\n");
} else {
kprintf(" no siblings\n");
}
}
}
lwkt_create(dfly_helper_thread, NULL, &dd->helper_thread, NULL,
0, i, "usched %d", i);
if (i) {
ATOMIC_CPUMASK_NANDMASK(dfly_curprocmask, mask);
dd->flags &= ~DFLY_PCPU_CURMASK;
}
if ((dd->flags & DFLY_PCPU_RDYMASK) == 0) {
ATOMIC_CPUMASK_ORMASK(dfly_rdyprocmask, mask);
dd->flags |= DFLY_PCPU_RDYMASK;
}
dd->upri = PRIBASE_NULL;
}
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "rrinterval", CTLFLAG_RW,
&usched_dfly_rrinterval, 0, "");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "decay", CTLFLAG_RW,
&usched_dfly_decay, 0, "Extra decay when not running");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "ipc_smt", CTLFLAG_RW,
&usched_dfly_ipc_smt, 0, "Pair IPC on hyper-threads");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "ipc_same", CTLFLAG_RW,
&usched_dfly_ipc_same, 0, "Pair IPC on same thread");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "poll_ticks", CTLFLAG_RW,
&usched_dfly_poll_ticks, 0, "Poll for work (0 ok)");
if (smt_not_supported) {
usched_dfly_smt = 0;
SYSCTL_ADD_STRING(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "smt", CTLFLAG_RD,
"NOT SUPPORTED", 0, "SMT NOT SUPPORTED");
} else {
usched_dfly_smt = 1;
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "smt", CTLFLAG_RW,
&usched_dfly_smt, 0, "Enable SMT scheduling");
}
if (cache_coherent_not_supported) {
usched_dfly_cache_coherent = 0;
SYSCTL_ADD_STRING(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "cache_coherent", CTLFLAG_RD,
"NOT SUPPORTED", 0,
"Cache coherence NOT SUPPORTED");
} else {
usched_dfly_cache_coherent = 1;
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "cache_coherent", CTLFLAG_RW,
&usched_dfly_cache_coherent, 0,
"Enable/Disable cache coherent scheduling");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight1", CTLFLAG_RW,
&usched_dfly_weight1, 200,
"Weight selection for current cpu");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight2", CTLFLAG_RW,
&usched_dfly_weight2, 180,
"Weight selection for wakefrom cpu");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight3", CTLFLAG_RW,
&usched_dfly_weight3, 40,
"Weight selection for num threads on queue");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight4", CTLFLAG_RW,
&usched_dfly_weight4, 160,
"Availability of other idle cpus");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight5", CTLFLAG_RW,
&usched_dfly_weight5, 50,
"Memory attached to node");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight6", CTLFLAG_RW,
&usched_dfly_weight6, 150,
"Transfer weight Feat 0x04");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "weight7", CTLFLAG_RW,
&usched_dfly_weight7, -100,
"Transfer weight Feat 0x01");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "fast_resched", CTLFLAG_RW,
&usched_dfly_fast_resched, 0,
"Availability of other idle cpus");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "features", CTLFLAG_RW,
&usched_dfly_features, 0x8F,
"Allow pulls into empty queues");
SYSCTL_ADD_INT(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "swmask", CTLFLAG_RW,
&usched_dfly_swmask, ~PPQMASK,
"Queue mask to force thread switch");
#if 0
SYSCTL_ADD_PROC(&usched_dfly_sysctl_ctx,
SYSCTL_CHILDREN(usched_dfly_sysctl_tree),
OID_AUTO, "stick_to_level",
CTLTYPE_INT | CTLFLAG_RW,
NULL, sizeof usched_dfly_stick_to_level,
sysctl_usched_dfly_stick_to_level, "I",
"Stick a process to this level. See sysctl"
"paremter hw.cpu_topology.level_description");
#endif
}
lockmgr(&usched_dfly_config_lk, LK_RELEASE);
}
SYSINIT(uschedtd, SI_BOOT2_USCHED, SI_ORDER_SECOND,
usched_dfly_cpu_init, NULL);