mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-30 08:19:09 +00:00
Implement 'domainset', a cpuset based NUMA policy mechanism. This allows
userspace to control NUMA policy administratively and programmatically. Implement domainset based iterators in the page layer. Remove the now legacy numa_* syscalls. Cleanup some header polution created by having seq.h in proc.h. Reviewed by: markj, kib Discussed with: alc Tested by: pho Sponsored by: Netflix, Dell/EMC Isilon Differential Revision: https://reviews.freebsd.org/D13403
This commit is contained in:
parent
fe8be58826
commit
3f289c3fcf
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=327895
@ -398,6 +398,8 @@ FBSD_1.5 {
|
||||
mknodat;
|
||||
stat;
|
||||
statfs;
|
||||
cpuset_getdomain;
|
||||
cpuset_setdomain;
|
||||
};
|
||||
|
||||
FBSDprivate_1.0 {
|
||||
@ -1022,4 +1024,8 @@ FBSDprivate_1.0 {
|
||||
gssd_syscall;
|
||||
__libc_interposing_slot;
|
||||
__libc_sigwait;
|
||||
_cpuset_getdomain;
|
||||
__sys_cpuset_getdomain;
|
||||
_cpuset_setdomain;
|
||||
__sys_cpuset_setdomain;
|
||||
};
|
||||
|
@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <machine/machdep.h>
|
||||
|
@ -3016,6 +3016,24 @@ freebsd32_cpuset_setaffinity(struct thread *td,
|
||||
PAIR32TO64(id_t,uap->id), uap->cpusetsize, uap->mask));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_cpuset_getdomain(struct thread *td,
|
||||
struct freebsd32_cpuset_getdomain_args *uap)
|
||||
{
|
||||
|
||||
return (kern_cpuset_getdomain(td, uap->level, uap->which,
|
||||
PAIR32TO64(id_t,uap->id), uap->domainsetsize, uap->mask, uap->policy));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_cpuset_setdomain(struct thread *td,
|
||||
struct freebsd32_cpuset_setdomain_args *uap)
|
||||
{
|
||||
|
||||
return (kern_cpuset_setdomain(td, uap->level, uap->which,
|
||||
PAIR32TO64(id_t,uap->id), uap->domainsetsize, uap->mask, uap->policy));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_nmount(struct thread *td,
|
||||
struct freebsd32_nmount_args /* {
|
||||
|
@ -1086,12 +1086,8 @@
|
||||
547 AUE_FUTIMESAT STD { int freebsd32_utimensat(int fd, \
|
||||
char *path, \
|
||||
struct timespec *times, int flag); }
|
||||
548 AUE_NULL NOPROTO { int numa_getaffinity(cpuwhich_t which, \
|
||||
id_t id, \
|
||||
struct vm_domain_policy *policy); }
|
||||
549 AUE_NULL NOPROTO { int numa_setaffinity(cpuwhich_t which, \
|
||||
id_t id, \
|
||||
const struct vm_domain_policy *policy); }
|
||||
548 AUE_NULL UNIMPL numa_getaffinity
|
||||
549 AUE_NULL UNIMPL numa_setaffinity
|
||||
550 AUE_FSYNC NOPROTO { int fdatasync(int fd); }
|
||||
551 AUE_FSTAT STD { int freebsd32_fstat(int fd, \
|
||||
struct stat32 *ub); }
|
||||
@ -1119,4 +1115,13 @@
|
||||
struct kevent32 *eventlist, \
|
||||
int nevents, \
|
||||
const struct timespec32 *timeout); }
|
||||
561 AUE_NULL STD { int freebsd32_cpuset_getdomain(cpulevel_t level, \
|
||||
cpuwhich_t which, uint32_t id1, uint32_t id2, \
|
||||
size_t domainsetsize, domainset_t *mask, \
|
||||
int *policy); }
|
||||
562 AUE_NULL STD { int freebsd32_cpuset_setdomain(cpulevel_t level, \
|
||||
cpuwhich_t which, uint32_t id1, uint32_t id2, \
|
||||
size_t domainsetsize, domainset_t *mask, \
|
||||
int policy); }
|
||||
|
||||
; vim: syntax=off
|
||||
|
@ -3787,7 +3787,6 @@ kern/kern_module.c standard
|
||||
kern/kern_mtxpool.c standard
|
||||
kern/kern_mutex.c standard
|
||||
kern/kern_ntptime.c standard
|
||||
kern/kern_numa.c standard
|
||||
kern/kern_osd.c standard
|
||||
kern/kern_physio.c standard
|
||||
kern/kern_pmc.c standard
|
||||
@ -4837,7 +4836,7 @@ vm/swap_pager.c standard
|
||||
vm/uma_core.c standard
|
||||
vm/uma_dbg.c standard
|
||||
vm/memguard.c optional DEBUG_MEMGUARD
|
||||
vm/vm_domain.c standard
|
||||
vm/vm_domainset.c standard
|
||||
vm/vm_fault.c standard
|
||||
vm/vm_glue.c standard
|
||||
vm/vm_init.c standard
|
||||
|
@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <machine/kdb.h>
|
||||
#include <machine/pcb.h>
|
||||
|
@ -89,7 +89,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_domain.h>
|
||||
#include <sys/copyright.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
@ -497,10 +496,7 @@ proc0_init(void *dummy __unused)
|
||||
td->td_flags = TDF_INMEM;
|
||||
td->td_pflags = TDP_KTHREAD;
|
||||
td->td_cpuset = cpuset_thread0();
|
||||
vm_domain_policy_init(&td->td_vm_dom_policy);
|
||||
vm_domain_policy_set(&td->td_vm_dom_policy, VM_POLICY_NONE, -1);
|
||||
vm_domain_policy_init(&p->p_vm_dom_policy);
|
||||
vm_domain_policy_set(&p->p_vm_dom_policy, VM_POLICY_NONE, -1);
|
||||
td->td_domain.dr_policy = td->td_cpuset->cs_domain;
|
||||
prison0_init();
|
||||
p->p_peers = 0;
|
||||
p->p_leader = p;
|
||||
|
@ -599,8 +599,8 @@ struct sysent sysent[] = {
|
||||
{ AS(ppoll_args), (sy_call_t *)sys_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 545 = ppoll */
|
||||
{ AS(futimens_args), (sy_call_t *)sys_futimens, AUE_FUTIMES, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 546 = futimens */
|
||||
{ AS(utimensat_args), (sy_call_t *)sys_utimensat, AUE_FUTIMESAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 547 = utimensat */
|
||||
{ AS(numa_getaffinity_args), (sy_call_t *)sys_numa_getaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 548 = numa_getaffinity */
|
||||
{ AS(numa_setaffinity_args), (sy_call_t *)sys_numa_setaffinity, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 549 = numa_setaffinity */
|
||||
{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 548 = numa_getaffinity */
|
||||
{ 0, (sy_call_t *)nosys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT }, /* 549 = numa_setaffinity */
|
||||
{ AS(fdatasync_args), (sy_call_t *)sys_fdatasync, AUE_FSYNC, NULL, 0, 0, 0, SY_THR_STATIC }, /* 550 = fdatasync */
|
||||
{ AS(fstat_args), (sy_call_t *)sys_fstat, AUE_FSTAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 551 = fstat */
|
||||
{ AS(fstatat_args), (sy_call_t *)sys_fstatat, AUE_FSTATAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 552 = fstatat */
|
||||
@ -612,4 +612,6 @@ struct sysent sysent[] = {
|
||||
{ AS(fhstatfs_args), (sy_call_t *)sys_fhstatfs, AUE_FHSTATFS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 558 = fhstatfs */
|
||||
{ AS(mknodat_args), (sy_call_t *)sys_mknodat, AUE_MKNODAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 559 = mknodat */
|
||||
{ AS(kevent_args), (sy_call_t *)sys_kevent, AUE_KEVENT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC }, /* 560 = kevent */
|
||||
{ AS(cpuset_getdomain_args), (sy_call_t *)sys_cpuset_getdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 561 = cpuset_getdomain */
|
||||
{ AS(cpuset_setdomain_args), (sy_call_t *)sys_cpuset_setdomain, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 562 = cpuset_setdomain */
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -88,7 +88,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/uma.h>
|
||||
#include <vm/vm_domain.h>
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
#include <sys/dtrace_bsd.h>
|
||||
@ -931,10 +930,6 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
|
||||
#ifdef MAC
|
||||
mac_proc_destroy(p);
|
||||
#endif
|
||||
/*
|
||||
* Free any domain policy that's still hiding around.
|
||||
*/
|
||||
vm_domain_policy_cleanup(&p->p_vm_dom_policy);
|
||||
|
||||
KASSERT(FIRST_THREAD_IN_PROC(p),
|
||||
("proc_reap: no residual thread!"));
|
||||
|
@ -83,7 +83,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/uma.h>
|
||||
#include <vm/vm_domain.h>
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
#include <sys/dtrace_bsd.h>
|
||||
@ -512,14 +511,6 @@ do_fork(struct thread *td, struct fork_req *fr, struct proc *p2, struct thread *
|
||||
if (p1->p_flag & P_PROFIL)
|
||||
startprofclock(p2);
|
||||
|
||||
/*
|
||||
* Whilst the proc lock is held, copy the VM domain data out
|
||||
* using the VM domain method.
|
||||
*/
|
||||
vm_domain_policy_init(&p2->p_vm_dom_policy);
|
||||
vm_domain_policy_localcopy(&p2->p_vm_dom_policy,
|
||||
&p1->p_vm_dom_policy);
|
||||
|
||||
if (fr->fr_flags & RFSIGSHARE) {
|
||||
p2->p_sigacts = sigacts_hold(p1->p_sigacts);
|
||||
} else {
|
||||
|
@ -1,169 +0,0 @@
|
||||
/*-
|
||||
* Copyright (c) 2015, Adrian Chadd <adrian@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/jail.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/priv.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/refcount.h>
|
||||
#include <sys/sched.h>
|
||||
#include <sys/smp.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/sx.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/libkern.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/interrupt.h>
|
||||
|
||||
#include <vm/uma.h>
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/vm_domain.h>
|
||||
|
||||
int
|
||||
sys_numa_setaffinity(struct thread *td, struct numa_setaffinity_args *uap)
|
||||
{
|
||||
int error;
|
||||
struct vm_domain_policy vp;
|
||||
struct thread *ttd;
|
||||
struct proc *p;
|
||||
struct cpuset *set;
|
||||
|
||||
set = NULL;
|
||||
p = NULL;
|
||||
|
||||
/*
|
||||
* Copy in just the policy information into the policy
|
||||
* struct. Userland only supplies vm_domain_policy_entry.
|
||||
*/
|
||||
error = copyin(uap->policy, &vp.p, sizeof(vp.p));
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Ensure the seq number is zero - otherwise seq.h
|
||||
* may get very confused.
|
||||
*/
|
||||
vp.seq = 0;
|
||||
|
||||
/*
|
||||
* Validate policy.
|
||||
*/
|
||||
if (vm_domain_policy_validate(&vp) != 0) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go find the desired proc/tid for this operation.
|
||||
*/
|
||||
error = cpuset_which(uap->which, uap->id, &p,
|
||||
&ttd, &set);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* Only handle CPU_WHICH_TID and CPU_WHICH_PID */
|
||||
/*
|
||||
* XXX if cpuset_which is called with WHICH_CPUSET and NULL cpuset,
|
||||
* it'll return ESRCH. We should just return EINVAL.
|
||||
*/
|
||||
switch (uap->which) {
|
||||
case CPU_WHICH_TID:
|
||||
vm_domain_policy_copy(&ttd->td_vm_dom_policy, &vp);
|
||||
break;
|
||||
case CPU_WHICH_PID:
|
||||
vm_domain_policy_copy(&p->p_vm_dom_policy, &vp);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
PROC_UNLOCK(p);
|
||||
out:
|
||||
if (set)
|
||||
cpuset_rel(set);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
sys_numa_getaffinity(struct thread *td, struct numa_getaffinity_args *uap)
|
||||
{
|
||||
int error;
|
||||
struct vm_domain_policy vp;
|
||||
struct thread *ttd;
|
||||
struct proc *p;
|
||||
struct cpuset *set;
|
||||
|
||||
set = NULL;
|
||||
p = NULL;
|
||||
|
||||
error = cpuset_which(uap->which, uap->id, &p,
|
||||
&ttd, &set);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
/* Only handle CPU_WHICH_TID and CPU_WHICH_PID */
|
||||
/*
|
||||
* XXX if cpuset_which is called with WHICH_CPUSET and NULL cpuset,
|
||||
* it'll return ESRCH. We should just return EINVAL.
|
||||
*/
|
||||
switch (uap->which) {
|
||||
case CPU_WHICH_TID:
|
||||
vm_domain_policy_localcopy(&vp, &ttd->td_vm_dom_policy);
|
||||
break;
|
||||
case CPU_WHICH_PID:
|
||||
vm_domain_policy_localcopy(&vp, &p->p_vm_dom_policy);
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
if (p)
|
||||
PROC_UNLOCK(p);
|
||||
/*
|
||||
* Copy out only the vm_domain_policy_entry part.
|
||||
*/
|
||||
if (error == 0)
|
||||
error = copyout(&vp.p, uap->policy, sizeof(vp.p));
|
||||
out:
|
||||
if (set)
|
||||
cpuset_rel(set);
|
||||
return (error);
|
||||
}
|
@ -57,8 +57,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/umtx.h>
|
||||
#include <sys/limits.h>
|
||||
|
||||
#include <vm/vm_domain.h>
|
||||
|
||||
#include <machine/frame.h>
|
||||
|
||||
#include <security/audit/audit.h>
|
||||
@ -260,12 +258,6 @@ thread_create(struct thread *td, struct rtprio *rtp,
|
||||
if (p->p_ptevents & PTRACE_LWP)
|
||||
newtd->td_dbgflags |= TDB_BORN;
|
||||
|
||||
/*
|
||||
* Copy the existing thread VM policy into the new thread.
|
||||
*/
|
||||
vm_domain_policy_localcopy(&newtd->td_vm_dom_policy,
|
||||
&td->td_vm_dom_policy);
|
||||
|
||||
PROC_UNLOCK(p);
|
||||
|
||||
tidhash_add(newtd);
|
||||
|
@ -64,7 +64,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_extern.h>
|
||||
#include <vm/uma.h>
|
||||
#include <vm/vm_domain.h>
|
||||
#include <sys/eventhandler.h>
|
||||
|
||||
/*
|
||||
@ -78,13 +77,13 @@ __FBSDID("$FreeBSD$");
|
||||
* structures.
|
||||
*/
|
||||
#ifdef __amd64__
|
||||
_Static_assert(offsetof(struct thread, td_flags) == 0xf4,
|
||||
_Static_assert(offsetof(struct thread, td_flags) == 0xfc,
|
||||
"struct thread KBI td_flags");
|
||||
_Static_assert(offsetof(struct thread, td_pflags) == 0xfc,
|
||||
_Static_assert(offsetof(struct thread, td_pflags) == 0x104,
|
||||
"struct thread KBI td_pflags");
|
||||
_Static_assert(offsetof(struct thread, td_frame) == 0x460,
|
||||
_Static_assert(offsetof(struct thread, td_frame) == 0x468,
|
||||
"struct thread KBI td_frame");
|
||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x508,
|
||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x510,
|
||||
"struct thread KBI td_emuldata");
|
||||
_Static_assert(offsetof(struct proc, p_flag) == 0xb0,
|
||||
"struct proc KBI p_flag");
|
||||
@ -98,13 +97,13 @@ _Static_assert(offsetof(struct proc, p_emuldata) == 0x4b8,
|
||||
"struct proc KBI p_emuldata");
|
||||
#endif
|
||||
#ifdef __i386__
|
||||
_Static_assert(offsetof(struct thread, td_flags) == 0x9c,
|
||||
_Static_assert(offsetof(struct thread, td_flags) == 0x98,
|
||||
"struct thread KBI td_flags");
|
||||
_Static_assert(offsetof(struct thread, td_pflags) == 0xa4,
|
||||
_Static_assert(offsetof(struct thread, td_pflags) == 0xa0,
|
||||
"struct thread KBI td_pflags");
|
||||
_Static_assert(offsetof(struct thread, td_frame) == 0x2ec,
|
||||
_Static_assert(offsetof(struct thread, td_frame) == 0x2e4,
|
||||
"struct thread KBI td_frame");
|
||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x338,
|
||||
_Static_assert(offsetof(struct thread, td_emuldata) == 0x330,
|
||||
"struct thread KBI td_emuldata");
|
||||
_Static_assert(offsetof(struct proc, p_flag) == 0x68,
|
||||
"struct proc KBI p_flag");
|
||||
@ -413,7 +412,6 @@ thread_alloc(int pages)
|
||||
return (NULL);
|
||||
}
|
||||
cpu_thread_alloc(td);
|
||||
vm_domain_policy_init(&td->td_vm_dom_policy);
|
||||
return (td);
|
||||
}
|
||||
|
||||
@ -443,7 +441,6 @@ thread_free(struct thread *td)
|
||||
cpu_thread_free(td);
|
||||
if (td->td_kstack != 0)
|
||||
vm_thread_dispose(td);
|
||||
vm_domain_policy_cleanup(&td->td_vm_dom_policy);
|
||||
callout_drain(&td->td_slpcallout);
|
||||
uma_zfree(thread_zone, td);
|
||||
}
|
||||
|
@ -139,6 +139,7 @@ sed -e '
|
||||
printf "#include <sys/signal.h>\n" > sysarg
|
||||
printf "#include <sys/acl.h>\n" > sysarg
|
||||
printf "#include <sys/cpuset.h>\n" > sysarg
|
||||
printf "#include <sys/domainset.h>\n" > sysarg
|
||||
printf "#include <sys/_ffcounter.h>\n" > sysarg
|
||||
printf "#include <sys/_semaphore.h>\n" > sysarg
|
||||
printf "#include <sys/ucontext.h>\n" > sysarg
|
||||
|
@ -781,6 +781,7 @@ sched_fork_thread(struct thread *td, struct thread *childtd)
|
||||
childtd->td_lastcpu = NOCPU;
|
||||
childtd->td_lock = &sched_lock;
|
||||
childtd->td_cpuset = cpuset_ref(td->td_cpuset);
|
||||
childtd->td_domain.dr_policy = td->td_cpuset->cs_domain;
|
||||
childtd->td_priority = childtd->td_base_pri;
|
||||
ts = td_get_sched(childtd);
|
||||
bzero(ts, sizeof(*ts));
|
||||
|
@ -2131,6 +2131,7 @@ sched_fork_thread(struct thread *td, struct thread *child)
|
||||
child->td_lastcpu = NOCPU;
|
||||
child->td_lock = TDQ_LOCKPTR(tdq);
|
||||
child->td_cpuset = cpuset_ref(td->td_cpuset);
|
||||
child->td_domain.dr_policy = td->td_cpuset->cs_domain;
|
||||
ts2->ts_cpu = ts->ts_cpu;
|
||||
ts2->ts_flags = 0;
|
||||
/*
|
||||
|
@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sbuf.h>
|
||||
|
@ -997,12 +997,8 @@
|
||||
547 AUE_FUTIMESAT STD { int utimensat(int fd, \
|
||||
char *path, \
|
||||
struct timespec *times, int flag); }
|
||||
548 AUE_NULL STD { int numa_getaffinity(cpuwhich_t which, \
|
||||
id_t id, \
|
||||
struct vm_domain_policy_entry *policy); }
|
||||
549 AUE_NULL STD { int numa_setaffinity(cpuwhich_t which, \
|
||||
id_t id, const struct \
|
||||
vm_domain_policy_entry *policy); }
|
||||
548 AUE_NULL UNIMPL numa_getaffinity
|
||||
549 AUE_NULL UNIMPL numa_setaffinity
|
||||
550 AUE_FSYNC STD { int fdatasync(int fd); }
|
||||
551 AUE_FSTAT STD { int fstat(int fd, struct stat *sb); }
|
||||
552 AUE_FSTATAT STD { int fstatat(int fd, char *path, \
|
||||
@ -1023,6 +1019,14 @@
|
||||
struct kevent *changelist, int nchanges, \
|
||||
struct kevent *eventlist, int nevents, \
|
||||
const struct timespec *timeout); }
|
||||
561 AUE_NULL STD { int cpuset_getdomain(cpulevel_t level, \
|
||||
cpuwhich_t which, id_t id, \
|
||||
size_t domainsetsize, domainset_t *mask, \
|
||||
int *policy); }
|
||||
562 AUE_NULL STD { int cpuset_setdomain(cpulevel_t level, \
|
||||
cpuwhich_t which, id_t id, \
|
||||
size_t domainsetsize, domainset_t *mask, \
|
||||
int policy); }
|
||||
|
||||
; Please copy any additions and changes to the following compatability tables:
|
||||
; sys/compat/freebsd32/syscalls.master
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <netinet/ip_fw.h> /* flow_id */
|
||||
#include <netinet/ip_dummynet.h>
|
||||
|
||||
#include <sys/lock.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/rwlock.h>
|
||||
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef __SYS_VM_DOMAIN_H__
|
||||
#define __SYS_VM_DOMAIN_H__
|
||||
|
||||
#include <sys/seq.h>
|
||||
|
||||
typedef enum {
|
||||
VM_POLICY_NONE,
|
||||
VM_POLICY_ROUND_ROBIN,
|
||||
VM_POLICY_FIXED_DOMAIN,
|
||||
VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN,
|
||||
VM_POLICY_FIRST_TOUCH,
|
||||
VM_POLICY_FIRST_TOUCH_ROUND_ROBIN,
|
||||
VM_POLICY_MAX
|
||||
} vm_domain_policy_type_t;
|
||||
|
||||
struct vm_domain_policy_entry {
|
||||
vm_domain_policy_type_t policy;
|
||||
int domain;
|
||||
};
|
||||
|
||||
struct vm_domain_policy {
|
||||
seq_t seq;
|
||||
struct vm_domain_policy_entry p;
|
||||
};
|
||||
|
||||
#define VM_DOMAIN_POLICY_STATIC_INITIALISER(vt, vd) \
|
||||
{ .seq = 0, \
|
||||
.p.policy = vt, \
|
||||
.p.domain = vd }
|
||||
|
||||
#endif /* __SYS_VM_DOMAIN_H__ */
|
@ -112,6 +112,7 @@ LIST_HEAD(setlist, cpuset);
|
||||
*/
|
||||
struct cpuset {
|
||||
cpuset_t cs_mask; /* bitmask of valid cpus. */
|
||||
struct domainset *cs_domain; /* (c) NUMA policy. */
|
||||
volatile u_int cs_ref; /* (a) Reference count. */
|
||||
int cs_flags; /* (s) Flags from below. */
|
||||
cpusetid_t cs_id; /* (s) Id or INVALID. */
|
||||
|
@ -62,11 +62,18 @@
|
||||
#include <sys/time.h> /* For structs itimerval, timeval. */
|
||||
#else
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/systm.h>
|
||||
#endif
|
||||
#include <sys/ucontext.h>
|
||||
#include <sys/ucred.h>
|
||||
#include <sys/_vm_domain.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/domainset.h>
|
||||
|
||||
#include <machine/proc.h> /* Machine-dependent proc substruct. */
|
||||
#ifdef _KERNEL
|
||||
#include <machine/cpu.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* One structure allocated per session.
|
||||
@ -179,6 +186,7 @@ struct procdesc;
|
||||
struct racct;
|
||||
struct sbuf;
|
||||
struct sleepqueue;
|
||||
struct socket;
|
||||
struct syscall_args;
|
||||
struct td_sched;
|
||||
struct thread;
|
||||
@ -222,12 +230,12 @@ struct thread {
|
||||
TAILQ_ENTRY(thread) td_lockq; /* (t) Lock queue. */
|
||||
LIST_ENTRY(thread) td_hash; /* (d) Hash chain. */
|
||||
struct cpuset *td_cpuset; /* (t) CPU affinity mask. */
|
||||
struct domainset_ref td_domain; /* (a) NUMA policy */
|
||||
struct seltd *td_sel; /* Select queue/channel. */
|
||||
struct sleepqueue *td_sleepqueue; /* (k) Associated sleep queue. */
|
||||
struct turnstile *td_turnstile; /* (k) Associated turnstile. */
|
||||
struct rl_q_entry *td_rlqe; /* (k) Associated range lock entry. */
|
||||
struct umtx_q *td_umtxq; /* (c?) Link for when we're blocked. */
|
||||
struct vm_domain_policy td_vm_dom_policy; /* (c) current numa domain policy */
|
||||
lwpid_t td_tid; /* (b) Thread ID. */
|
||||
sigqueue_t td_sigqueue; /* (c) Sigs arrived, not delivered. */
|
||||
#define td_siglist td_sigqueue.sq_signals
|
||||
@ -286,7 +294,6 @@ struct thread {
|
||||
pid_t td_dbg_forked; /* (c) Child pid for debugger. */
|
||||
u_int td_vp_reserv; /* (k) Count of reserved vnodes. */
|
||||
int td_no_sleeping; /* (k) Sleeping disabled count. */
|
||||
int td_dom_rr_idx; /* (k) RR Numa domain selection. */
|
||||
void *td_su; /* (k) FFS SU private */
|
||||
sbintime_t td_sleeptimo; /* (t) Sleep timeout. */
|
||||
int td_rtcgen; /* (s) rtc_generation of abs. sleep */
|
||||
@ -655,7 +662,6 @@ struct proc {
|
||||
uint64_t p_prev_runtime; /* (c) Resource usage accounting. */
|
||||
struct racct *p_racct; /* (b) Resource accounting. */
|
||||
int p_throttled; /* (c) Flag for racct pcpu throttling */
|
||||
struct vm_domain_policy p_vm_dom_policy; /* (c) process default VM domain, or -1 */
|
||||
/*
|
||||
* An orphan is the child that has beed re-parented to the
|
||||
* debugger as a result of attaching to it. Need to keep
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <sys/mac.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/_cpuset.h>
|
||||
#include <sys/_domainset.h>
|
||||
|
||||
struct file;
|
||||
struct filecaps;
|
||||
@ -96,6 +97,12 @@ int kern_cpuset_getaffinity(struct thread *td, cpulevel_t level,
|
||||
int kern_cpuset_setaffinity(struct thread *td, cpulevel_t level,
|
||||
cpuwhich_t which, id_t id, size_t cpusetsize,
|
||||
const cpuset_t *maskp);
|
||||
int kern_cpuset_getdomain(struct thread *td, cpulevel_t level,
|
||||
cpuwhich_t which, id_t id, size_t domainsetsize,
|
||||
domainset_t *maskp, int *policyp);
|
||||
int kern_cpuset_setdomain(struct thread *td, cpulevel_t level,
|
||||
cpuwhich_t which, id_t id, size_t domainsetsize,
|
||||
const domainset_t *maskp, int policy);
|
||||
int kern_cpuset_getid(struct thread *td, cpulevel_t level,
|
||||
cpuwhich_t which, id_t id, cpusetid_t *setid);
|
||||
int kern_cpuset_setid(struct thread *td, cpuwhich_t which,
|
||||
|
@ -1,514 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_vm.h"
|
||||
#include "opt_ddb.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mutex.h>
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
#include <sys/proc.h>
|
||||
#endif
|
||||
#include <sys/queue.h>
|
||||
#include <sys/rwlock.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/tree.h>
|
||||
#include <sys/vmmeter.h>
|
||||
#include <sys/seq.h>
|
||||
|
||||
#include <ddb/ddb.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_phys.h>
|
||||
|
||||
#include <vm/vm_domain.h>
|
||||
|
||||
/*
|
||||
* Default to first-touch + round-robin.
|
||||
*/
|
||||
static struct mtx vm_default_policy_mtx;
|
||||
MTX_SYSINIT(vm_default_policy, &vm_default_policy_mtx, "default policy mutex",
|
||||
MTX_DEF);
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
static struct vm_domain_policy vm_default_policy =
|
||||
VM_DOMAIN_POLICY_STATIC_INITIALISER(VM_POLICY_FIRST_TOUCH_ROUND_ROBIN, 0);
|
||||
#else
|
||||
/* Use round-robin so the domain policy code will only try once per allocation */
|
||||
static struct vm_domain_policy vm_default_policy =
|
||||
VM_DOMAIN_POLICY_STATIC_INITIALISER(VM_POLICY_ROUND_ROBIN, 0);
|
||||
#endif
|
||||
|
||||
static int
|
||||
sysctl_vm_default_policy(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
char policy_name[32];
|
||||
int error;
|
||||
|
||||
mtx_lock(&vm_default_policy_mtx);
|
||||
|
||||
/* Map policy to output string */
|
||||
switch (vm_default_policy.p.policy) {
|
||||
case VM_POLICY_FIRST_TOUCH:
|
||||
strcpy(policy_name, "first-touch");
|
||||
break;
|
||||
case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
|
||||
strcpy(policy_name, "first-touch-rr");
|
||||
break;
|
||||
case VM_POLICY_ROUND_ROBIN:
|
||||
default:
|
||||
strcpy(policy_name, "rr");
|
||||
break;
|
||||
}
|
||||
mtx_unlock(&vm_default_policy_mtx);
|
||||
|
||||
error = sysctl_handle_string(oidp, &policy_name[0],
|
||||
sizeof(policy_name), req);
|
||||
if (error != 0 || req->newptr == NULL)
|
||||
return (error);
|
||||
|
||||
mtx_lock(&vm_default_policy_mtx);
|
||||
/* Set: match on the subset of policies that make sense as a default */
|
||||
if (strcmp("first-touch-rr", policy_name) == 0) {
|
||||
vm_domain_policy_set(&vm_default_policy,
|
||||
VM_POLICY_FIRST_TOUCH_ROUND_ROBIN, 0);
|
||||
} else if (strcmp("first-touch", policy_name) == 0) {
|
||||
vm_domain_policy_set(&vm_default_policy,
|
||||
VM_POLICY_FIRST_TOUCH, 0);
|
||||
} else if (strcmp("rr", policy_name) == 0) {
|
||||
vm_domain_policy_set(&vm_default_policy,
|
||||
VM_POLICY_ROUND_ROBIN, 0);
|
||||
} else {
|
||||
error = EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
error = 0;
|
||||
finish:
|
||||
mtx_unlock(&vm_default_policy_mtx);
|
||||
return (error);
|
||||
}
|
||||
|
||||
SYSCTL_PROC(_vm, OID_AUTO, default_policy, CTLTYPE_STRING | CTLFLAG_RW,
|
||||
0, 0, sysctl_vm_default_policy, "A",
|
||||
"Default policy (rr, first-touch, first-touch-rr");
|
||||
|
||||
/*
|
||||
* Initialise a VM domain iterator.
|
||||
*
|
||||
* Check the thread policy, then the proc policy,
|
||||
* then default to the system policy.
|
||||
*/
|
||||
void
|
||||
vm_policy_iterator_init(struct vm_domain_iterator *vi)
|
||||
{
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
struct vm_domain_policy lcl;
|
||||
#endif
|
||||
|
||||
vm_domain_iterator_init(vi);
|
||||
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
/* Copy out the thread policy */
|
||||
vm_domain_policy_localcopy(&lcl, &curthread->td_vm_dom_policy);
|
||||
if (lcl.p.policy != VM_POLICY_NONE) {
|
||||
/* Thread policy is present; use it */
|
||||
vm_domain_iterator_set_policy(vi, &lcl);
|
||||
return;
|
||||
}
|
||||
|
||||
vm_domain_policy_localcopy(&lcl,
|
||||
&curthread->td_proc->p_vm_dom_policy);
|
||||
if (lcl.p.policy != VM_POLICY_NONE) {
|
||||
/* Process policy is present; use it */
|
||||
vm_domain_iterator_set_policy(vi, &lcl);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Use system default policy */
|
||||
vm_domain_iterator_set_policy(vi, &vm_default_policy);
|
||||
}
|
||||
|
||||
void
|
||||
vm_policy_iterator_finish(struct vm_domain_iterator *vi)
|
||||
{
|
||||
|
||||
vm_domain_iterator_cleanup(vi);
|
||||
}
|
||||
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
static __inline int
|
||||
vm_domain_rr_selectdomain(int skip_domain)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
td = curthread;
|
||||
|
||||
td->td_dom_rr_idx++;
|
||||
td->td_dom_rr_idx %= vm_ndomains;
|
||||
|
||||
/*
|
||||
* If skip_domain is provided then skip over that
|
||||
* domain. This is intended for round robin variants
|
||||
* which first try a fixed domain.
|
||||
*/
|
||||
if ((skip_domain > -1) && (td->td_dom_rr_idx == skip_domain)) {
|
||||
td->td_dom_rr_idx++;
|
||||
td->td_dom_rr_idx %= vm_ndomains;
|
||||
}
|
||||
return (td->td_dom_rr_idx);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This implements a very simple set of VM domain memory allocation
|
||||
* policies and iterators.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A VM domain policy represents a desired VM domain policy.
|
||||
* Iterators implement searching through VM domains in a specific
|
||||
* order.
|
||||
*/
|
||||
|
||||
/*
|
||||
* When setting a policy, the caller must establish their own
|
||||
* exclusive write protection for the contents of the domain
|
||||
* policy.
|
||||
*/
|
||||
int
|
||||
vm_domain_policy_init(struct vm_domain_policy *vp)
|
||||
{
|
||||
|
||||
bzero(vp, sizeof(*vp));
|
||||
vp->p.policy = VM_POLICY_NONE;
|
||||
vp->p.domain = -1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vm_domain_policy_set(struct vm_domain_policy *vp,
|
||||
vm_domain_policy_type_t vt, int domain)
|
||||
{
|
||||
|
||||
seq_write_begin(&vp->seq);
|
||||
vp->p.policy = vt;
|
||||
vp->p.domain = domain;
|
||||
seq_write_end(&vp->seq);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a local copy of a policy.
|
||||
*
|
||||
* The destination policy isn't write-barriered; this is used
|
||||
* for doing local copies into something that isn't shared.
|
||||
*/
|
||||
void
|
||||
vm_domain_policy_localcopy(struct vm_domain_policy *dst,
|
||||
const struct vm_domain_policy *src)
|
||||
{
|
||||
seq_t seq;
|
||||
|
||||
for (;;) {
|
||||
seq = seq_read(&src->seq);
|
||||
*dst = *src;
|
||||
if (seq_consistent(&src->seq, seq))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a write-barrier copy of a policy.
|
||||
*
|
||||
* The destination policy is write -barriered; this is used
|
||||
* for doing copies into policies that may be read by other
|
||||
* threads.
|
||||
*/
|
||||
void
|
||||
vm_domain_policy_copy(struct vm_domain_policy *dst,
|
||||
const struct vm_domain_policy *src)
|
||||
{
|
||||
seq_t seq;
|
||||
struct vm_domain_policy d;
|
||||
|
||||
for (;;) {
|
||||
seq = seq_read(&src->seq);
|
||||
d = *src;
|
||||
if (seq_consistent(&src->seq, seq)) {
|
||||
seq_write_begin(&dst->seq);
|
||||
dst->p.domain = d.p.domain;
|
||||
dst->p.policy = d.p.policy;
|
||||
seq_write_end(&dst->seq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
vm_domain_policy_validate(const struct vm_domain_policy *vp)
|
||||
{
|
||||
|
||||
switch (vp->p.policy) {
|
||||
case VM_POLICY_NONE:
|
||||
case VM_POLICY_ROUND_ROBIN:
|
||||
case VM_POLICY_FIRST_TOUCH:
|
||||
case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
|
||||
if (vp->p.domain == -1)
|
||||
return (0);
|
||||
return (-1);
|
||||
case VM_POLICY_FIXED_DOMAIN:
|
||||
case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
if (vp->p.domain >= 0 && vp->p.domain < vm_ndomains)
|
||||
return (0);
|
||||
#else
|
||||
if (vp->p.domain == 0)
|
||||
return (0);
|
||||
#endif
|
||||
return (-1);
|
||||
default:
|
||||
return (-1);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
vm_domain_policy_cleanup(struct vm_domain_policy *vp)
|
||||
{
|
||||
|
||||
/* For now, empty */
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
vm_domain_iterator_init(struct vm_domain_iterator *vi)
|
||||
{
|
||||
|
||||
/* Nothing to do for now */
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Manually setup an iterator with the given details.
|
||||
*/
|
||||
int
|
||||
vm_domain_iterator_set(struct vm_domain_iterator *vi,
|
||||
vm_domain_policy_type_t vt, int domain)
|
||||
{
|
||||
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
switch (vt) {
|
||||
case VM_POLICY_FIXED_DOMAIN:
|
||||
vi->policy = VM_POLICY_FIXED_DOMAIN;
|
||||
vi->domain = domain;
|
||||
vi->n = 1;
|
||||
break;
|
||||
case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
|
||||
vi->policy = VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN;
|
||||
vi->domain = domain;
|
||||
vi->n = vm_ndomains;
|
||||
break;
|
||||
case VM_POLICY_FIRST_TOUCH:
|
||||
vi->policy = VM_POLICY_FIRST_TOUCH;
|
||||
vi->domain = PCPU_GET(domain);
|
||||
vi->n = 1;
|
||||
break;
|
||||
case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
|
||||
vi->policy = VM_POLICY_FIRST_TOUCH_ROUND_ROBIN;
|
||||
vi->domain = PCPU_GET(domain);
|
||||
vi->n = vm_ndomains;
|
||||
break;
|
||||
case VM_POLICY_ROUND_ROBIN:
|
||||
default:
|
||||
vi->policy = VM_POLICY_ROUND_ROBIN;
|
||||
vi->domain = -1;
|
||||
vi->n = vm_ndomains;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
vi->domain = 0;
|
||||
vi->n = 1;
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup an iterator based on the given policy.
|
||||
*/
|
||||
static inline void
|
||||
_vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
|
||||
const struct vm_domain_policy *vt)
|
||||
{
|
||||
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
/*
|
||||
* Initialise the iterator.
|
||||
*
|
||||
* For first-touch, the initial domain is set
|
||||
* via the current thread CPU domain.
|
||||
*
|
||||
* For fixed-domain, it's assumed that the
|
||||
* caller has initialised the specific domain
|
||||
* it is after.
|
||||
*/
|
||||
switch (vt->p.policy) {
|
||||
case VM_POLICY_FIXED_DOMAIN:
|
||||
vi->policy = vt->p.policy;
|
||||
vi->domain = vt->p.domain;
|
||||
vi->n = 1;
|
||||
break;
|
||||
case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
|
||||
vi->policy = vt->p.policy;
|
||||
vi->domain = vt->p.domain;
|
||||
vi->n = vm_ndomains;
|
||||
break;
|
||||
case VM_POLICY_FIRST_TOUCH:
|
||||
vi->policy = vt->p.policy;
|
||||
vi->domain = PCPU_GET(domain);
|
||||
vi->n = 1;
|
||||
break;
|
||||
case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
|
||||
vi->policy = vt->p.policy;
|
||||
vi->domain = PCPU_GET(domain);
|
||||
vi->n = vm_ndomains;
|
||||
break;
|
||||
case VM_POLICY_ROUND_ROBIN:
|
||||
default:
|
||||
/*
|
||||
* Default to round-robin policy.
|
||||
*/
|
||||
vi->policy = VM_POLICY_ROUND_ROBIN;
|
||||
vi->domain = -1;
|
||||
vi->n = vm_ndomains;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
vi->domain = 0;
|
||||
vi->n = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
|
||||
const struct vm_domain_policy *vt)
|
||||
{
|
||||
seq_t seq;
|
||||
struct vm_domain_policy vt_lcl;
|
||||
|
||||
for (;;) {
|
||||
seq = seq_read(&vt->seq);
|
||||
vt_lcl = *vt;
|
||||
if (seq_consistent(&vt->seq, seq)) {
|
||||
_vm_domain_iterator_set_policy(vi, &vt_lcl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next VM domain to use.
|
||||
*
|
||||
* Returns 0 w/ domain set to the next domain to use, or
|
||||
* -1 to indicate no more domains are available.
|
||||
*/
|
||||
int
|
||||
vm_domain_iterator_run(struct vm_domain_iterator *vi, int *domain)
|
||||
{
|
||||
|
||||
/* General catch-all */
|
||||
if (vi->n <= 0)
|
||||
return (-1);
|
||||
|
||||
#ifdef VM_NUMA_ALLOC
|
||||
switch (vi->policy) {
|
||||
case VM_POLICY_FIXED_DOMAIN:
|
||||
case VM_POLICY_FIRST_TOUCH:
|
||||
*domain = vi->domain;
|
||||
vi->n--;
|
||||
break;
|
||||
case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
|
||||
case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
|
||||
/*
|
||||
* XXX TODO: skip over the rr'ed domain
|
||||
* if it equals the one we started with.
|
||||
*/
|
||||
if (vi->n == vm_ndomains)
|
||||
*domain = vi->domain;
|
||||
else
|
||||
*domain = vm_domain_rr_selectdomain(vi->domain);
|
||||
vi->n--;
|
||||
break;
|
||||
case VM_POLICY_ROUND_ROBIN:
|
||||
default:
|
||||
*domain = vm_domain_rr_selectdomain(-1);
|
||||
vi->n--;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
*domain = 0;
|
||||
vi->n--;
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns 1 if the iteration is done, or 0 if it has not.
|
||||
|
||||
* This can only be called after at least one loop through
|
||||
* the iterator. Ie, it's designed to be used as a tail
|
||||
* check of a loop, not the head check of a loop.
|
||||
*/
|
||||
int
|
||||
vm_domain_iterator_isdone(struct vm_domain_iterator *vi)
|
||||
{
|
||||
|
||||
return (vi->n <= 0);
|
||||
}
|
||||
|
||||
int
|
||||
vm_domain_iterator_cleanup(struct vm_domain_iterator *vi)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
|
||||
* redistribution must be conditioned upon including a substantially
|
||||
* similar Disclaimer requirement for further binary redistribution.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef __VM_DOMAIN_H__
|
||||
#define __VM_DOMAIN_H__
|
||||
|
||||
#include <sys/_vm_domain.h>
|
||||
|
||||
struct vm_domain_iterator {
|
||||
vm_domain_policy_type_t policy;
|
||||
int domain;
|
||||
int n;
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO: check to see if these should just become inline functions
|
||||
* at some point.
|
||||
*/
|
||||
extern int vm_domain_policy_init(struct vm_domain_policy *vp);
|
||||
extern int vm_domain_policy_set(struct vm_domain_policy *vp,
|
||||
vm_domain_policy_type_t vt, int domain);
|
||||
extern int vm_domain_policy_cleanup(struct vm_domain_policy *vp);
|
||||
extern void vm_domain_policy_localcopy(struct vm_domain_policy *dst,
|
||||
const struct vm_domain_policy *src);
|
||||
extern void vm_domain_policy_copy(struct vm_domain_policy *dst,
|
||||
const struct vm_domain_policy *src);
|
||||
extern int vm_domain_policy_validate(const struct vm_domain_policy *vp);
|
||||
|
||||
extern int vm_domain_iterator_init(struct vm_domain_iterator *vi);
|
||||
extern int vm_domain_iterator_set(struct vm_domain_iterator *vi,
|
||||
vm_domain_policy_type_t vt, int domain);
|
||||
extern void vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
|
||||
const struct vm_domain_policy *vt);
|
||||
extern int vm_domain_iterator_run(struct vm_domain_iterator *vi,
|
||||
int *domain);
|
||||
extern int vm_domain_iterator_isdone(struct vm_domain_iterator *vi);
|
||||
extern int vm_domain_iterator_cleanup(struct vm_domain_iterator *vi);
|
||||
|
||||
extern void vm_policy_iterator_init(struct vm_domain_iterator *vi);
|
||||
extern void vm_policy_iterator_finish(struct vm_domain_iterator *vi);
|
||||
|
||||
#endif /* __VM_DOMAIN_H__ */
|
@ -1589,6 +1589,7 @@ vm_fault_copy_entry(vm_map_t dst_map, vm_map_t src_map,
|
||||
KASSERT(upgrade || dst_entry->object.vm_object == NULL,
|
||||
("vm_fault_copy_entry: vm_object not NULL"));
|
||||
if (src_object != dst_object) {
|
||||
dst_object->domain = src_object->domain;
|
||||
dst_entry->object.vm_object = dst_object;
|
||||
dst_entry->offset = 0;
|
||||
dst_object->charge = dst_entry->end - dst_entry->start;
|
||||
|
@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
@ -1364,6 +1365,7 @@ vm_object_shadow(
|
||||
result->backing_object_offset = *offset;
|
||||
if (source != NULL) {
|
||||
VM_OBJECT_WLOCK(source);
|
||||
result->domain = source->domain;
|
||||
LIST_INSERT_HEAD(&source->shadow_head, result, shadow_list);
|
||||
source->shadow_count++;
|
||||
#if VM_NRESERVLEVEL > 0
|
||||
@ -1419,6 +1421,7 @@ vm_object_split(vm_map_entry_t entry)
|
||||
*/
|
||||
VM_OBJECT_WLOCK(new_object);
|
||||
VM_OBJECT_WLOCK(orig_object);
|
||||
new_object->domain = orig_object->domain;
|
||||
source = orig_object->backing_object;
|
||||
if (source != NULL) {
|
||||
VM_OBJECT_WLOCK(source);
|
||||
|
@ -74,6 +74,7 @@
|
||||
#include <sys/_mutex.h>
|
||||
#include <sys/_pctrie.h>
|
||||
#include <sys/_rwlock.h>
|
||||
#include <sys/_domainset.h>
|
||||
|
||||
#include <vm/_vm_radix.h>
|
||||
|
||||
@ -102,6 +103,7 @@ struct vm_object {
|
||||
struct pglist memq; /* list of resident pages */
|
||||
struct vm_radix rtree; /* root of the resident page radix trie*/
|
||||
vm_pindex_t size; /* Object size */
|
||||
struct domainset_ref domain; /* NUMA policy. */
|
||||
int generation; /* generation ID */
|
||||
int ref_count; /* How many refs?? */
|
||||
int shadow_count; /* how many objects that this is a shadow for */
|
||||
|
@ -91,6 +91,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/domainset.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/linker.h>
|
||||
@ -109,7 +110,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_param.h>
|
||||
#include <vm/vm_domain.h>
|
||||
#include <vm/vm_domainset.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/vm_object.h>
|
||||
#include <vm/vm_page.h>
|
||||
@ -742,6 +743,12 @@ vm_page_startup(vm_offset_t vaddr)
|
||||
*/
|
||||
vm_reserv_init();
|
||||
#endif
|
||||
/*
|
||||
* Set an initial domain policy for thread0 so that allocations
|
||||
* can work.
|
||||
*/
|
||||
domainset_zero();
|
||||
|
||||
return (vaddr);
|
||||
}
|
||||
|
||||
@ -1622,23 +1629,17 @@ vm_page_t
|
||||
vm_page_alloc_after(vm_object_t object, vm_pindex_t pindex,
|
||||
int req, vm_page_t mpred)
|
||||
{
|
||||
struct vm_domain_iterator vi;
|
||||
struct vm_domainset_iter di;
|
||||
vm_page_t m;
|
||||
int domain, wait;
|
||||
int domain;
|
||||
|
||||
m = NULL;
|
||||
vm_policy_iterator_init(&vi);
|
||||
wait = req & (VM_ALLOC_WAITFAIL | VM_ALLOC_WAITOK);
|
||||
req &= ~wait;
|
||||
while (vm_domain_iterator_run(&vi, &domain) == 0) {
|
||||
if (vm_domain_iterator_isdone(&vi))
|
||||
req |= wait;
|
||||
vm_domainset_iter_page_init(&di, object, &domain, &req);
|
||||
do {
|
||||
m = vm_page_alloc_domain_after(object, pindex, domain, req,
|
||||
mpred);
|
||||
if (m != NULL)
|
||||
break;
|
||||
}
|
||||
vm_policy_iterator_finish(&vi);
|
||||
} while (vm_domainset_iter_page(&di, &domain, &req) == 0);
|
||||
|
||||
return (m);
|
||||
}
|
||||
@ -1835,23 +1836,17 @@ vm_page_alloc_contig(vm_object_t object, vm_pindex_t pindex, int req,
|
||||
u_long npages, vm_paddr_t low, vm_paddr_t high, u_long alignment,
|
||||
vm_paddr_t boundary, vm_memattr_t memattr)
|
||||
{
|
||||
struct vm_domain_iterator vi;
|
||||
struct vm_domainset_iter di;
|
||||
vm_page_t m;
|
||||
int domain, wait;
|
||||
int domain;
|
||||
|
||||
m = NULL;
|
||||
vm_policy_iterator_init(&vi);
|
||||
wait = req & (VM_ALLOC_WAITFAIL | VM_ALLOC_WAITOK);
|
||||
req &= ~wait;
|
||||
while (vm_domain_iterator_run(&vi, &domain) == 0) {
|
||||
if (vm_domain_iterator_isdone(&vi))
|
||||
req |= wait;
|
||||
vm_domainset_iter_page_init(&di, object, &domain, &req);
|
||||
do {
|
||||
m = vm_page_alloc_contig_domain(object, pindex, domain, req,
|
||||
npages, low, high, alignment, boundary, memattr);
|
||||
if (m != NULL)
|
||||
break;
|
||||
}
|
||||
vm_policy_iterator_finish(&vi);
|
||||
} while (vm_domainset_iter_page(&di, &domain, &req) == 0);
|
||||
|
||||
return (m);
|
||||
}
|
||||
@ -2045,22 +2040,16 @@ vm_page_alloc_check(vm_page_t m)
|
||||
vm_page_t
|
||||
vm_page_alloc_freelist(int freelist, int req)
|
||||
{
|
||||
struct vm_domain_iterator vi;
|
||||
struct vm_domainset_iter di;
|
||||
vm_page_t m;
|
||||
int domain, wait;
|
||||
int domain;
|
||||
|
||||
m = NULL;
|
||||
vm_policy_iterator_init(&vi);
|
||||
wait = req & (VM_ALLOC_WAITFAIL | VM_ALLOC_WAITOK);
|
||||
req &= ~wait;
|
||||
while (vm_domain_iterator_run(&vi, &domain) == 0) {
|
||||
if (vm_domain_iterator_isdone(&vi))
|
||||
req |= wait;
|
||||
vm_domainset_iter_page_init(&di, kernel_object, &domain, &req);
|
||||
do {
|
||||
m = vm_page_alloc_freelist_domain(domain, freelist, req);
|
||||
if (m != NULL)
|
||||
break;
|
||||
}
|
||||
vm_policy_iterator_finish(&vi);
|
||||
} while (vm_domainset_iter_page(&di, &domain, &req) == 0);
|
||||
|
||||
return (m);
|
||||
}
|
||||
@ -2562,8 +2551,8 @@ CTASSERT(powerof2(NRUNS));
|
||||
* must be a power of two.
|
||||
*/
|
||||
bool
|
||||
vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
u_long alignment, vm_paddr_t boundary)
|
||||
vm_page_reclaim_contig_domain(int domain, int req, u_long npages,
|
||||
vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary)
|
||||
{
|
||||
vm_paddr_t curr_low;
|
||||
vm_page_t m_run, m_runs[NRUNS];
|
||||
@ -2603,8 +2592,8 @@ vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
curr_low = low;
|
||||
count = 0;
|
||||
for (;;) {
|
||||
m_run = vm_phys_scan_contig(npages, curr_low, high,
|
||||
alignment, boundary, options);
|
||||
m_run = vm_phys_scan_contig(domain, npages, curr_low,
|
||||
high, alignment, boundary, options);
|
||||
if (m_run == NULL)
|
||||
break;
|
||||
curr_low = VM_PAGE_TO_PHYS(m_run) + ptoa(npages);
|
||||
@ -2645,6 +2634,26 @@ vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
u_long alignment, vm_paddr_t boundary)
|
||||
{
|
||||
struct vm_domainset_iter di;
|
||||
int domain;
|
||||
bool ret;
|
||||
|
||||
vm_domainset_iter_page_init(&di, kernel_object, &domain, &req);
|
||||
do {
|
||||
ret = vm_page_reclaim_contig_domain(domain, req, npages, low,
|
||||
high, alignment, boundary);
|
||||
if (ret)
|
||||
break;
|
||||
} while (vm_domainset_iter_page(&di, &domain, &req) == 0);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* vm_wait: (also see VM_WAIT macro)
|
||||
*
|
||||
|
@ -229,6 +229,7 @@ struct vm_pagequeue {
|
||||
|
||||
struct vm_domain {
|
||||
struct vm_pagequeue vmd_pagequeues[PQ_COUNT];
|
||||
struct vmem *vmd_kernel_arena;
|
||||
u_int vmd_page_count;
|
||||
u_int vmd_free_count;
|
||||
long vmd_segs; /* bitmask of the segments */
|
||||
@ -514,7 +515,7 @@ void vm_page_putfake(vm_page_t m);
|
||||
void vm_page_readahead_finish(vm_page_t m);
|
||||
bool vm_page_reclaim_contig(int req, u_long npages, vm_paddr_t low,
|
||||
vm_paddr_t high, u_long alignment, vm_paddr_t boundary);
|
||||
bool vm_page_reclaim_contig_domain(int req, u_long npages, int domain,
|
||||
bool vm_page_reclaim_contig_domain(int domain, int req, u_long npages,
|
||||
vm_paddr_t low, vm_paddr_t high, u_long alignment, vm_paddr_t boundary);
|
||||
void vm_page_reference(vm_page_t m);
|
||||
void vm_page_remove (vm_page_t);
|
||||
|
@ -68,8 +68,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_phys.h>
|
||||
|
||||
#include <vm/vm_domain.h>
|
||||
|
||||
_Static_assert(sizeof(long) * NBBY >= VM_PHYSSEG_MAX,
|
||||
"Too many physsegs.");
|
||||
|
||||
@ -973,7 +971,7 @@ vm_phys_free_contig(vm_page_t m, u_long npages)
|
||||
* be a power of two.
|
||||
*/
|
||||
vm_page_t
|
||||
vm_phys_scan_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
vm_phys_scan_contig(int domain, u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
u_long alignment, vm_paddr_t boundary, int options)
|
||||
{
|
||||
vm_paddr_t pa_end;
|
||||
@ -988,6 +986,8 @@ vm_phys_scan_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
return (NULL);
|
||||
for (segind = 0; segind < vm_phys_nsegs; segind++) {
|
||||
seg = &vm_phys_segs[segind];
|
||||
if (seg->domain != domain)
|
||||
continue;
|
||||
if (seg->start >= high)
|
||||
break;
|
||||
if (low >= seg->end)
|
||||
|
@ -86,8 +86,8 @@ void vm_phys_free_contig(vm_page_t m, u_long npages);
|
||||
void vm_phys_free_pages(vm_page_t m, int order);
|
||||
void vm_phys_init(void);
|
||||
vm_page_t vm_phys_paddr_to_vm_page(vm_paddr_t pa);
|
||||
vm_page_t vm_phys_scan_contig(u_long npages, vm_paddr_t low, vm_paddr_t high,
|
||||
u_long alignment, vm_paddr_t boundary, int options);
|
||||
vm_page_t vm_phys_scan_contig(int domain, u_long npages, vm_paddr_t low,
|
||||
vm_paddr_t high, u_long alignment, vm_paddr_t boundary, int options);
|
||||
void vm_phys_set_pool(int pool, vm_page_t m, int order);
|
||||
boolean_t vm_phys_unfree_page(vm_page_t m);
|
||||
int vm_phys_mem_affinity(int f, int t);
|
||||
|
@ -252,7 +252,8 @@ srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *arg)
|
||||
"enabled" : "disabled");
|
||||
if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED))
|
||||
break;
|
||||
if (!overlaps_phys_avail(mem->BaseAddress,
|
||||
if (mem->BaseAddress >= cpu_getmaxphyaddr() ||
|
||||
!overlaps_phys_avail(mem->BaseAddress,
|
||||
mem->BaseAddress + mem->Length)) {
|
||||
printf("SRAT: Ignoring memory at addr 0x%jx\n",
|
||||
(uintmax_t)mem->BaseAddress);
|
||||
|
@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/domainset.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
@ -55,6 +56,7 @@ static int gflag;
|
||||
static int iflag;
|
||||
static int jflag;
|
||||
static int lflag;
|
||||
static int nflag;
|
||||
static int pflag;
|
||||
static int rflag;
|
||||
static int sflag;
|
||||
@ -66,30 +68,40 @@ static cpuwhich_t which;
|
||||
|
||||
static void usage(void);
|
||||
|
||||
static void printset(cpuset_t *mask);
|
||||
struct numa_policy {
|
||||
const char *name;
|
||||
int policy;
|
||||
};
|
||||
|
||||
static struct numa_policy policies[] = {
|
||||
{ "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
|
||||
{ "rr", DOMAINSET_POLICY_ROUNDROBIN },
|
||||
{ "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
|
||||
{ "ft", DOMAINSET_POLICY_FIRSTTOUCH },
|
||||
{ "prefer", DOMAINSET_POLICY_PREFER },
|
||||
{ NULL, DOMAINSET_POLICY_INVALID }
|
||||
};
|
||||
|
||||
BITSET_DEFINE(bitset, 1);
|
||||
static void printset(struct bitset *mask, int size);
|
||||
|
||||
static void
|
||||
parselist(char *list, cpuset_t *mask)
|
||||
parselist(char *list, struct bitset *mask, int size)
|
||||
{
|
||||
enum { NONE, NUM, DASH } state;
|
||||
int lastnum;
|
||||
int curnum;
|
||||
char *l;
|
||||
|
||||
if (strcasecmp(list, "all") == 0) {
|
||||
if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
|
||||
sizeof(*mask), mask) != 0)
|
||||
err(EXIT_FAILURE, "getaffinity");
|
||||
return;
|
||||
}
|
||||
state = NONE;
|
||||
curnum = lastnum = 0;
|
||||
for (l = list; *l != '\0';) {
|
||||
if (isdigit(*l)) {
|
||||
curnum = atoi(l);
|
||||
if (curnum > CPU_SETSIZE)
|
||||
if (curnum > size)
|
||||
errx(EXIT_FAILURE,
|
||||
"Only %d cpus supported", CPU_SETSIZE);
|
||||
"List entry %d exceeds maximum of %d",
|
||||
curnum, size);
|
||||
while (isdigit(*l))
|
||||
l++;
|
||||
switch (state) {
|
||||
@ -99,7 +111,7 @@ parselist(char *list, cpuset_t *mask)
|
||||
break;
|
||||
case DASH:
|
||||
for (; lastnum <= curnum; lastnum++)
|
||||
CPU_SET(lastnum, mask);
|
||||
BIT_SET(size, lastnum, mask);
|
||||
state = NONE;
|
||||
break;
|
||||
case NUM:
|
||||
@ -114,7 +126,7 @@ parselist(char *list, cpuset_t *mask)
|
||||
case NONE:
|
||||
break;
|
||||
case NUM:
|
||||
CPU_SET(curnum, mask);
|
||||
BIT_SET(size, curnum, mask);
|
||||
state = NONE;
|
||||
break;
|
||||
case DASH:
|
||||
@ -136,29 +148,86 @@ parselist(char *list, cpuset_t *mask)
|
||||
case NONE:
|
||||
break;
|
||||
case NUM:
|
||||
CPU_SET(curnum, mask);
|
||||
BIT_SET(size, curnum, mask);
|
||||
break;
|
||||
case DASH:
|
||||
goto parserr;
|
||||
}
|
||||
return;
|
||||
parserr:
|
||||
errx(EXIT_FAILURE, "Malformed cpu-list %s", list);
|
||||
errx(EXIT_FAILURE, "Malformed list %s", list);
|
||||
}
|
||||
|
||||
static void
|
||||
printset(cpuset_t *mask)
|
||||
parsecpulist(char *list, cpuset_t *mask)
|
||||
{
|
||||
|
||||
if (strcasecmp(list, "all") == 0) {
|
||||
if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
|
||||
sizeof(*mask), mask) != 0)
|
||||
err(EXIT_FAILURE, "getaffinity");
|
||||
return;
|
||||
}
|
||||
parselist(list, (struct bitset *)mask, CPU_SETSIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* permissively parse policy:domain list
|
||||
* allow:
|
||||
* round-robin:0-4 explicit
|
||||
* round-robin:all explicit root domains
|
||||
* 0-4 implicit root policy
|
||||
* round-robin implicit root domains
|
||||
* all explicit root domains and implicit policy
|
||||
*/
|
||||
static void
|
||||
parsedomainlist(char *list, domainset_t *mask, int *policyp)
|
||||
{
|
||||
domainset_t rootmask;
|
||||
struct numa_policy *policy;
|
||||
char *l;
|
||||
int p;
|
||||
|
||||
/*
|
||||
* Use the rootset's policy as the default for unspecified policies.
|
||||
*/
|
||||
if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
|
||||
sizeof(rootmask), &rootmask, &p) != 0)
|
||||
err(EXIT_FAILURE, "getdomain");
|
||||
|
||||
l = list;
|
||||
for (policy = &policies[0]; policy->name != NULL; policy++) {
|
||||
if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
|
||||
p = policy->policy;
|
||||
l += strlen(policy->name);
|
||||
if (*l != ':' && *l != '\0')
|
||||
errx(EXIT_FAILURE, "Malformed list %s", list);
|
||||
if (*l == ':')
|
||||
l++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*policyp = p;
|
||||
if (strcasecmp(l, "all") == 0 || *l == '\0') {
|
||||
DOMAINSET_COPY(&rootmask, mask);
|
||||
return;
|
||||
}
|
||||
parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE);
|
||||
}
|
||||
|
||||
static void
|
||||
printset(struct bitset *mask, int size)
|
||||
{
|
||||
int once;
|
||||
int cpu;
|
||||
int bit;
|
||||
|
||||
for (once = 0, cpu = 0; cpu < CPU_SETSIZE; cpu++) {
|
||||
if (CPU_ISSET(cpu, mask)) {
|
||||
for (once = 0, bit = 0; bit < size; bit++) {
|
||||
if (BIT_ISSET(size, bit, mask)) {
|
||||
if (once == 0) {
|
||||
printf("%d", cpu);
|
||||
printf("%d", bit);
|
||||
once = 1;
|
||||
} else
|
||||
printf(", %d", cpu);
|
||||
printf(", %d", bit);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
@ -167,17 +236,30 @@ printset(cpuset_t *mask)
|
||||
static const char *whichnames[] = { NULL, "tid", "pid", "cpuset", "irq", "jail",
|
||||
"domain" };
|
||||
static const char *levelnames[] = { NULL, " root", " cpuset", "" };
|
||||
static const char *policynames[] = { "invalid", "round-robin", "first-touch",
|
||||
"prefer" };
|
||||
|
||||
static void
|
||||
printaffinity(void)
|
||||
{
|
||||
domainset_t domain;
|
||||
cpuset_t mask;
|
||||
int policy;
|
||||
|
||||
if (cpuset_getaffinity(level, which, id, sizeof(mask), &mask) != 0)
|
||||
err(EXIT_FAILURE, "getaffinity");
|
||||
printf("%s %jd%s mask: ", whichnames[which], (intmax_t)id,
|
||||
levelnames[level]);
|
||||
printset(&mask);
|
||||
printset((struct bitset *)&mask, CPU_SETSIZE);
|
||||
if (dflag)
|
||||
goto out;
|
||||
if (cpuset_getdomain(level, which, id, sizeof(domain), &domain,
|
||||
&policy) != 0)
|
||||
err(EXIT_FAILURE, "getdomain");
|
||||
printf("%s %jd%s domain policy: %s mask: ", whichnames[which],
|
||||
(intmax_t)id, levelnames[level], policynames[policy]);
|
||||
printset((struct bitset *)&domain, DOMAINSET_SETSIZE);
|
||||
out:
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@ -200,17 +282,21 @@ printsetid(void)
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
domainset_t domains;
|
||||
cpusetid_t setid;
|
||||
cpuset_t mask;
|
||||
int policy;
|
||||
lwpid_t tid;
|
||||
pid_t pid;
|
||||
int ch;
|
||||
|
||||
CPU_ZERO(&mask);
|
||||
DOMAINSET_ZERO(&domains);
|
||||
policy = DOMAINSET_POLICY_INVALID;
|
||||
level = CPU_LEVEL_WHICH;
|
||||
which = CPU_WHICH_PID;
|
||||
id = pid = tid = setid = -1;
|
||||
while ((ch = getopt(argc, argv, "Ccd:gij:l:p:rs:t:x:")) != -1) {
|
||||
while ((ch = getopt(argc, argv, "Ccd:gij:l:n:p:rs:t:x:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'C':
|
||||
Cflag = 1;
|
||||
@ -237,7 +323,11 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
case 'l':
|
||||
lflag = 1;
|
||||
parselist(optarg, &mask);
|
||||
parsecpulist(optarg, &mask);
|
||||
break;
|
||||
case 'n':
|
||||
nflag = 1;
|
||||
parsedomainlist(optarg, &domains, &policy);
|
||||
break;
|
||||
case 'p':
|
||||
pflag = 1;
|
||||
@ -270,7 +360,7 @@ main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (gflag) {
|
||||
if (argc || Cflag || lflag)
|
||||
if (argc || Cflag || lflag || nflag)
|
||||
usage();
|
||||
/* Only one identity specifier. */
|
||||
if (dflag + jflag + xflag + sflag + pflag + tflag > 1)
|
||||
@ -281,6 +371,7 @@ main(int argc, char *argv[])
|
||||
printaffinity();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (dflag || iflag || rflag)
|
||||
usage();
|
||||
/*
|
||||
@ -301,6 +392,11 @@ main(int argc, char *argv[])
|
||||
-1, sizeof(mask), &mask) != 0)
|
||||
err(EXIT_FAILURE, "setaffinity");
|
||||
}
|
||||
if (nflag) {
|
||||
if (cpuset_setdomain(level, CPU_WHICH_PID,
|
||||
-1, sizeof(domains), &domains, policy) != 0)
|
||||
err(EXIT_FAILURE, "setdomain");
|
||||
}
|
||||
errno = 0;
|
||||
execvp(*argv, argv);
|
||||
err(errno == ENOENT ? 127 : 126, "%s", *argv);
|
||||
@ -310,9 +406,9 @@ main(int argc, char *argv[])
|
||||
*/
|
||||
if (Cflag && (jflag || !pflag || sflag || tflag || xflag))
|
||||
usage();
|
||||
if (!lflag && cflag)
|
||||
if ((!lflag && !nflag) && cflag)
|
||||
usage();
|
||||
if (!lflag && !(Cflag || sflag))
|
||||
if ((!lflag && !nflag) && !(Cflag || sflag))
|
||||
usage();
|
||||
/* You can only set a mask on a thread. */
|
||||
if (tflag && (sflag | pflag | xflag | jflag))
|
||||
@ -344,6 +440,11 @@ main(int argc, char *argv[])
|
||||
&mask) != 0)
|
||||
err(EXIT_FAILURE, "setaffinity");
|
||||
}
|
||||
if (nflag) {
|
||||
if (cpuset_setdomain(level, which, id, sizeof(domains),
|
||||
&domains, policy) != 0)
|
||||
err(EXIT_FAILURE, "setdomain");
|
||||
}
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/cpuset.h>
|
||||
#include <sys/numa.h>
|
||||
#include <sys/domainset.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
@ -58,58 +58,67 @@ static struct option longopts[] = {
|
||||
};
|
||||
|
||||
static const char *
|
||||
policy_to_str(vm_domain_policy_type_t vt)
|
||||
policy_to_str(int policy)
|
||||
{
|
||||
|
||||
switch (vt) {
|
||||
case VM_POLICY_NONE:
|
||||
return ("none");
|
||||
case VM_POLICY_ROUND_ROBIN:
|
||||
return ("rr");
|
||||
case VM_POLICY_FIXED_DOMAIN:
|
||||
return ("fixed-domain");
|
||||
case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
|
||||
return ("fixed-domain-rr");
|
||||
case VM_POLICY_FIRST_TOUCH:
|
||||
switch (policy) {
|
||||
case DOMAINSET_POLICY_INVALID:
|
||||
return ("invalid");
|
||||
case DOMAINSET_POLICY_ROUNDROBIN:
|
||||
return ("round-robin");
|
||||
case DOMAINSET_POLICY_FIRSTTOUCH:
|
||||
return ("first-touch");
|
||||
case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
|
||||
return ("first-touch-rr");
|
||||
case DOMAINSET_POLICY_PREFER:
|
||||
return ("prefer");
|
||||
default:
|
||||
return ("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
domain_print(domainset_t *mask)
|
||||
{
|
||||
int once;
|
||||
int bit;
|
||||
|
||||
for (once = 0, bit = 0; bit < DOMAINSET_SETSIZE; bit++) {
|
||||
if (DOMAINSET_ISSET(bit, mask)) {
|
||||
if (once == 0) {
|
||||
printf("%d", bit);
|
||||
once = 1;
|
||||
} else
|
||||
printf(", %d", bit);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int
|
||||
parse_policy(struct vm_domain_policy_entry *vd, const char *str)
|
||||
parse_policy(int *policy, const char *str)
|
||||
{
|
||||
|
||||
if (strcmp(str, "rr") == 0) {
|
||||
vd->policy = VM_POLICY_ROUND_ROBIN;
|
||||
vd->domain = -1;
|
||||
*policy = DOMAINSET_POLICY_ROUNDROBIN;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(str, "first-touch-rr") == 0) {
|
||||
vd->policy = VM_POLICY_FIRST_TOUCH_ROUND_ROBIN;
|
||||
vd->domain = -1;
|
||||
*policy = DOMAINSET_POLICY_FIRSTTOUCH;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(str, "first-touch") == 0) {
|
||||
vd->policy = VM_POLICY_FIRST_TOUCH;
|
||||
vd->domain = -1;
|
||||
*policy = DOMAINSET_POLICY_FIRSTTOUCH;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(str, "fixed-domain") == 0) {
|
||||
vd->policy = VM_POLICY_FIXED_DOMAIN;
|
||||
vd->domain = 0;
|
||||
*policy = DOMAINSET_POLICY_PREFER;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (strcmp(str, "fixed-domain-rr") == 0) {
|
||||
vd->policy = VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN;
|
||||
vd->domain = 0;
|
||||
*policy = DOMAINSET_POLICY_PREFER;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -150,10 +159,28 @@ set_numa_domain_cpuaffinity(int cpu_domain, cpuwhich_t which, id_t id)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to maintain compatability with old style syscalls.
|
||||
*/
|
||||
static int
|
||||
numa_setaffinity(cpuwhich_t which, id_t id, int policy, int domain)
|
||||
{
|
||||
domainset_t mask;
|
||||
int p;
|
||||
|
||||
DOMAINSET_ZERO(&mask);
|
||||
if (policy == DOMAINSET_POLICY_PREFER)
|
||||
DOMAINSET_SET(domain, &mask);
|
||||
else if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
|
||||
sizeof(mask), &mask, &p) != 0)
|
||||
err(EXIT_FAILURE, "getdomain");
|
||||
return cpuset_setdomain(CPU_LEVEL_WHICH, which, id, sizeof(mask),
|
||||
&mask, policy);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
struct vm_domain_policy_entry vd;
|
||||
lwpid_t tid;
|
||||
pid_t pid;
|
||||
cpuwhich_t which;
|
||||
@ -163,6 +190,8 @@ main(int argc, char *argv[])
|
||||
int mem_policy_set;
|
||||
int ch;
|
||||
int cpu_domain;
|
||||
int policy;
|
||||
int domain;
|
||||
|
||||
id = -1;
|
||||
which = -1;
|
||||
@ -172,6 +201,8 @@ main(int argc, char *argv[])
|
||||
tid = -1;
|
||||
pid = -1;
|
||||
cpu_domain = -1;
|
||||
domain = -1;
|
||||
policy = DOMAINSET_POLICY_INVALID;
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "c:gl:m:p:st:", longopts,
|
||||
NULL)) != -1) {
|
||||
@ -183,7 +214,7 @@ main(int argc, char *argv[])
|
||||
is_get = 1;
|
||||
break;
|
||||
case 'l':
|
||||
if (parse_policy(&vd, optarg) != 0) {
|
||||
if (parse_policy(&policy, optarg) != 0) {
|
||||
fprintf(stderr,
|
||||
"Could not parse policy: '%s'\n", optarg);
|
||||
exit(1);
|
||||
@ -191,12 +222,7 @@ main(int argc, char *argv[])
|
||||
mem_policy_set = 1;
|
||||
break;
|
||||
case 'm':
|
||||
if (mem_policy_set == 0) {
|
||||
fprintf(stderr,
|
||||
"Error: set policy first before domain\n");
|
||||
exit(1);
|
||||
}
|
||||
vd.domain = atoi(optarg);
|
||||
domain = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
pid = atoi(optarg);
|
||||
@ -223,7 +249,7 @@ main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* Set current memory process policy, will be inherited */
|
||||
if (numa_setaffinity(CPU_WHICH_PID, -1, &vd) != 0)
|
||||
if (numa_setaffinity(CPU_WHICH_PID, -1, policy, domain) != 0)
|
||||
err(1, "numa_setaffinity");
|
||||
|
||||
/* If a CPU domain policy was given, include that too */
|
||||
@ -261,19 +287,22 @@ main(int argc, char *argv[])
|
||||
|
||||
/* If it's get, then get the policy and return */
|
||||
if (is_get) {
|
||||
error = numa_getaffinity(which, id, &vd);
|
||||
domainset_t mask;
|
||||
|
||||
error = cpuset_getdomain(CPU_LEVEL_WHICH, which, id,
|
||||
sizeof(mask), &mask, &policy);
|
||||
if (error != 0)
|
||||
err(1, "numa_getaffinity");
|
||||
printf(" Policy: %s; domain: %d\n",
|
||||
policy_to_str(vd.policy),
|
||||
vd.domain);
|
||||
err(1, "cpuset_getdomain");
|
||||
printf(" Policy: %s; domain: ",
|
||||
policy_to_str(policy));
|
||||
domain_print(&mask);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Assume it's set */
|
||||
|
||||
/* Syscall */
|
||||
error = numa_setaffinity(which, id, &vd);
|
||||
error = numa_setaffinity(which, id, policy, domain);
|
||||
if (error != 0)
|
||||
err(1, "numa_setaffinity");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user