#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>
#define MAXPRI 128
#define PRIMASK (MAXPRI - 1)
#define PRIBASE_REALTIME 0
#define PRIBASE_NORMAL MAXPRI
#define PRIBASE_IDLE (MAXPRI * 2)
#define PRIBASE_THREAD (MAXPRI * 3)
#define PRIBASE_NULL (MAXPRI * 4)
#define NQS 32
#define PPQ (MAXPRI / NQS)
#define PPQMASK (PPQ - 1)
#define NICEPPQ 2
#define ESTCPUPPQ 512
#define ESTCPUMAX (ESTCPUPPQ * NQS)
#define BATCHMAX (ESTCPUFREQ * 30)
#define PRIO_RANGE (PRIO_MAX - PRIO_MIN + 1)
#define ESTCPULIM(v) min((v), ESTCPUMAX)
TAILQ_HEAD(rq, lwp);
#define lwp_priority lwp_usdata.bsd4.priority
#define lwp_rqindex lwp_usdata.bsd4.rqindex
#define lwp_estcpu lwp_usdata.bsd4.estcpu
#define lwp_batch lwp_usdata.bsd4.batch
#define lwp_rqtype lwp_usdata.bsd4.rqtype
static void bsd4_acquire_curproc(struct lwp *lp);
static void bsd4_release_curproc(struct lwp *lp);
static void bsd4_select_curproc(globaldata_t gd);
static void bsd4_setrunqueue(struct lwp *lp);
static void bsd4_schedulerclock(struct lwp *lp, sysclock_t period,
sysclock_t cpstamp);
static void bsd4_recalculate_estcpu(struct lwp *lp);
static void bsd4_resetpriority(struct lwp *lp);
static void bsd4_forking(struct lwp *plp, struct lwp *lp);
static void bsd4_exiting(struct lwp *lp, struct proc *);
static void bsd4_uload_update(struct lwp *lp);
static void bsd4_yield(struct lwp *lp);
static void bsd4_need_user_resched_remote(void *dummy);
static int bsd4_batchy_looser_pri_test(struct lwp* lp);
static struct lwp *bsd4_chooseproc_locked_cache_coherent(struct lwp *chklp);
static void bsd4_kick_helper(struct lwp *lp);
static struct lwp *bsd4_chooseproc_locked(struct lwp *chklp);
static void bsd4_remrunqueue_locked(struct lwp *lp);
static void bsd4_setrunqueue_locked(struct lwp *lp);
static void bsd4_changedcpu(struct lwp *lp);
struct usched usched_bsd4 = {
{ NULL },
"bsd4", "Original DragonFly Scheduler",
NULL,
NULL,
bsd4_acquire_curproc,
bsd4_release_curproc,
bsd4_setrunqueue,
bsd4_schedulerclock,
bsd4_recalculate_estcpu,
bsd4_resetpriority,
bsd4_forking,
bsd4_exiting,
bsd4_uload_update,
NULL,
bsd4_yield,
bsd4_changedcpu
};
struct usched_bsd4_pcpu {
struct thread *helper_thread;
short rrcount;
short upri;
struct lwp *uschedcp;
struct lwp *old_uschedcp;
cpu_node_t *cpunode;
};
typedef struct usched_bsd4_pcpu *bsd4_pcpu_t;
static struct rq bsd4_queues[NQS];
static struct rq bsd4_rtqueues[NQS];
static struct rq bsd4_idqueues[NQS];
static u_int32_t bsd4_queuebits;
static u_int32_t bsd4_rtqueuebits;
static u_int32_t bsd4_idqueuebits;
static cpumask_t bsd4_curprocmask = CPUMASK_INITIALIZER_ALLONES;
static cpumask_t bsd4_rdyprocmask;
static int bsd4_runqcount;
static volatile int bsd4_scancpu;
static struct spinlock bsd4_spin;
static struct usched_bsd4_pcpu bsd4_pcpu[MAXCPU];
static struct sysctl_ctx_list usched_bsd4_sysctl_ctx;
static struct sysctl_oid *usched_bsd4_sysctl_tree;
SYSCTL_INT(_debug, OID_AUTO, bsd4_runqcount, CTLFLAG_RD,
&bsd4_runqcount, 0,
"Number of run queues");
static int usched_bsd4_debug = -1;
SYSCTL_INT(_debug, OID_AUTO, bsd4_scdebug, CTLFLAG_RW,
&usched_bsd4_debug, 0,
"Print debug information for this pid");
static int usched_bsd4_pid_debug = -1;
SYSCTL_INT(_debug, OID_AUTO, bsd4_pid_debug, CTLFLAG_RW,
&usched_bsd4_pid_debug, 0,
"Print KTR debug information for this pid");
static int usched_bsd4_smt = 0;
static int usched_bsd4_cache_coherent = 0;
static int usched_bsd4_upri_affinity = 16;
static int usched_bsd4_queue_checks = 5;
static int usched_bsd4_stick_to_level = 0;
static long usched_bsd4_kicks;
static int usched_bsd4_rrinterval = (ESTCPUFREQ + 9) / 10;
static int usched_bsd4_decay = 8;
static int usched_bsd4_batch_time = 10;
KTR_INFO_MASTER_EXTERN(usched);
#if !defined(KTR_USCHED_BSD4)
#define KTR_USCHED_BSD4 KTR_ALL
#endif
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_acquire_curproc_urw, 0,
"USCHED_BSD4(bsd4_acquire_curproc in user_reseched_wanted "
"after release: pid %d, cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_acquire_curproc_before_loop, 0,
"USCHED_BSD4(bsd4_acquire_curproc before loop: pid %d, cpuid %d, "
"curr_cpuid %d)",
pid_t pid, int cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_acquire_curproc_not, 0,
"USCHED_BSD4(bsd4_acquire_curproc couldn't acquire after "
"bsd4_setrunqueue: pid %d, cpuid %d, curr_lp pid %d, curr_cpuid %d)",
pid_t pid, int cpuid, pid_t curr_pid, int curr_cpuid);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_acquire_curproc_switch, 0,
"USCHED_BSD4(bsd4_acquire_curproc after lwkt_switch: pid %d, "
"cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_release_curproc, 0,
"USCHED_BSD4(bsd4_release_curproc before select: pid %d, "
"cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_select_curproc, 0,
"USCHED_BSD4(bsd4_release_curproc before select: pid %d, "
"cpuid %d, old_pid %d, old_cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, pid_t old_pid, int old_cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, batchy_test_false, 0,
"USCHED_BSD4(batchy_looser_pri_test false: pid %d, "
"cpuid %d, verify_mask %lu)",
pid_t pid, int cpuid, unsigned long mask);
KTR_INFO(KTR_USCHED_BSD4, usched, batchy_test_true, 0,
"USCHED_BSD4(batchy_looser_pri_test true: pid %d, "
"cpuid %d, verify_mask %lu)",
pid_t pid, int cpuid, unsigned long mask);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_setrunqueue_fc_smt, 0,
"USCHED_BSD4(bsd4_setrunqueue free cpus smt: pid %d, cpuid %d, "
"mask %lu, curr_cpuid %d)",
pid_t pid, int cpuid, unsigned long mask, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_setrunqueue_fc_non_smt, 0,
"USCHED_BSD4(bsd4_setrunqueue free cpus check non_smt: pid %d, "
"cpuid %d, mask %lu, curr_cpuid %d)",
pid_t pid, int cpuid, unsigned long mask, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_setrunqueue_rc, 0,
"USCHED_BSD4(bsd4_setrunqueue running cpus check: pid %d, "
"cpuid %d, mask %lu, curr_cpuid %d)",
pid_t pid, int cpuid, unsigned long mask, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_setrunqueue_found, 0,
"USCHED_BSD4(bsd4_setrunqueue found cpu: pid %d, cpuid %d, "
"mask %lu, found_cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, unsigned long mask, int found_cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_setrunqueue_not_found, 0,
"USCHED_BSD4(bsd4_setrunqueue not found cpu: pid %d, cpuid %d, "
"try_cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, int try_cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_setrunqueue_found_best_cpuid, 0,
"USCHED_BSD4(bsd4_setrunqueue found cpu: pid %d, cpuid %d, "
"mask %lu, found_cpuid %d, curr_cpuid %d)",
pid_t pid, int cpuid, unsigned long mask, int found_cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, bsd4_chooseproc, 0,
"USCHED_BSD4(chooseproc: pid %d, old_cpuid %d, curr_cpuid %d)",
pid_t pid, int old_cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, chooseproc_cc, 0,
"USCHED_BSD4(chooseproc_cc: pid %d, old_cpuid %d, curr_cpuid %d)",
pid_t pid, int old_cpuid, int curr);
KTR_INFO(KTR_USCHED_BSD4, usched, chooseproc_cc_not_good, 0,
"USCHED_BSD4(chooseproc_cc not good: pid %d, old_cpumask %lu, "
"sibling_mask %lu, curr_cpumask %lu)",
pid_t pid, unsigned long old_cpumask, unsigned long sibling_mask, unsigned long curr);
KTR_INFO(KTR_USCHED_BSD4, usched, chooseproc_cc_elected, 0,
"USCHED_BSD4(chooseproc_cc elected: pid %d, old_cpumask %lu, "
"sibling_mask %lu, curr_cpumask: %lu)",
pid_t pid, unsigned long old_cpumask, unsigned long sibling_mask, unsigned long curr);
KTR_INFO(KTR_USCHED_BSD4, usched, sched_thread_no_process, 0,
"USCHED_BSD4(sched_thread %d no process scheduled: pid %d, old_cpuid %d)",
int id, pid_t pid, int cpuid);
KTR_INFO(KTR_USCHED_BSD4, usched, sched_thread_process, 0,
"USCHED_BSD4(sched_thread %d process scheduled: pid %d, old_cpuid %d)",
int id, pid_t pid, int cpuid);
KTR_INFO(KTR_USCHED_BSD4, usched, sched_thread_no_process_found, 0,
"USCHED_BSD4(sched_thread %d no process found; tmpmask %lu)",
int id, unsigned long tmpmask);
static void
bsd4_rqinit(void *dummy)
{
int i;
spin_init(&bsd4_spin, "bsd4rq");
for (i = 0; i < NQS; i++) {
TAILQ_INIT(&bsd4_queues[i]);
TAILQ_INIT(&bsd4_rtqueues[i]);
TAILQ_INIT(&bsd4_idqueues[i]);
}
ATOMIC_CPUMASK_NANDBIT(bsd4_curprocmask, 0);
}
SYSINIT(runqueue, SI_BOOT2_USCHED, SI_ORDER_FIRST, bsd4_rqinit, NULL);
static void
bsd4_acquire_curproc(struct lwp *lp)
{
globaldata_t gd;
bsd4_pcpu_t dd;
thread_t td;
#if 0
struct lwp *olp;
#endif
td = lp->lwp_thread;
crit_enter_quick(td);
if (td->td_flags & TDF_TSLEEPQ)
tsleep_remove(td);
bsd4_recalculate_estcpu(lp);
if (user_resched_wanted()) {
clear_user_resched();
bsd4_release_curproc(lp);
KTR_COND_LOG(usched_bsd4_acquire_curproc_urw,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
mycpu->gd_cpuid);
}
gd = mycpu;
dd = &bsd4_pcpu[gd->gd_cpuid];
KTR_COND_LOG(usched_bsd4_acquire_curproc_before_loop,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
gd->gd_cpuid);
do {
lwkt_yield();
if (__predict_false(
CPUMASK_TESTBIT(lp->lwp_cpumask, gd->gd_cpuid) == 0)) {
bsd4_release_curproc(lp);
goto resched;
}
if (dd->uschedcp == lp) {
dd->upri = lp->lwp_priority;
} else if (dd->uschedcp == NULL) {
ATOMIC_CPUMASK_ORBIT(bsd4_curprocmask, gd->gd_cpuid);
dd->uschedcp = lp;
dd->upri = lp->lwp_priority;
} else if (dd->upri > lp->lwp_priority) {
dd->uschedcp = lp;
dd->upri = lp->lwp_priority;
} else {
resched:
lwkt_deschedule(lp->lwp_thread);
bsd4_setrunqueue(lp);
KTR_COND_LOG(usched_bsd4_acquire_curproc_not,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
dd->uschedcp->lwp_proc->p_pid,
gd->gd_cpuid);
lwkt_switch();
gd = mycpu;
dd = &bsd4_pcpu[gd->gd_cpuid];
KTR_COND_LOG(usched_bsd4_acquire_curproc_switch,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
gd->gd_cpuid);
}
} while (dd->uschedcp != lp);
crit_exit_quick(td);
KKASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0);
}
static void
bsd4_release_curproc(struct lwp *lp)
{
globaldata_t gd = mycpu;
bsd4_pcpu_t dd = &bsd4_pcpu[gd->gd_cpuid];
if (dd->uschedcp == lp) {
crit_enter();
KKASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0);
KTR_COND_LOG(usched_bsd4_release_curproc,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
gd->gd_cpuid);
dd->uschedcp = NULL;
dd->upri = PRIBASE_NULL;
ATOMIC_CPUMASK_NANDBIT(bsd4_curprocmask, gd->gd_cpuid);
dd->old_uschedcp = lp;
bsd4_select_curproc(gd);
crit_exit();
}
}
static
void
bsd4_select_curproc(globaldata_t gd)
{
bsd4_pcpu_t dd = &bsd4_pcpu[gd->gd_cpuid];
struct lwp *nlp;
int cpuid = gd->gd_cpuid;
crit_enter_gd(gd);
spin_lock(&bsd4_spin);
if(usched_bsd4_cache_coherent)
nlp = bsd4_chooseproc_locked_cache_coherent(dd->uschedcp);
else
nlp = bsd4_chooseproc_locked(dd->uschedcp);
if (nlp) {
KTR_COND_LOG(usched_bsd4_select_curproc,
nlp->lwp_proc->p_pid == usched_bsd4_pid_debug,
nlp->lwp_proc->p_pid,
nlp->lwp_thread->td_gd->gd_cpuid,
dd->old_uschedcp->lwp_proc->p_pid,
dd->old_uschedcp->lwp_thread->td_gd->gd_cpuid,
gd->gd_cpuid);
ATOMIC_CPUMASK_ORBIT(bsd4_curprocmask, cpuid);
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
dd->rrcount = 0;
spin_unlock(&bsd4_spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else {
spin_unlock(&bsd4_spin);
}
#if 0
} else if (bsd4_runqcount && CPUMASK_TESTBIT(bsd4_rdyprocmask, cpuid)) {
ATOMIC_CPUMASK_NANDBIT(bsd4_rdyprocmask, cpuid);
spin_unlock(&bsd4_spin);
lwkt_schedule(dd->helper_thread);
} else {
spin_unlock(&bsd4_spin);
}
#endif
crit_exit_gd(gd);
}
static int
bsd4_batchy_looser_pri_test(struct lwp* lp)
{
cpumask_t mask;
bsd4_pcpu_t other_dd;
int cpu;
mask = bsd4_curprocmask;
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, usched_global_cpumask);
while (CPUMASK_TESTNZERO(mask)) {
cpu = BSFCPUMASK(mask);
other_dd = &bsd4_pcpu[cpu];
if (other_dd->upri - lp->lwp_priority > usched_bsd4_upri_affinity * PPQ) {
KTR_COND_LOG(usched_batchy_test_false,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask));
return 0;
}
CPUMASK_NANDBIT(mask, cpu);
}
KTR_COND_LOG(usched_batchy_test_true,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask));
return 1;
}
static void
bsd4_setrunqueue(struct lwp *lp)
{
globaldata_t gd;
bsd4_pcpu_t dd;
int cpuid;
cpumask_t mask;
cpumask_t tmpmask;
crit_enter();
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);
gd = lp->lwp_thread->td_gd;
dd = &bsd4_pcpu[gd->gd_cpuid];
KKASSERT(dd->uschedcp != lp);
if ((lp->lwp_thread->td_flags & TDF_MIGRATING) == 0)
lwkt_giveaway(lp->lwp_thread);
spin_lock(&bsd4_spin);
bsd4_setrunqueue_locked(lp);
lp->lwp_rebal_ticks = sched_ticks;
++bsd4_scancpu;
if (usched_bsd4_smt) {
int best_cpuid = -1;
int min_prio = MAXPRI * MAXPRI;
int sibling;
cpuid = (bsd4_scancpu & 0xFFFF) % ncpus;
mask = bsd4_rdyprocmask;
CPUMASK_NANDMASK(mask, bsd4_curprocmask);
CPUMASK_ANDMASK(mask, lp->lwp_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, usched_global_cpumask);
KTR_COND_LOG(usched_bsd4_setrunqueue_fc_smt,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
mycpu->gd_cpuid);
while (CPUMASK_TESTNZERO(mask)) {
CPUMASK_ASSNBMASK(tmpmask, cpuid);
if (CPUMASK_TESTMASK(tmpmask, mask)) {
CPUMASK_ANDMASK(tmpmask, mask);
cpuid = BSFCPUMASK(tmpmask);
} else {
cpuid = BSFCPUMASK(mask);
}
gd = globaldata_find(cpuid);
dd = &bsd4_pcpu[cpuid];
if ((dd->upri & ~PPQMASK) >= (lp->lwp_priority & ~PPQMASK)) {
tmpmask = dd->cpunode->parent_node->members;
CPUMASK_NANDMASK(tmpmask, dd->cpunode->members);
CPUMASK_ANDMASK(tmpmask, mask);
if (CPUMASK_TESTNZERO(tmpmask)) {
KTR_COND_LOG(usched_bsd4_setrunqueue_found,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
cpuid,
mycpu->gd_cpuid);
goto found;
} else {
tmpmask =
dd->cpunode->parent_node->members;
CPUMASK_NANDMASK(tmpmask,
dd->cpunode->members);
sibling = BSFCPUMASK(tmpmask);
if (min_prio >
bsd4_pcpu[sibling].upri) {
min_prio =
bsd4_pcpu[sibling].upri;
best_cpuid = cpuid;
}
}
}
CPUMASK_NANDBIT(mask, cpuid);
}
if (best_cpuid != -1) {
cpuid = best_cpuid;
gd = globaldata_find(cpuid);
dd = &bsd4_pcpu[cpuid];
KTR_COND_LOG(usched_bsd4_setrunqueue_found_best_cpuid,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
cpuid,
mycpu->gd_cpuid);
goto found;
}
} else {
cpuid = (bsd4_scancpu & 0xFFFF) % ncpus;
mask = bsd4_rdyprocmask;
CPUMASK_NANDMASK(mask, bsd4_curprocmask);
CPUMASK_ANDMASK(mask, lp->lwp_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, usched_global_cpumask);
KTR_COND_LOG(usched_bsd4_setrunqueue_fc_non_smt,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
mycpu->gd_cpuid);
while (CPUMASK_TESTNZERO(mask)) {
CPUMASK_ASSNBMASK(tmpmask, cpuid);
if (CPUMASK_TESTMASK(tmpmask, mask)) {
CPUMASK_ANDMASK(tmpmask, mask);
cpuid = BSFCPUMASK(tmpmask);
} else {
cpuid = BSFCPUMASK(mask);
}
gd = globaldata_find(cpuid);
dd = &bsd4_pcpu[cpuid];
if ((dd->upri & ~PPQMASK) >=
(lp->lwp_priority & ~PPQMASK)) {
KTR_COND_LOG(usched_bsd4_setrunqueue_found,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
cpuid,
mycpu->gd_cpuid);
goto found;
}
CPUMASK_NANDBIT(mask, cpuid);
}
}
mask = bsd4_curprocmask;
CPUMASK_ANDMASK(mask, bsd4_rdyprocmask);
CPUMASK_ANDMASK(mask, lp->lwp_cpumask);
CPUMASK_ANDMASK(mask, smp_active_mask);
CPUMASK_ANDMASK(mask, usched_global_cpumask);
KTR_COND_LOG(usched_bsd4_setrunqueue_rc,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
mycpu->gd_cpuid);
while (CPUMASK_TESTNZERO(mask)) {
CPUMASK_ASSNBMASK(tmpmask, cpuid);
if (CPUMASK_TESTMASK(tmpmask, mask)) {
CPUMASK_ANDMASK(tmpmask, mask);
cpuid = BSFCPUMASK(tmpmask);
} else {
cpuid = BSFCPUMASK(mask);
}
gd = globaldata_find(cpuid);
dd = &bsd4_pcpu[cpuid];
if ((dd->upri & ~PPQMASK) > (lp->lwp_priority & ~PPQMASK)) {
KTR_COND_LOG(usched_bsd4_setrunqueue_found,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
(unsigned long)CPUMASK_LOWMASK(mask),
cpuid,
mycpu->gd_cpuid);
goto found;
}
CPUMASK_NANDBIT(mask, cpuid);
}
cpuid = (bsd4_scancpu & 0xFFFF) % ncpus;
if (CPUMASK_TESTBIT(lp->lwp_cpumask, cpuid) == 0)
cpuid = BSFCPUMASK(lp->lwp_cpumask);
else if (CPUMASK_TESTBIT(usched_global_cpumask, cpuid) == 0)
cpuid = 0;
gd = globaldata_find(cpuid);
dd = &bsd4_pcpu[cpuid];
KTR_COND_LOG(usched_bsd4_setrunqueue_not_found,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
cpuid,
mycpu->gd_cpuid);
found:
if (gd == mycpu) {
spin_unlock(&bsd4_spin);
if ((dd->upri & ~PPQMASK) > (lp->lwp_priority & ~PPQMASK)) {
if (dd->uschedcp == NULL) {
wakeup_mycpu(dd->helper_thread);
} else {
need_user_resched();
}
}
} else {
ATOMIC_CPUMASK_NANDBIT(bsd4_rdyprocmask, cpuid);
spin_unlock(&bsd4_spin);
if ((dd->upri & ~PPQMASK) > (lp->lwp_priority & ~PPQMASK))
lwkt_send_ipiq(gd, bsd4_need_user_resched_remote, NULL);
else
wakeup(dd->helper_thread);
}
crit_exit();
}
static
void
bsd4_schedulerclock(struct lwp *lp, sysclock_t period, sysclock_t cpstamp)
{
globaldata_t gd = mycpu;
bsd4_pcpu_t dd = &bsd4_pcpu[gd->gd_cpuid];
if (lp == NULL)
return;
if (++dd->rrcount >= usched_bsd4_rrinterval) {
dd->rrcount = 0;
need_user_resched();
}
lp->lwp_estcpu = ESTCPULIM(lp->lwp_estcpu + ESTCPUMAX / ESTCPUFREQ + 1);
KKASSERT(gd->gd_spinlocks == 0);
bsd4_resetpriority(lp);
}
static
void
bsd4_recalculate_estcpu(struct lwp *lp)
{
globaldata_t gd = mycpu;
sysclock_t cpbase;
sysclock_t ttlticks;
int estcpu;
int decay_factor;
cpbase = gd->gd_schedclock.time - gd->gd_schedclock.periodic;
if (lp->lwp_slptime > 1) {
lp->lwp_estcpu = lp->lwp_estcpu >> 1;
bsd4_resetpriority(lp);
lp->lwp_cpbase = cpbase;
lp->lwp_cpticks = 0;
lp->lwp_batch -= ESTCPUFREQ;
if (lp->lwp_batch < 0)
lp->lwp_batch = 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 == 0)
return;
updatepcpu(lp, lp->lwp_cpticks, ttlticks);
estcpu = (lp->lwp_cpticks * ESTCPUMAX) *
(bsd4_runqcount + ncpus) / (ncpus * ttlticks);
if (estcpu > ESTCPUMAX / 2) {
lp->lwp_batch += ttlticks;
if (lp->lwp_batch > BATCHMAX)
lp->lwp_batch = BATCHMAX;
} else {
lp->lwp_batch -= ttlticks;
if (lp->lwp_batch < 0)
lp->lwp_batch = 0;
}
if (usched_bsd4_debug == lp->lwp_proc->p_pid) {
kprintf("pid %d lwp %p estcpu %3d %3d bat %d "
"cp %ld/%ld",
lp->lwp_proc->p_pid, lp,
estcpu, lp->lwp_estcpu,
lp->lwp_batch,
lp->lwp_cpticks, ttlticks);
}
decay_factor = usched_bsd4_decay;
if (decay_factor < 1)
decay_factor = 1;
if (decay_factor > 1024)
decay_factor = 1024;
lp->lwp_estcpu = ESTCPULIM(
(lp->lwp_estcpu * decay_factor + estcpu) /
(decay_factor + 1));
if (usched_bsd4_debug == lp->lwp_proc->p_pid)
kprintf(" finalestcpu %d\n", lp->lwp_estcpu);
bsd4_resetpriority(lp);
lp->lwp_cpbase += ttlticks * gd->gd_schedclock.periodic;
lp->lwp_cpticks = 0;
}
}
static void
bsd4_resetpriority(struct lwp *lp)
{
bsd4_pcpu_t dd;
int newpriority;
u_short newrqtype;
int reschedcpu;
int checkpri;
int estcpu;
crit_enter();
spin_lock(&bsd4_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 * (lp->lwp_batch + BATCHMAX) /
(BATCHMAX * 2);
newpriority = (lp->lwp_proc->p_nice - PRIO_MIN) * PPQ / NICEPPQ;
newpriority += estcpu * PPQ / ESTCPUPPQ;
newpriority = newpriority * MAXPRI / (PRIO_RANGE * PPQ /
NICEPPQ + ESTCPUMAX * PPQ / ESTCPUPPQ);
newpriority = PRIBASE_NORMAL + (newpriority & PRIMASK);
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 & ~PPQMASK);
if ((lp->lwp_priority ^ newpriority) & ~PPQMASK) {
lp->lwp_priority = newpriority;
if (lp->lwp_mpflags & LWP_MP_ONRUNQ) {
bsd4_remrunqueue_locked(lp);
lp->lwp_rqtype = newrqtype;
lp->lwp_rqindex = (newpriority & PRIMASK) / PPQ;
bsd4_setrunqueue_locked(lp);
checkpri = 1;
} else {
lp->lwp_rqtype = newrqtype;
lp->lwp_rqindex = (newpriority & PRIMASK) / PPQ;
checkpri = 0;
}
reschedcpu = lp->lwp_thread->td_gd->gd_cpuid;
} else {
lp->lwp_priority = newpriority;
reschedcpu = -1;
checkpri = 1;
}
if (reschedcpu >= 0) {
dd = &bsd4_pcpu[reschedcpu];
if (CPUMASK_TESTBIT(bsd4_rdyprocmask, reschedcpu) &&
(checkpri == 0 ||
(dd->upri & ~PRIMASK) > (lp->lwp_priority & ~PRIMASK))) {
if (reschedcpu == mycpu->gd_cpuid) {
spin_unlock(&bsd4_spin);
need_user_resched();
} else {
spin_unlock(&bsd4_spin);
ATOMIC_CPUMASK_NANDBIT(bsd4_rdyprocmask,
reschedcpu);
lwkt_send_ipiq(lp->lwp_thread->td_gd,
bsd4_need_user_resched_remote,
NULL);
}
} else {
spin_unlock(&bsd4_spin);
}
} else {
spin_unlock(&bsd4_spin);
}
crit_exit();
}
static
void
bsd4_yield(struct lwp *lp)
{
#if 0
switch(lp->lwp_rqtype) {
case RTP_PRIO_NORMAL:
lp->lwp_estcpu = ESTCPULIM(lp->lwp_estcpu + ESTCPUINCR);
break;
default:
break;
}
#endif
need_user_resched();
}
static
void
bsd4_changedcpu(struct lwp *lp __unused)
{
}
static void
bsd4_forking(struct lwp *plp, struct lwp *lp)
{
lp->lwp_estcpu = ESTCPULIM(plp->lwp_estcpu + ESTCPUPPQ * 4);
lp->lwp_batch = BATCHMAX / 2;
plp->lwp_estcpu = ESTCPULIM(plp->lwp_estcpu + ESTCPUPPQ / 16);
}
static void
bsd4_exiting(struct lwp *lp, struct proc *child_proc)
{
}
static void
bsd4_uload_update(struct lwp *lp)
{
}
static
struct lwp *
bsd4_chooseproc_locked(struct lwp *chklp)
{
struct lwp *lp;
struct rq *q;
u_int32_t *which, *which2;
u_int32_t pri;
u_int32_t rtqbits;
u_int32_t tsqbits;
u_int32_t idqbits;
cpumask_t cpumask;
rtqbits = bsd4_rtqueuebits;
tsqbits = bsd4_queuebits;
idqbits = bsd4_idqueuebits;
cpumask = mycpu->gd_cpumask;
again:
if (rtqbits) {
pri = bsfl(rtqbits);
q = &bsd4_rtqueues[pri];
which = &bsd4_rtqueuebits;
which2 = &rtqbits;
} else if (tsqbits) {
pri = bsfl(tsqbits);
q = &bsd4_queues[pri];
which = &bsd4_queuebits;
which2 = &tsqbits;
} else if (idqbits) {
pri = bsfl(idqbits);
q = &bsd4_idqueues[pri];
which = &bsd4_idqueuebits;
which2 = &idqbits;
} else {
return NULL;
}
lp = TAILQ_FIRST(q);
KASSERT(lp, ("chooseproc: no lwp on busy queue"));
while (CPUMASK_TESTMASK(lp->lwp_cpumask, cpumask) == 0) {
lp = TAILQ_NEXT(lp, lwp_procq);
if (lp == NULL) {
*which2 &= ~(1 << pri);
goto again;
}
}
if (chklp) {
if (chklp->lwp_priority < lp->lwp_priority + PPQ)
return(NULL);
}
if (lp->lwp_thread->td_gd != mycpu &&
(chklp = TAILQ_NEXT(lp, lwp_procq)) != NULL
) {
if (chklp->lwp_thread->td_gd == mycpu) {
lp = chklp;
}
}
KTR_COND_LOG(usched_bsd4_chooseproc,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
mycpu->gd_cpuid);
TAILQ_REMOVE(q, lp, lwp_procq);
--bsd4_runqcount;
if (TAILQ_EMPTY(q))
*which &= ~(1 << pri);
KASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) != 0, ("not on runq6!"));
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
return lp;
}
static
struct lwp *
bsd4_chooseproc_locked_cache_coherent(struct lwp *chklp)
{
struct lwp *lp;
struct rq *q;
u_int32_t *which, *which2;
u_int32_t pri;
u_int32_t checks;
u_int32_t rtqbits;
u_int32_t tsqbits;
u_int32_t idqbits;
cpumask_t cpumask;
struct lwp * min_level_lwp = NULL;
struct rq *min_q = NULL;
cpumask_t siblings;
cpu_node_t* cpunode = NULL;
u_int32_t min_level = MAXCPU;
u_int32_t *min_which = NULL;
u_int32_t min_pri = 0;
u_int32_t level = 0;
rtqbits = bsd4_rtqueuebits;
tsqbits = bsd4_queuebits;
idqbits = bsd4_idqueuebits;
cpumask = mycpu->gd_cpumask;
cpunode = bsd4_pcpu[mycpu->gd_cpuid].cpunode;
level = usched_bsd4_stick_to_level;
while (level) {
cpunode = cpunode->parent_node;
level--;
}
siblings = cpunode->members;
checks = 0;
again:
if (rtqbits) {
pri = bsfl(rtqbits);
q = &bsd4_rtqueues[pri];
which = &bsd4_rtqueuebits;
which2 = &rtqbits;
} else if (tsqbits) {
pri = bsfl(tsqbits);
q = &bsd4_queues[pri];
which = &bsd4_queuebits;
which2 = &tsqbits;
} else if (idqbits) {
pri = bsfl(idqbits);
q = &bsd4_idqueues[pri];
which = &bsd4_idqueuebits;
which2 = &idqbits;
} else {
bsd4_kick_helper(min_level_lwp);
return NULL;
}
lp = TAILQ_FIRST(q);
KASSERT(lp, ("chooseproc: no lwp on busy queue"));
while (checks < usched_bsd4_queue_checks) {
if (CPUMASK_TESTMASK(lp->lwp_cpumask, cpumask) == 0 ||
(CPUMASK_TESTMASK(siblings,
lp->lwp_thread->td_gd->gd_cpumask) == 0 &&
(lp->lwp_rebal_ticks == sched_ticks ||
lp->lwp_rebal_ticks == (int)(sched_ticks - 1)) &&
bsd4_batchy_looser_pri_test(lp))) {
KTR_COND_LOG(usched_chooseproc_cc_not_good,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
(unsigned long)CPUMASK_LOWMASK(
lp->lwp_thread->td_gd->gd_cpumask),
(unsigned long)CPUMASK_LOWMASK(siblings),
(unsigned long)CPUMASK_LOWMASK(cpumask));
cpunode = bsd4_pcpu[lp->lwp_thread->td_gd->gd_cpuid].cpunode;
level = 0;
while (cpunode) {
if (CPUMASK_TESTMASK(cpunode->members,
cpumask)) {
break;
}
cpunode = cpunode->parent_node;
level++;
}
if (level < min_level ||
(level == min_level && min_level_lwp &&
lp->lwp_priority < min_level_lwp->lwp_priority)) {
bsd4_kick_helper(min_level_lwp);
min_level_lwp = lp;
min_level = level;
min_q = q;
min_which = which;
min_pri = pri;
} else {
bsd4_kick_helper(lp);
}
lp = TAILQ_NEXT(lp, lwp_procq);
if (lp == NULL) {
*which2 &= ~(1 << pri);
goto again;
}
} else {
KTR_COND_LOG(usched_chooseproc_cc_elected,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
(unsigned long)CPUMASK_LOWMASK(
lp->lwp_thread->td_gd->gd_cpumask),
(unsigned long)CPUMASK_LOWMASK(siblings),
(unsigned long)CPUMASK_LOWMASK(cpumask));
goto found;
}
++checks;
}
lp = min_level_lwp;
q = min_q;
which = min_which;
pri = min_pri;
KASSERT(lp, ("chooseproc: at least the first lp was good"));
found:
if (chklp) {
if (chklp->lwp_priority < lp->lwp_priority + PPQ) {
bsd4_kick_helper(lp);
return(NULL);
}
}
KTR_COND_LOG(usched_chooseproc_cc,
lp->lwp_proc->p_pid == usched_bsd4_pid_debug,
lp->lwp_proc->p_pid,
lp->lwp_thread->td_gd->gd_cpuid,
mycpu->gd_cpuid);
TAILQ_REMOVE(q, lp, lwp_procq);
--bsd4_runqcount;
if (TAILQ_EMPTY(q))
*which &= ~(1 << pri);
KASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) != 0, ("not on runq6!"));
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
return lp;
}
static
void
bsd4_kick_helper(struct lwp *lp)
{
globaldata_t gd;
bsd4_pcpu_t dd;
cpumask_t tmpmask;
if (lp == NULL)
return;
gd = lp->lwp_thread->td_gd;
dd = &bsd4_pcpu[gd->gd_cpuid];
tmpmask = smp_active_mask;
CPUMASK_ANDMASK(tmpmask, usched_global_cpumask);
CPUMASK_ANDMASK(tmpmask, bsd4_rdyprocmask);
CPUMASK_ANDMASK(tmpmask, gd->gd_cpumask);
if (CPUMASK_TESTZERO(tmpmask))
return;
++usched_bsd4_kicks;
ATOMIC_CPUMASK_NANDBIT(bsd4_rdyprocmask, gd->gd_cpuid);
if ((dd->upri & ~PPQMASK) > (lp->lwp_priority & ~PPQMASK)) {
lwkt_send_ipiq(gd, bsd4_need_user_resched_remote, NULL);
} else {
wakeup(dd->helper_thread);
}
}
static
void
bsd4_need_user_resched_remote(void *dummy)
{
globaldata_t gd = mycpu;
bsd4_pcpu_t dd = &bsd4_pcpu[gd->gd_cpuid];
need_user_resched();
wakeup_mycpu(dd->helper_thread);
}
static void
bsd4_remrunqueue_locked(struct lwp *lp)
{
struct rq *q;
u_int32_t *which;
u_int8_t pri;
KKASSERT(lp->lwp_mpflags & LWP_MP_ONRUNQ);
atomic_clear_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
--bsd4_runqcount;
KKASSERT(bsd4_runqcount >= 0);
pri = lp->lwp_rqindex;
switch(lp->lwp_rqtype) {
case RTP_PRIO_NORMAL:
q = &bsd4_queues[pri];
which = &bsd4_queuebits;
break;
case RTP_PRIO_REALTIME:
case RTP_PRIO_FIFO:
q = &bsd4_rtqueues[pri];
which = &bsd4_rtqueuebits;
break;
case RTP_PRIO_IDLE:
q = &bsd4_idqueues[pri];
which = &bsd4_idqueuebits;
break;
default:
panic("remrunqueue: invalid rtprio type");
}
TAILQ_REMOVE(q, lp, lwp_procq);
if (TAILQ_EMPTY(q)) {
KASSERT((*which & (1 << pri)) != 0,
("remrunqueue: remove from empty queue"));
*which &= ~(1 << pri);
}
}
static void
bsd4_setrunqueue_locked(struct lwp *lp)
{
struct rq *q;
u_int32_t *which;
int pri;
KKASSERT((lp->lwp_mpflags & LWP_MP_ONRUNQ) == 0);
atomic_set_int(&lp->lwp_mpflags, LWP_MP_ONRUNQ);
++bsd4_runqcount;
pri = lp->lwp_rqindex;
switch(lp->lwp_rqtype) {
case RTP_PRIO_NORMAL:
q = &bsd4_queues[pri];
which = &bsd4_queuebits;
break;
case RTP_PRIO_REALTIME:
case RTP_PRIO_FIFO:
q = &bsd4_rtqueues[pri];
which = &bsd4_rtqueuebits;
break;
case RTP_PRIO_IDLE:
q = &bsd4_idqueues[pri];
which = &bsd4_idqueuebits;
break;
default:
panic("remrunqueue: invalid rtprio type");
}
TAILQ_INSERT_TAIL(q, lp, lwp_procq);
*which |= 1 << pri;
}
static void
sched_thread(void *dummy)
{
globaldata_t gd;
bsd4_pcpu_t dd;
bsd4_pcpu_t tmpdd;
struct lwp *nlp;
cpumask_t mask;
int cpuid;
cpumask_t tmpmask;
int tmpid;
gd = mycpu;
cpuid = gd->gd_cpuid;
mask = gd->gd_cpumask;
dd = &bsd4_pcpu[cpuid];
lwkt_setpri_self(TDPRI_USER_SCHEDULER);
tsleep(dd->helper_thread, 0, "sched_thread_sleep", 0);
for (;;) {
crit_enter_gd(gd);
tsleep_interlock(dd->helper_thread, 0);
spin_lock(&bsd4_spin);
ATOMIC_CPUMASK_ORMASK(bsd4_rdyprocmask, mask);
clear_user_resched();
dd->rrcount = 0;
if (CPUMASK_TESTMASK(bsd4_curprocmask, mask) == 0) {
KKASSERT(dd->uschedcp == NULL);
if ((nlp = bsd4_chooseproc_locked(NULL)) != NULL) {
KTR_COND_LOG(usched_sched_thread_no_process,
nlp->lwp_proc->p_pid == usched_bsd4_pid_debug,
gd->gd_cpuid,
nlp->lwp_proc->p_pid,
nlp->lwp_thread->td_gd->gd_cpuid);
ATOMIC_CPUMASK_ORMASK(bsd4_curprocmask, mask);
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
dd->rrcount = 0;
spin_unlock(&bsd4_spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else {
spin_unlock(&bsd4_spin);
}
} else if (bsd4_runqcount) {
if ((nlp = bsd4_chooseproc_locked(dd->uschedcp)) != NULL) {
KTR_COND_LOG(usched_sched_thread_process,
nlp->lwp_proc->p_pid == usched_bsd4_pid_debug,
gd->gd_cpuid,
nlp->lwp_proc->p_pid,
nlp->lwp_thread->td_gd->gd_cpuid);
dd->upri = nlp->lwp_priority;
dd->uschedcp = nlp;
dd->rrcount = 0;
spin_unlock(&bsd4_spin);
lwkt_acquire(nlp->lwp_thread);
lwkt_schedule(nlp->lwp_thread);
} else {
tmpmask = bsd4_rdyprocmask;
CPUMASK_NANDMASK(tmpmask, bsd4_curprocmask);
CPUMASK_ANDMASK(tmpmask, smp_active_mask);
if (CPUMASK_TESTNZERO(tmpmask)) {
tmpid = BSFCPUMASK(tmpmask);
tmpdd = &bsd4_pcpu[tmpid];
ATOMIC_CPUMASK_NANDBIT(bsd4_rdyprocmask, tmpid);
spin_unlock(&bsd4_spin);
wakeup(tmpdd->helper_thread);
} else {
spin_unlock(&bsd4_spin);
}
KTR_LOG(usched_sched_thread_no_process_found,
gd->gd_cpuid, (unsigned long)CPUMASK_LOWMASK(tmpmask));
}
} else {
spin_unlock(&bsd4_spin);
}
crit_exit_gd(gd);
tsleep(dd->helper_thread, PINTERLOCKED, "schslp", 0);
}
}
static int
sysctl_usched_bsd4_stick_to_level(SYSCTL_HANDLER_ARGS)
{
int error, new_val;
new_val = usched_bsd4_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_bsd4_stick_to_level = new_val;
return (0);
}
static void
sched_thread_cpu_init(void)
{
int i;
int smt_not_supported = 0;
int cache_coherent_not_supported = 0;
if (bootverbose)
kprintf("Start usched_bsd4 helpers on cpus:\n");
sysctl_ctx_init(&usched_bsd4_sysctl_ctx);
usched_bsd4_sysctl_tree =
SYSCTL_ADD_NODE(&usched_bsd4_sysctl_ctx,
SYSCTL_STATIC_CHILDREN(_kern), OID_AUTO,
"usched_bsd4", CTLFLAG_RD, 0, "");
for (i = 0; i < ncpus; ++i) {
bsd4_pcpu_t dd = &bsd4_pcpu[i];
cpumask_t mask;
CPUMASK_ASSBIT(mask, i);
if (CPUMASK_TESTMASK(mask, smp_active_mask) == 0)
continue;
dd->cpunode = get_cpu_node_by_cpuid(i);
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(sched_thread, NULL, &dd->helper_thread, NULL,
0, i, "usched %d", i);
if (i)
ATOMIC_CPUMASK_NANDMASK(bsd4_curprocmask, mask);
ATOMIC_CPUMASK_ORMASK(bsd4_rdyprocmask, mask);
dd->upri = PRIBASE_NULL;
}
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "rrinterval", CTLFLAG_RW,
&usched_bsd4_rrinterval, 0, "");
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "decay", CTLFLAG_RW,
&usched_bsd4_decay, 0, "Extra decay when not running");
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "batch_time", CTLFLAG_RW,
&usched_bsd4_batch_time, 0, "Min batch counter value");
SYSCTL_ADD_LONG(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "kicks", CTLFLAG_RW,
&usched_bsd4_kicks, "Number of kickstarts");
if (smt_not_supported) {
usched_bsd4_smt = 0;
SYSCTL_ADD_STRING(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "smt", CTLFLAG_RD,
"NOT SUPPORTED", 0, "SMT NOT SUPPORTED");
} else {
usched_bsd4_smt = 1;
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "smt", CTLFLAG_RW,
&usched_bsd4_smt, 0, "Enable SMT scheduling");
}
if (cache_coherent_not_supported) {
usched_bsd4_cache_coherent = 0;
SYSCTL_ADD_STRING(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "cache_coherent", CTLFLAG_RD,
"NOT SUPPORTED", 0,
"Cache coherence NOT SUPPORTED");
} else {
usched_bsd4_cache_coherent = 1;
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "cache_coherent", CTLFLAG_RW,
&usched_bsd4_cache_coherent, 0,
"Enable/Disable cache coherent scheduling");
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "upri_affinity", CTLFLAG_RW,
&usched_bsd4_upri_affinity, 1,
"Number of PPQs in user priority check");
SYSCTL_ADD_INT(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "queue_checks", CTLFLAG_RW,
&usched_bsd4_queue_checks, 5,
"LWPs to check from a queue before giving up");
SYSCTL_ADD_PROC(&usched_bsd4_sysctl_ctx,
SYSCTL_CHILDREN(usched_bsd4_sysctl_tree),
OID_AUTO, "stick_to_level",
CTLTYPE_INT | CTLFLAG_RW,
NULL, sizeof usched_bsd4_stick_to_level,
sysctl_usched_bsd4_stick_to_level, "I",
"Stick a process to this level. See sysctl"
"paremter hw.cpu_topology.level_description");
}
}
SYSINIT(uschedtd, SI_BOOT2_USCHED, SI_ORDER_SECOND,
sched_thread_cpu_init, NULL);