Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F148646695
D2559.1787871531.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
71 KB
Referenced Files
None
Subscribers
None
D2559.1787871531.diff
View Options
Index: lib/libc/sys/Makefile.inc
===================================================================
--- lib/libc/sys/Makefile.inc
+++ lib/libc/sys/Makefile.inc
@@ -235,6 +235,7 @@
nanosleep.2 \
nfssvc.2 \
ntp_adjtime.2 \
+ numa_getaffinity.2 \
open.2 \
pathconf.2 \
pdfork.2 \
@@ -395,6 +396,7 @@
MLINKS+=mq_receive.2 mq_timedreceive.2
MLINKS+=mq_send.2 mq_timedsend.2
MLINKS+=ntp_adjtime.2 ntp_gettime.2
+MLINKS+=numa_getaffinity.2 numa_setaffinity.2
MLINKS+=open.2 openat.2
MLINKS+=pathconf.2 fpathconf.2
MLINKS+=pathconf.2 lpathconf.2
Index: lib/libc/sys/Symbol.map
===================================================================
--- lib/libc/sys/Symbol.map
+++ lib/libc/sys/Symbol.map
@@ -400,6 +400,8 @@
futimens;
ppoll;
utimensat;
+ numa_setaffinity;
+ numa_getaffinity;
};
FBSDprivate_1.0 {
Index: lib/libc/sys/numa_getaffinity.2
===================================================================
--- /dev/null
+++ lib/libc/sys/numa_getaffinity.2
@@ -0,0 +1,198 @@
+.\" Copyright (c) 2008 Christian Brueffer
+.\" Copyright (c) 2008 Jeffrey Roberson
+.\" Copyright (c) 2015 Adrian Chadd
+.\" 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.
+.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 7, 2015
+.Dt NUMA_GETAFFINITY 2
+.Os
+.Sh NAME
+.Nm numa_getaffinity ,
+.Nm numa_setaffinity
+.Nd manage NUMA affinity
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/param.h
+.In sys/numa.h
+.Ft int
+.Fn numa_getaffinity "cpuwhich_t which" "id_t id" "struct vm_domain_policy *policy"
+.Ft int
+.Fn numa_setaffinity "cpuwhich_t which" "id_t id" "const struct vm_domain_policy *policy"
+.Sh DESCRIPTION
+.Fn numa_getaffinity
+and
+.Fn numa_setaffinity
+allow the manipulation of NUMA policies available to processes and threads.
+These functions may manipulate NUMA policies that contain many processes
+or affect only a single object.
+.Pp
+Valid values for the
+.Fa which
+argument are documented in
+.Xr cpuset 2 .
+These arguments specify which object set are used.
+Only
+.Dv CPU_WHICH_TID
+and
+.Dv CPU_WHICH_PID
+can be manipulated.
+.Pp
+The
+.Fa policy
+entry contains a vm_domain_policy with the following fields:
+.Bd -literal
+struct vm_domain_policy {
+ seq_t seq; /* sequence number, used internally by kernel */
+ vm_domain_policy_type_t policy; /* VM policy */
+ int domain; /* VM domain, if applicable */
+}
+.Ed
+.Fa vm_domain_policy_type_t policy
+is one these:
+.Bl -tag -width VM_POLICY_NONE
+.It Dv VM_POLICY_NONE
+Reset the domain back to none.
+Any parent object NUMA domain policy will apply.
+The only valid value for
+.Dv domain
+is -1.
+.It Dv VM_POLICY_ROUND_ROBIN
+Select round-robin policy.
+Pages will be allocated round-robin from each VM domain in order.
+The only valid value for
+.Dv domain
+is -1.
+.It Dv VM_POLICY_FIXED_DOMAIN
+Select fixed-domain only policy.
+Pages will be allocated from the given
+.Dv domain
+which must be set to a valid VM domain.
+Pages will not be allocated from another domain if
+.Dv domain
+is out of free pages.
+.It Dv VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN
+Select fixed-domain only policy.
+Pages will be allocated from
+.Dv domain
+which must be set to a valid VM domain.
+If page allocation fails, pages will be round-robin
+allocated from another domain if
+.Dv domain
+is out of free pages.
+.It Dv VM_POLICY_FIRST_TOUCH
+Select first-touch policy.
+Pages will be allocated from the NUMA domain which the thread
+is currently scheduled upon.
+Pages will not be allocated from another domain if the current domain
+is out of free pages.
+The only valid value for
+.Dv domain
+is -1.
+.It Dv VM_POLICY_FIRST_TOUCH_ROUND_ROBIN
+Select first-touch policy.
+Pages will be allocated from the NUMA domain which the thread
+is currently scheduled upon.
+Pages will be allocated round-robin from another domain if the
+current domain is out of free pages.
+The only valid value for
+.Dv domain
+is -1.
+.El
+.Pp
+Note that the VM might assign some pages from other domains.
+For example, if an existing page allocation is covered by a superpage
+allocation.
+.Pp
+.Fn numa_getaffinity
+retrieves the
+NUMA policy from the object specified by
+.Fa which
+and
+.Fa id
+and stores it in the space provided by
+.Fa policy .
+.Pp
+.Fn numa_setaffinity
+attempts to set the NUMA policy for the object specified by
+.Fa which
+and
+.Fa id
+to the policy in
+.Fa policy .
+.Sh RETURN VALUES
+.Rv -std
+.Sh ERRORS
+.Va errno
+can contain these error codes:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa level
+or
+.Fa which
+argument was not a valid value.
+.It Bq Er EINVAL
+The
+.Fa policy
+argument specified when calling
+.Fn numa_setaffinity
+did not contain a valid policy.
+.It Bq Er EFAULT
+The policy pointer passed was invalid.
+.It Bq Er ESRCH
+The object specified by the
+.Fa id
+and
+.Fa which
+arguments could not be found.
+.It Bq Er ERANGE
+The
+.Fa domain
+in the given policy
+was out of the range of possible VM domains available.
+.It Bq Er EPERM
+The calling process did not have the credentials required to complete the
+operation.
+.El
+.Sh SEE ALSO
+.Xr cpuset 1 ,
+.Xr numactl 1 ,
+.Xr cpuset 2 ,
+.Xr cpuset_getaffinity 2 ,
+.Xr cpuset_getid 2 ,
+.Xr cpuset_setaffinity 2 ,
+.Xr cpuset_setid 2 ,
+.Xr pthread_affinity_np 3 ,
+.Xr pthread_attr_affinity_np 3 ,
+.Xr numa 4
+.Sh HISTORY
+The
+.Nm
+family of system calls first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An Adrian Chadd Aq Mt adrian@FreeBSD.org
Index: share/man/man4/Makefile
===================================================================
--- share/man/man4/Makefile
+++ share/man/man4/Makefile
@@ -363,6 +363,7 @@
nsp.4 \
${_ntb.4} \
null.4 \
+ numa.4 \
${_nvd.4} \
${_nvme.4} \
${_nvram.4} \
Index: share/man/man4/numa.4
===================================================================
--- /dev/null
+++ share/man/man4/numa.4
@@ -0,0 +1,172 @@
+.\" 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.
+.\" 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 AUTHORS AND CONTRIBUTORS ``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 AUTHORS OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 10, 2015
+.Dt NUMA 4
+.Os
+.Sh NAME
+.Nm NUMA
+.Nd Non-Uniform Memory Access
+.Sh SYNOPSIS
+.Cd options SMP
+.Cd options MAXMEMDOM=16
+.Pp
+.In sys/numa.h
+.In sys/cpuset.h
+.In sys/bus.h
+.Sh DESCRIPTION
+Non-Uniform Memory Access is a computer architecture design which
+involves unequal costs between processors, memory and IO devices
+in a given system.
+.Pp
+In a
+.Nm
+architecture, the latency to access specific memory or IO devices
+depends upon which processor the memory or device is attached to.
+Accessing memory local to a processor is faster than accessing memory
+that is connected to one of the other processors.
+.Pp
+.Nm
+is enabled when the
+.Cd MAXMEMDOM
+option is used in a kernel configuration
+file and is set to a value greater than 1.
+.Pp
+Thread and process
+.Nm
+policies are controlled with the
+.Xr numa_setaffinity 2
+and
+.Xr numa_getaffinity 2
+syscalls.
+.Pp
+The
+.Xr numactl 1
+tool is available for starting processes with a non-default
+policy, or to change the policy of an existing thread or process.
+.Pp
+Systems with non-uniform access to I/O devices may mark those devices
+with the local VM domain identifier.
+Drivers can find out their local domain information by calling
+.Xr bus_get_domain 9 .
+.Ss MIB Variables
+The operation of
+.Nm
+is controlled and exposes information with these
+.Xr sysctl 8
+MIB variables:
+.Pp
+.Bl -tag -width indent -compact
+.It Va vm.ndomains
+The number of VM domains which have been detected.
+.Pp
+.It Va vm.default_policy
+The default VM domain allocation policy.
+Defaults to "first-touch-rr".
+The valid values are "first-touch", "first-touch-rr",
+"rr", where "rr" is a short-hand for "round-robin."
+See
+.Xr numa_setaffinity 2
+for more information about the available policies.
+.Pp
+.It Va vm.phys_locality
+A table indicating the relative cost of each VM domain to each other.
+A value of 10 indicates equal cost.
+A value of -1 means the locality map is not available or no
+locality information is available.
+.Pp
+.It Va vm.phys_segs
+The map of physical memory, grouped by VM domain.
+.El
+.Sh IMPLEMENTATION NOTES
+The current
+.Nm
+implementation is VM-focused.
+The hardware
+.Nm
+domains are mapped into a contiguous, non-sparse
+VM domain space, starting from 0.
+Thus, VM domain information (for example, the domain identifier) is not
+necessarily the same as is found in the hardware specific information.
+.Pp
+The
+.Nm
+allocation policies are implemented as a policy and iterator in
+.Pa sys/vm/vm_domain.c
+and
+.Pa sys/vm/vm_domain.h .
+Policy information is available in both struct thread and struct proc.
+Processes inherit
+.Nm
+policy from parent processes and threads inherit
+.Nm
+policy from parent threads.
+Note that threads do not explicitly inherit their
+.Nm
+policy from processes.
+Instead, if no thread policy is set, the system
+will fall back to the process policy.
+.Pp
+For now,
+.Nm
+domain policies only influence physical page allocation in
+.Pa sys/vm/vm_phys.c .
+This is useful for userland memory allocation, but not for kernel
+and driver memory allocation.
+These features will be implemented in future work.
+.Sh SEE ALSO
+.Xr numactl 1 ,
+.Xr numa_getaffinity 2 ,
+.Xr numa_setaffinity 2 ,
+.Xr bus_get_domain 9
+.Sh HISTORY
+.Nm
+first appeared in
+.Fx 9.0
+as a first-touch allocation policy with a fail-over to round-robin allocation
+and was not configurable.
+It was then modified in
+.Fx 10.0
+to implement a round-robin allocation policy and was also not configurable.
+.Pp
+The
+.Xr numa_getaffinity 2
+and
+.Xr numa_setaffinity 2
+syscalls first appeared in
+.Fx 11.0 .
+.Pp
+The
+.Xr numactl 1
+tool first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+This manual page written by
+.An Adrian Chadd Aq Mt adrian@FreeBSD.org .
+.Sh NOTES
+No statistics are kept to indicate how often
+.Nm
+allocation policies succeed or fail.
Index: sys/compat/freebsd32/freebsd32_syscall.h
===================================================================
--- sys/compat/freebsd32/freebsd32_syscall.h
+++ sys/compat/freebsd32/freebsd32_syscall.h
@@ -455,4 +455,6 @@
#define FREEBSD32_SYS_freebsd32_ppoll 545
#define FREEBSD32_SYS_freebsd32_futimens 546
#define FREEBSD32_SYS_freebsd32_utimensat 547
-#define FREEBSD32_SYS_MAXSYSCALL 548
+#define FREEBSD32_SYS_numa_getaffinity 548
+#define FREEBSD32_SYS_numa_setaffinity 549
+#define FREEBSD32_SYS_MAXSYSCALL 550
Index: sys/compat/freebsd32/freebsd32_syscalls.c
===================================================================
--- sys/compat/freebsd32/freebsd32_syscalls.c
+++ sys/compat/freebsd32/freebsd32_syscalls.c
@@ -581,4 +581,6 @@
"freebsd32_ppoll", /* 545 = freebsd32_ppoll */
"freebsd32_futimens", /* 546 = freebsd32_futimens */
"freebsd32_utimensat", /* 547 = freebsd32_utimensat */
+ "numa_getaffinity", /* 548 = numa_getaffinity */
+ "numa_setaffinity", /* 549 = numa_setaffinity */
};
Index: sys/compat/freebsd32/freebsd32_sysent.c
===================================================================
--- sys/compat/freebsd32/freebsd32_sysent.c
+++ sys/compat/freebsd32/freebsd32_sysent.c
@@ -618,4 +618,6 @@
{ AS(freebsd32_ppoll_args), (sy_call_t *)freebsd32_ppoll, AUE_POLL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 545 = freebsd32_ppoll */
{ AS(freebsd32_futimens_args), (sy_call_t *)freebsd32_futimens, AUE_FUTIMES, NULL, 0, 0, 0, SY_THR_STATIC }, /* 546 = freebsd32_futimens */
{ AS(freebsd32_utimensat_args), (sy_call_t *)freebsd32_utimensat, AUE_FUTIMESAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 547 = freebsd32_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 */
};
Index: sys/compat/freebsd32/freebsd32_systrace_args.c
===================================================================
--- sys/compat/freebsd32/freebsd32_systrace_args.c
+++ sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3327,6 +3327,24 @@
*n_args = 4;
break;
}
+ /* numa_getaffinity */
+ case 548: {
+ struct numa_getaffinity_args *p = params;
+ iarg[0] = p->which; /* cpuwhich_t */
+ iarg[1] = p->id; /* id_t */
+ uarg[2] = (intptr_t) p->policy; /* struct vm_domain_policy * */
+ *n_args = 3;
+ break;
+ }
+ /* numa_setaffinity */
+ case 549: {
+ struct numa_setaffinity_args *p = params;
+ iarg[0] = p->which; /* cpuwhich_t */
+ iarg[1] = p->id; /* id_t */
+ uarg[2] = (intptr_t) p->policy; /* const struct vm_domain_policy * */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -8923,6 +8941,38 @@
break;
};
break;
+ /* numa_getaffinity */
+ case 548:
+ switch(ndx) {
+ case 0:
+ p = "cpuwhich_t";
+ break;
+ case 1:
+ p = "id_t";
+ break;
+ case 2:
+ p = "struct vm_domain_policy *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* numa_setaffinity */
+ case 549:
+ switch(ndx) {
+ case 0:
+ p = "cpuwhich_t";
+ break;
+ case 1:
+ p = "id_t";
+ break;
+ case 2:
+ p = "const struct vm_domain_policy *";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -10811,6 +10861,16 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* numa_getaffinity */
+ case 548:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* numa_setaffinity */
+ case 549:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ sys/compat/freebsd32/syscalls.master
@@ -1074,3 +1074,9 @@
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); }
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -2984,6 +2984,7 @@
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
@@ -4012,6 +4013,7 @@
vm/vm_phys.c standard
vm/vm_radix.c standard
vm/vm_reserv.c standard
+vm/vm_domain.c standard
vm/vm_unix.c standard
vm/vm_zeroidle.c standard
vm/vnode_pager.c standard
Index: sys/dev/sound/midi/sequencer.c
===================================================================
--- sys/dev/sound/midi/sequencer.c
+++ sys/dev/sound/midi/sequencer.c
@@ -101,7 +101,7 @@
static d_open_t seq_open;
static d_close_t seq_close;
static d_ioctl_t seq_ioctl;
-static d_read_t seq_read;
+static d_read_t mseq_read;
static d_write_t seq_write;
static d_poll_t seq_poll;
@@ -109,7 +109,7 @@
.d_version = D_VERSION,
.d_open = seq_open,
.d_close = seq_close,
- .d_read = seq_read,
+ .d_read = mseq_read,
.d_write = seq_write,
.d_ioctl = seq_ioctl,
.d_poll = seq_poll,
@@ -858,7 +858,7 @@
}
int
-seq_read(struct cdev *i_dev, struct uio *uio, int ioflag)
+mseq_read(struct cdev *i_dev, struct uio *uio, int ioflag)
{
int retval, used;
struct seq_softc *scp = i_dev->si_drv1;
@@ -869,12 +869,12 @@
if (scp == NULL)
return ENXIO;
- SEQ_DEBUG(7, printf("seq_read: unit %d, resid %zd.\n",
+ SEQ_DEBUG(7, printf("mseq_read: unit %d, resid %zd.\n",
scp->unit, uio->uio_resid));
mtx_lock(&scp->seq_lock);
if ((scp->fflags & FREAD) == 0) {
- SEQ_DEBUG(2, printf("seq_read: unit %d is not for reading.\n",
+ SEQ_DEBUG(2, printf("mseq_read: unit %d is not for reading.\n",
scp->unit));
retval = EIO;
goto err1;
@@ -927,7 +927,7 @@
retval = 0;
err1:
mtx_unlock(&scp->seq_lock);
- SEQ_DEBUG(6, printf("seq_read: ret %d, resid %zd.\n",
+ SEQ_DEBUG(6, printf("mseq_read: ret %d, resid %zd.\n",
retval, uio->uio_resid));
return retval;
Index: sys/kern/init_main.c
===================================================================
--- sys/kern/init_main.c
+++ sys/kern/init_main.c
@@ -87,6 +87,7 @@
#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>
@@ -496,6 +497,12 @@
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);
prison0_init();
p->p_peers = 0;
p->p_leader = p;
Index: sys/kern/init_sysent.c
===================================================================
--- sys/kern/init_sysent.c
+++ sys/kern/init_sysent.c
@@ -588,4 +588,6 @@
{ 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 */
};
Index: sys/kern/kern_cpuset.c
===================================================================
--- sys/kern/kern_cpuset.c
+++ sys/kern/kern_cpuset.c
@@ -400,7 +400,7 @@
* -1 may be supplied for any argument to mean the current proc/thread or
* the base set of the current thread. May fail with ESRCH/EPERM.
*/
-static int
+int
cpuset_which(cpuwhich_t which, id_t id, struct proc **pp, struct thread **tdp,
struct cpuset **setp)
{
Index: sys/kern/kern_exit.c
===================================================================
--- sys/kern/kern_exit.c
+++ sys/kern/kern_exit.c
@@ -86,6 +86,7 @@
#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>
@@ -951,6 +952,11 @@
#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!"));
uma_zfree(proc_zone, p);
Index: sys/kern/kern_fork.c
===================================================================
--- sys/kern/kern_fork.c
+++ sys/kern/kern_fork.c
@@ -80,6 +80,7 @@
#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>
@@ -405,6 +406,7 @@
bcopy(&p1->p_startcopy, &p2->p_startcopy,
__rangeof(struct proc, p_startcopy, p_endcopy));
pargs_hold(p2->p_args);
+
PROC_UNLOCK(p1);
bzero(&p2->p_startzero,
@@ -498,6 +500,18 @@
startprofclock(p2);
td2->td_ucred = crhold(p2->p_ucred);
+ /*
+ * 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);
+ if (vm_domain_policy_localcopy(&p2->p_vm_dom_policy,
+ &p1->p_vm_dom_policy) != 0) {
+ /* failed; fall through to none */
+ vm_domain_policy_set(&p2->p_vm_dom_policy,
+ VM_POLICY_NONE, -1);
+ }
+
if (flags & RFSIGSHARE) {
p2->p_sigacts = sigacts_hold(p1->p_sigacts);
} else {
Index: sys/kern/kern_numa.c
===================================================================
--- /dev/null
+++ sys/kern/kern_numa.c
@@ -0,0 +1,174 @@
+/*-
+ * 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_phys.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 = NULL;
+
+ error = copyin(uap->policy, &vp, sizeof(vp));
+ 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:
+ if (vm_domain_policy_copy(&ttd->td_vm_dom_policy,
+ &vp) != 0) {
+ error = EINVAL; /* XXX */
+ goto out2;
+ }
+ break;
+ case CPU_WHICH_PID:
+ if (vm_domain_policy_copy(&p->p_vm_dom_policy,
+ &vp) != 0) {
+ error = EINVAL; /* XXX */
+ goto out2;
+ }
+ break;
+ default:
+ error = EINVAL;
+ goto out2;
+ }
+
+out2:
+ 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 = 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:
+ if (vm_domain_policy_localcopy(&vp,
+ &ttd->td_vm_dom_policy) != 0) {
+ error = EINVAL; /* XXX */
+ goto out2;
+ }
+ break;
+ case CPU_WHICH_PID:
+ if (vm_domain_policy_localcopy(&vp,
+ &p->p_vm_dom_policy) != 0) {
+ error = EINVAL; /* XXX */
+ goto out2;
+ }
+ break;
+ default:
+ error = EINVAL;
+ goto out2;
+ }
+
+ error = copyout(&vp, uap->policy, sizeof(vp));
+out2:
+ PROC_UNLOCK(p);
+out:
+ if (set)
+ cpuset_rel(set);
+ return (error);
+}
Index: sys/kern/kern_thr.c
===================================================================
--- sys/kern/kern_thr.c
+++ sys/kern/kern_thr.c
@@ -54,6 +54,8 @@
#include <sys/umtx.h>
#include <sys/limits.h>
+#include <vm/vm_domain.h>
+
#include <machine/frame.h>
#include <security/audit/audit.h>
@@ -254,6 +256,17 @@
thread_unlock(td);
if (P_SHOULDSTOP(p))
newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
+
+ /*
+ * Copy the existing thread VM policy into the new thread.
+ */
+ if (vm_domain_policy_localcopy(&newtd->td_vm_dom_policy,
+ &td->td_vm_dom_policy) != 0) {
+ /* failed; fall through to none */
+ vm_domain_policy_set(&newtd->td_vm_dom_policy,
+ VM_POLICY_NONE, -1);
+ }
+
PROC_UNLOCK(p);
tidhash_add(newtd);
Index: sys/kern/kern_thread.c
===================================================================
--- sys/kern/kern_thread.c
+++ sys/kern/kern_thread.c
@@ -60,6 +60,7 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/uma.h>
+#include <vm/vm_domain.h>
#include <sys/eventhandler.h>
SDT_PROVIDER_DECLARE(proc);
@@ -352,6 +353,7 @@
return (NULL);
}
cpu_thread_alloc(td);
+ vm_domain_policy_init(&td->td_vm_dom_policy);
return (td);
}
@@ -381,6 +383,7 @@
cpu_thread_free(td);
if (td->td_kstack != 0)
vm_thread_dispose(td);
+ vm_domain_policy_cleanup(&td->td_vm_dom_policy);
uma_zfree(thread_zone, td);
}
Index: sys/kern/syscalls.c
===================================================================
--- sys/kern/syscalls.c
+++ sys/kern/syscalls.c
@@ -555,4 +555,6 @@
"ppoll", /* 545 = ppoll */
"futimens", /* 546 = futimens */
"utimensat", /* 547 = utimensat */
+ "numa_getaffinity", /* 548 = numa_getaffinity */
+ "numa_setaffinity", /* 549 = numa_setaffinity */
};
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -988,5 +988,12 @@
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 *policy); }
+549 AUE_NULL STD { int numa_setaffinity(cpuwhich_t which, \
+ id_t id, \
+ const struct vm_domain_policy *policy); }
+
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: sys/kern/systrace_args.c
===================================================================
--- sys/kern/systrace_args.c
+++ sys/kern/systrace_args.c
@@ -3337,6 +3337,24 @@
*n_args = 4;
break;
}
+ /* numa_getaffinity */
+ case 548: {
+ struct numa_getaffinity_args *p = params;
+ iarg[0] = p->which; /* cpuwhich_t */
+ iarg[1] = p->id; /* id_t */
+ uarg[2] = (intptr_t) p->policy; /* struct vm_domain_policy * */
+ *n_args = 3;
+ break;
+ }
+ /* numa_setaffinity */
+ case 549: {
+ struct numa_setaffinity_args *p = params;
+ iarg[0] = p->which; /* cpuwhich_t */
+ iarg[1] = p->id; /* id_t */
+ uarg[2] = (intptr_t) p->policy; /* const struct vm_domain_policy * */
+ *n_args = 3;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -8883,6 +8901,38 @@
break;
};
break;
+ /* numa_getaffinity */
+ case 548:
+ switch(ndx) {
+ case 0:
+ p = "cpuwhich_t";
+ break;
+ case 1:
+ p = "id_t";
+ break;
+ case 2:
+ p = "struct vm_domain_policy *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* numa_setaffinity */
+ case 549:
+ switch(ndx) {
+ case 0:
+ p = "cpuwhich_t";
+ break;
+ case 1:
+ p = "id_t";
+ break;
+ case 2:
+ p = "const struct vm_domain_policy *";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -10806,6 +10856,16 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* numa_getaffinity */
+ case 548:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* numa_setaffinity */
+ case 549:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
Index: sys/sys/_vm_domain.h
===================================================================
--- /dev/null
+++ sys/sys/_vm_domain.h
@@ -0,0 +1,63 @@
+/*-
+ * 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 ___PRIV_VM_DOMAIN_H___
+#define ___PRIV_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 {
+ seq_t seq;
+ vm_domain_policy_type_t policy;
+ int domain;
+};
+
+struct vm_domain_iterator {
+ vm_domain_policy_type_t policy;
+ int domain;
+ int n;
+};
+
+#define VM_DOMAIN_POLICY_STATIC_INITIALISER(vt, vd) \
+ { .policy = vt, \
+ .seq = 0, \
+ .domain = vd }
+
+#endif /* ___PRIV_VM_DOMAIN_H___ */
Index: sys/sys/cpuset.h
===================================================================
--- sys/sys/cpuset.h
+++ sys/sys/cpuset.h
@@ -124,6 +124,9 @@
int cpuset_setithread(lwpid_t id, int cpu);
int cpuset_create_root(struct prison *, struct cpuset **);
int cpuset_setproc_update_set(struct proc *, struct cpuset *);
+int cpuset_which(cpuwhich_t, id_t, struct proc **,
+ struct thread **, struct cpuset **);
+
char *cpusetobj_strprint(char *, const cpuset_t *);
int cpusetobj_strscan(cpuset_t *, const char *);
#ifdef DDB
Index: sys/sys/numa.h
===================================================================
--- /dev/null
+++ sys/sys/numa.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015 Adrian Chadd <adrian@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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.
+ * 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.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+#ifndef __SYS_NUMA_H__
+#define __SYS_NUMA_H__
+
+#include <sys/_vm_domain.h>
+
+extern int numa_setaffinity(cpuwhich_t which, id_t id,
+ struct vm_domain_policy *vd);
+extern int numa_getaffinity(cpuwhich_t which, id_t id,
+ struct vm_domain_policy *vd);
+
+#endif /* __SYS_NUMA_H__ */
Index: sys/sys/proc.h
===================================================================
--- sys/sys/proc.h
+++ sys/sys/proc.h
@@ -63,6 +63,7 @@
#endif
#include <sys/ucontext.h>
#include <sys/ucred.h>
+#include <sys/_vm_domain.h>
#include <machine/proc.h> /* Machine-dependent proc substruct. */
/*
@@ -217,6 +218,7 @@
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
@@ -603,6 +605,7 @@
uint64_t p_prev_runtime; /* (c) Resource usage accounting. */
struct racct *p_racct; /* (b) Resource accounting. */
u_char 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
Index: sys/sys/syscall.h
===================================================================
--- sys/sys/syscall.h
+++ sys/sys/syscall.h
@@ -465,4 +465,6 @@
#define SYS_ppoll 545
#define SYS_futimens 546
#define SYS_utimensat 547
-#define SYS_MAXSYSCALL 548
+#define SYS_numa_getaffinity 548
+#define SYS_numa_setaffinity 549
+#define SYS_MAXSYSCALL 550
Index: sys/sys/syscall.mk
===================================================================
--- sys/sys/syscall.mk
+++ sys/sys/syscall.mk
@@ -412,4 +412,6 @@
procctl.o \
ppoll.o \
futimens.o \
- utimensat.o
+ utimensat.o \
+ numa_getaffinity.o \
+ numa_setaffinity.o
Index: sys/sys/sysproto.h
===================================================================
--- sys/sys/sysproto.h
+++ sys/sys/sysproto.h
@@ -1790,6 +1790,16 @@
char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)];
char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)];
};
+struct numa_getaffinity_args {
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id_l_[PADL_(id_t)]; id_t id; char id_r_[PADR_(id_t)];
+ char policy_l_[PADL_(struct vm_domain_policy *)]; struct vm_domain_policy * policy; char policy_r_[PADR_(struct vm_domain_policy *)];
+};
+struct numa_setaffinity_args {
+ char which_l_[PADL_(cpuwhich_t)]; cpuwhich_t which; char which_r_[PADR_(cpuwhich_t)];
+ char id_l_[PADL_(id_t)]; id_t id; char id_r_[PADR_(id_t)];
+ char policy_l_[PADL_(const struct vm_domain_policy *)]; const struct vm_domain_policy * policy; char policy_r_[PADR_(const struct vm_domain_policy *)];
+};
int nosys(struct thread *, struct nosys_args *);
void sys_sys_exit(struct thread *, struct sys_exit_args *);
int sys_fork(struct thread *, struct fork_args *);
@@ -2178,6 +2188,8 @@
int sys_ppoll(struct thread *, struct ppoll_args *);
int sys_futimens(struct thread *, struct futimens_args *);
int sys_utimensat(struct thread *, struct utimensat_args *);
+int sys_numa_getaffinity(struct thread *, struct numa_getaffinity_args *);
+int sys_numa_setaffinity(struct thread *, struct numa_setaffinity_args *);
#ifdef COMPAT_43
@@ -2931,6 +2943,8 @@
#define SYS_AUE_ppoll AUE_POLL
#define SYS_AUE_futimens AUE_FUTIMES
#define SYS_AUE_utimensat AUE_FUTIMESAT
+#define SYS_AUE_numa_getaffinity AUE_NULL
+#define SYS_AUE_numa_setaffinity AUE_NULL
#undef PAD_
#undef PADL_
Index: sys/vm/vm_domain.h
===================================================================
--- /dev/null
+++ sys/vm/vm_domain.h
@@ -0,0 +1,60 @@
+/*-
+ * 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>
+
+/*
+ * 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 int vm_domain_policy_localcopy(struct vm_domain_policy *dst,
+ const struct vm_domain_policy *src);
+extern int 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 int 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);
+
+#endif /* __VM_DOMAIN_H__ */
Index: sys/vm/vm_domain.c
===================================================================
--- /dev/null
+++ sys/vm/vm_domain.c
@@ -0,0 +1,399 @@
+/*-
+ * 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>
+#if MAXMEMDOM > 1
+#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>
+
+static __inline int
+vm_domain_rr_selectdomain(void)
+{
+#if MAXMEMDOM > 1
+ struct thread *td;
+
+ td = curthread;
+
+ td->td_dom_rr_idx++;
+ td->td_dom_rr_idx %= vm_ndomains;
+ return (td->td_dom_rr_idx);
+#else
+ return (0);
+#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->policy = VM_POLICY_NONE;
+ vp->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->policy = vt;
+ vp->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.
+ *
+ * Returns 0 + the policy copied if OK.
+ * Returns -1 if there was a problem.
+ */
+int
+vm_domain_policy_localcopy(struct vm_domain_policy *dst,
+ const struct vm_domain_policy *src)
+{
+ int i;
+ seq_t seq;
+
+ for (i = 0; i < 10; i++) {
+ seq = seq_read(&src->seq);
+ *dst = *src;
+ if (seq_consistent(&src->seq, seq))
+ return (0);
+ cpu_spinwait();
+ }
+
+ return (-1);
+}
+
+/*
+ * Take a write-barrier copy of a policy.
+ *
+ * The destination policy iswrite -barriered; this is used
+ * for doing copies into policies that may be read by other
+ * threads.
+ *
+ * Returns 0 + the policy copied if OK.
+ * Returns -1 if there was a problem.
+ */
+int
+vm_domain_policy_copy(struct vm_domain_policy *dst,
+ const struct vm_domain_policy *src)
+{
+ int i;
+ seq_t seq;
+ struct vm_domain_policy d;
+
+ for (i = 0; i < 10; i++) {
+ seq = seq_read(&src->seq);
+ d = *src;
+ if (seq_consistent(&src->seq, seq)) {
+ seq_write_begin(&dst->seq);
+ dst->domain = d.domain;
+ dst->policy = d.policy;
+ seq_write_end(&dst->seq);
+ return (0);
+ }
+ cpu_spinwait();
+ }
+
+ return (-1);
+}
+
+int
+vm_domain_policy_validate(const struct vm_domain_policy *vp)
+{
+
+ switch (vp->policy) {
+ case VM_POLICY_NONE:
+ case VM_POLICY_ROUND_ROBIN:
+ case VM_POLICY_FIRST_TOUCH:
+ case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
+ if (vp->domain == -1)
+ return (0);
+ return (-1);
+ case VM_POLICY_FIXED_DOMAIN:
+ case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
+ if (vp->domain >= 0 & vp->domain < vm_ndomains)
+ return (0);
+ 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)
+{
+
+ 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;
+ }
+ return (0);
+}
+
+/*
+ * Setup an iterator based on the given policy.
+ */
+static inline int
+_vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
+ const struct vm_domain_policy *vt)
+{
+ /*
+ * 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->policy) {
+ case VM_POLICY_FIXED_DOMAIN:
+ vi->policy = vt->policy;
+ vi->domain = vt->domain;
+ vi->n = 1;
+ break;
+ case VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN:
+ vi->policy = vt->policy;
+ vi->domain = vt->domain;
+ vi->n = vm_ndomains;
+ break;
+ case VM_POLICY_FIRST_TOUCH:
+ vi->policy = vt->policy;
+ vi->domain = PCPU_GET(domain);
+ vi->n = 1;
+ break;
+ case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
+ vi->policy = vt->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;
+ }
+
+ return (0);
+}
+
+int
+vm_domain_iterator_set_policy(struct vm_domain_iterator *vi,
+ const struct vm_domain_policy *vt)
+{
+ int count;
+ seq_t seq;
+ struct vm_domain_policy vt_lcl;
+
+ for (count = 0; count < 10; count++) {
+ seq = seq_read(&vt->seq);
+ vt_lcl = *vt;
+ if (seq_consistent(&vt->seq, seq))
+ break;
+ cpu_spinwait();
+ }
+
+ if (count < 10)
+ return (_vm_domain_iterator_set_policy(vi, &vt_lcl));
+
+ /*
+ * Default to round-robin policy.
+ */
+ vi->policy = VM_POLICY_ROUND_ROBIN;
+ vi->domain = -1;
+ vi->n = vm_ndomains;
+
+ return (0);
+}
+
+/*
+ * 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);
+
+ 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->n--;
+ break;
+ case VM_POLICY_ROUND_ROBIN:
+ default:
+ *domain = vm_domain_rr_selectdomain();
+ vi->n--;
+ break;
+ }
+
+ 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);
+}
Index: sys/vm/vm_page.c
===================================================================
--- sys/vm/vm_page.c
+++ sys/vm/vm_page.c
@@ -1625,6 +1625,7 @@
* vm_page_cache().
*/
mtx_lock_flags(&vm_page_queue_free_mtx, MTX_RECURSE);
+ m = NULL;
if (vm_cnt.v_free_count + vm_cnt.v_cache_count > vm_cnt.v_free_reserved ||
(req_class == VM_ALLOC_SYSTEM &&
vm_cnt.v_free_count + vm_cnt.v_cache_count > vm_cnt.v_interrupt_free_min) ||
@@ -1669,7 +1670,19 @@
}
#endif
}
- } else {
+ }
+
+ /*
+ * Can't allocate or attempted to and couldn't allocate a page
+ * given the current VM policy. Give up.
+ *
+ * Note - yes, this is one of the current shortcomings of the
+ * VM domain design - there's a global set of vm_cnt counters,
+ * and it's quite possible things will get unhappy with this.
+ * However without it'll kernel panic below - the code didn't
+ * check m == NULL here and would continue.
+ */
+ if (m == NULL) {
/*
* Not allocatable, give up.
*/
Index: sys/vm/vm_phys.c
===================================================================
--- sys/vm/vm_phys.c
+++ sys/vm/vm_phys.c
@@ -57,6 +57,7 @@
#include <sys/sysctl.h>
#include <sys/tree.h>
#include <sys/vmmeter.h>
+#include <sys/seq.h>
#include <ddb/ddb.h>
@@ -67,6 +68,8 @@
#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.");
@@ -141,13 +144,30 @@
SYSCTL_OID(_vm, OID_AUTO, phys_segs, CTLTYPE_STRING | CTLFLAG_RD,
NULL, 0, sysctl_vm_phys_segs, "A", "Phys Seg Info");
+#if MAXMEMDOM > 1
static int sysctl_vm_phys_locality(SYSCTL_HANDLER_ARGS);
SYSCTL_OID(_vm, OID_AUTO, phys_locality, CTLTYPE_STRING | CTLFLAG_RD,
NULL, 0, sysctl_vm_phys_locality, "A", "Phys Locality Info");
+#endif
SYSCTL_INT(_vm, OID_AUTO, ndomains, CTLFLAG_RD,
&vm_ndomains, 0, "Number of physical memory domains available.");
+/*
+ * 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);
+#if MAXMEMDOM > 1
+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 vm_page_t vm_phys_alloc_domain_pages(int domain, int flind, int pool,
int order);
static void _vm_phys_create_seg(vm_paddr_t start, vm_paddr_t end, int domain);
@@ -156,6 +176,60 @@
static void vm_phys_split_pages(vm_page_t m, int oind, struct vm_freelist *fl,
int order);
+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.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");
+
/*
* Red-black tree helpers for vm fictitious range management.
*/
@@ -213,6 +287,54 @@
#endif
}
+/*
+ * Initialise a VM domain iterator.
+ *
+ * Check the thread policy, then the proc policy,
+ * then default to the system policy.
+ *
+ * Later on the various layers will have this logic
+ * plumbed into them and the phys code will be explicitly
+ * handed a VM domain policy to use.
+ */
+static void
+vm_policy_iterator_init(struct vm_domain_iterator *vi)
+{
+#if MAXMEMDOM > 1
+ struct vm_domain_policy lcl;
+#endif
+
+ vm_domain_iterator_init(vi);
+
+#if MAXMEMDOM > 1
+ /* Attempt to copy out the thread policy */
+ if ((vm_domain_policy_localcopy(&lcl,
+ &curthread->td_vm_dom_policy) == 0) &&
+ (lcl.policy != VM_POLICY_NONE)) {
+ /* Thread policy is present; use it */
+ vm_domain_iterator_set_policy(vi, &lcl);
+ } else if ((vm_domain_policy_localcopy(&lcl,
+ &curthread->td_proc->p_vm_dom_policy) == 0) &&
+ (lcl.policy != VM_POLICY_NONE)) {
+ /* Process policy is present; use it */
+ vm_domain_iterator_set_policy(vi, &lcl);
+
+ } else {
+ /* Use system default policy */
+ vm_domain_iterator_set_policy(vi, &vm_default_policy);
+ }
+#else
+ vm_domain_iterator_set_policy(vi, &vm_default_policy);
+#endif
+}
+
+static void
+vm_policy_iterator_finish(struct vm_domain_iterator *vi)
+{
+
+ vm_domain_iterator_cleanup(vi);
+}
+
boolean_t
vm_phys_domain_intersects(long mask, vm_paddr_t low, vm_paddr_t high)
{
@@ -309,13 +431,18 @@
vm_phys_mem_affinity(int f, int t)
{
+#if MAXMEMDOM > 1
if (mem_locality == NULL)
return (-1);
if (f >= vm_ndomains || t >= vm_ndomains)
return (-1);
return (mem_locality[f * vm_ndomains + t]);
+#else
+ return (-1);
+#endif
}
+#if MAXMEMDOM > 1
/*
* Outputs the VM locality table.
*/
@@ -343,6 +470,7 @@
sbuf_delete(&sbuf);
return (error);
}
+#endif
static void
vm_freelist_add(struct vm_freelist *fl, vm_page_t m, int order, int tail)
@@ -634,15 +762,17 @@
vm_phys_alloc_pages(int pool, int order)
{
vm_page_t m;
- int dom, domain, flind;
+ int domain, flind;
+ struct vm_domain_iterator vi;
KASSERT(pool < VM_NFREEPOOL,
("vm_phys_alloc_pages: pool %d is out of range", pool));
KASSERT(order < VM_NFREEORDER,
("vm_phys_alloc_pages: order %d is out of range", order));
- for (dom = 0; dom < vm_ndomains; dom++) {
- domain = vm_rr_selectdomain();
+ vm_policy_iterator_init(&vi);
+
+ while ((vm_domain_iterator_run(&vi, &domain)) == 0) {
for (flind = 0; flind < vm_nfreelists; flind++) {
m = vm_phys_alloc_domain_pages(domain, flind, pool,
order);
@@ -650,6 +780,8 @@
return (m);
}
}
+
+ vm_policy_iterator_finish(&vi);
return (NULL);
}
@@ -664,7 +796,8 @@
vm_phys_alloc_freelist_pages(int freelist, int pool, int order)
{
vm_page_t m;
- int dom, domain;
+ struct vm_domain_iterator vi;
+ int domain;
KASSERT(freelist < VM_NFREELIST,
("vm_phys_alloc_freelist_pages: freelist %d is out of range",
@@ -673,13 +806,17 @@
("vm_phys_alloc_freelist_pages: pool %d is out of range", pool));
KASSERT(order < VM_NFREEORDER,
("vm_phys_alloc_freelist_pages: order %d is out of range", order));
- for (dom = 0; dom < vm_ndomains; dom++) {
- domain = vm_rr_selectdomain();
+
+ vm_policy_iterator_init(&vi);
+
+ while ((vm_domain_iterator_run(&vi, &domain)) == 0) {
m = vm_phys_alloc_domain_pages(domain,
vm_freelist_to_flind[freelist], pool, order);
if (m != NULL)
return (m);
}
+
+ vm_policy_iterator_finish(&vi);
return (NULL);
}
@@ -1169,7 +1306,8 @@
vm_paddr_t pa, pa_last, size;
vm_page_t m, m_ret;
u_long npages_end;
- int dom, domain, flind, oind, order, pind;
+ int domain, flind, oind, order, pind;
+ struct vm_domain_iterator vi;
mtx_assert(&vm_page_queue_free_mtx, MA_OWNED);
size = npages << PAGE_SHIFT;
@@ -1181,9 +1319,15 @@
("vm_phys_alloc_contig: boundary must be a power of 2"));
/* Compute the queue that is the best fit for npages. */
for (order = 0; (1 << order) < npages; order++);
- dom = 0;
+
+ vm_policy_iterator_init(&vi);
+
restartdom:
- domain = vm_rr_selectdomain();
+ if (vm_domain_iterator_run(&vi, &domain) != 0) {
+ vm_policy_iterator_finish(&vi);
+ return (NULL);
+ }
+
for (flind = 0; flind < vm_nfreelists; flind++) {
for (oind = min(order, VM_NFREEORDER - 1); oind < VM_NFREEORDER; oind++) {
for (pind = 0; pind < VM_NFREEPOOL; pind++) {
@@ -1241,8 +1385,9 @@
}
}
}
- if (++dom < vm_ndomains)
+ if (!vm_domain_iterator_isdone(&vi))
goto restartdom;
+ vm_policy_iterator_finish(&vi);
return (NULL);
done:
for (m = m_ret; m < &m_ret[npages]; m = &m[1 << oind]) {
Index: usr.bin/Makefile
===================================================================
--- usr.bin/Makefile
+++ usr.bin/Makefile
@@ -117,6 +117,7 @@
nice \
nl \
${_nm} \
+ numactl \
nohup \
opieinfo \
opiekey \
Index: usr.bin/numactl/Makefile
===================================================================
--- /dev/null
+++ usr.bin/numactl/Makefile
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+PROG= numactl
+
+.include <bsd.prog.mk>
Index: usr.bin/numactl/numactl.1
===================================================================
--- /dev/null
+++ usr.bin/numactl/numactl.1
@@ -0,0 +1,132 @@
+.\" 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.
+.\" 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 9, 2015
+.Dt NUMACTL 1
+.Os
+.Sh NAME
+.Nm numactl
+.Nd "manage NUMA policy configuration"
+.Sh SYNOPSIS
+.Nm
+.Op Fl -mempolicy Ar policy
+.Op Fl -memdomain Ar domain
+.Op Fl -cpudomain Ar domain
+.Ar cmd ...
+.Nm
+.Fl -get
+.Op Fl -tid Ar tid
+.Op Fl -pid Ar tid
+.Nm
+.Fl -set
+.Op Fl -mempolicy Ar policy
+.Op Fl -memdomain Ar domain
+.Op Fl -cpudomain Ar domain
+.Op Fl -tid Ar tid
+.Op Fl -pid Ar tid
+.Sh DESCRIPTION
+The
+.Nm
+command can be used to assign NUMA policies to processes/threads,
+run commands with a given NUMA policy, and query information
+about NUMA policies on running processes.
+.Pp
+.Nm
+requires a target to modify or query.
+The target may be specified as a command, process id or a thread id.
+Using
+.Fl -get
+the target's NUMA policy may be queried.
+Using
+.Fl -set
+the target's NUMA policy may be queried.
+If no target is specified,
+.Nm
+operates on itself.
+Not all combinations of operations and targets are supported.
+For example,
+you may not set the id of an existing set or query and launch a command
+at the same time.
+.Pp
+Each process and thread has a NUMA policy.
+By default the policy is NONE.
+If a thread policy is NONE, then the policy will fall back to the process.
+If the process policy is NONE, then the policy will fall back to the
+system default.
+The policy may be queried by using
+.Fl -get.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl -cpudomain Ar domain"
+.It Fl -cpudomain Ar domain
+Set the given CPU scheduling policy.
+Constrain the the object (tid, pid, command) to run on CPUs
+that belong to the given domain.
+.It Fl -get
+Retrieve the NUMA policy for the given thread or process id.
+.It Fl -set
+Set the NUMA policy for the given thread or process id.
+.It Fl -memdomain Ar domain
+Constrain the object (tid, pid, command) to the given
+domain.
+This is only valid for fixed-domain and fixed-domain-rr.
+It must not be set for other policies.
+.It Fl -mempolicy Ar policy
+Set the given memory allocation policy.
+Valid policies are none, rr, fixed-domain, fixed-domain-rr,
+first-touch, and first-touch-rr.
+A memdomain argument is required for fixed-domain and
+fixed-domain-rr.
+.It Fl -pid Ar pid
+Operate on the given pid.
+.It Fl -tid Ar tid
+Operate on the given tid.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Create a
+.Pa /bin/sh
+process with memory coming from domain 0, but
+CPUs coming from domain 1:
+.Dl numactl --mempolicy=fixed-domain --memdomain=0 --cpudomain=1 /bin/sh
+.Pp
+Query the NUMA policy for the
+.Aq sh pid :
+.Dl numactl --get --pid=<sh pid>
+.Pp
+Set the NUMA policy for the given TID to round-robin:
+.Dl numactl --set --mempolicy=rr --tid=<tid>
+.Sh SEE ALSO
+.Xr cpuset 2 ,
+.Xr numa 4
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An Adrian Chadd Aq Mt adrian@FreeBSD.org
Index: usr.bin/numactl/numactl.c
===================================================================
--- /dev/null
+++ usr.bin/numactl/numactl.c
@@ -0,0 +1,293 @@
+/*
+ * 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.
+ * 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 REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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/types.h>
+#include <sys/time.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <sysexits.h>
+
+#include <sys/resource.h>
+#include <sys/cpuset.h>
+#include <sys/numa.h>
+
+enum {
+ OPT_TID = 1001,
+ OPT_PID,
+ OPT_MEMDOMAIN,
+ OPT_CPUDOMAIN,
+ OPT_MEMPOLICY,
+ OPT_SET,
+ OPT_GET
+};
+
+static struct option longopts[] = {
+ { "tid", required_argument, NULL, OPT_TID },
+ { "pid", required_argument, NULL, OPT_PID },
+ { "memdomain", required_argument, NULL, OPT_MEMDOMAIN },
+ { "cpudomain", required_argument, NULL, OPT_CPUDOMAIN },
+ { "mempolicy", required_argument, NULL, OPT_MEMPOLICY },
+ { "set", no_argument, NULL, OPT_SET },
+ { "get", no_argument, NULL, OPT_GET },
+ { NULL, 0, NULL, 0 }
+};
+
+static const char *
+policy_to_str(vm_domain_policy_type_t vt)
+{
+ 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:
+ return ("first-touch");
+ case VM_POLICY_FIRST_TOUCH_ROUND_ROBIN:
+ return ("first-touch-rr");
+ default:
+ return ("unknown");
+ }
+}
+
+static int
+parse_policy(struct vm_domain_policy *vd, const char *str)
+{
+
+ if (strcmp(str, "rr") == 0) {
+ vd->policy = VM_POLICY_ROUND_ROBIN;
+ vd->domain = -1;
+ vd->seq = 0;
+ return (0);
+ }
+
+ if (strcmp(str, "first-touch-rr") == 0) {
+ vd->policy = VM_POLICY_FIRST_TOUCH_ROUND_ROBIN;
+ vd->domain = -1;
+ vd->seq = 0;
+ return (0);
+ }
+
+ if (strcmp(str, "first-touch") == 0) {
+ vd->policy = VM_POLICY_FIRST_TOUCH;
+ vd->domain = -1;
+ vd->seq = 0;
+ return (0);
+ }
+
+ if (strcmp(str, "fixed-domain") == 0) {
+ vd->policy = VM_POLICY_FIXED_DOMAIN;
+ vd->domain = 0;
+ vd->seq = 0;
+ return (0);
+ }
+
+ if (strcmp(str, "fixed-domain-rr") == 0) {
+ vd->policy = VM_POLICY_FIXED_DOMAIN_ROUND_ROBIN;
+ vd->domain = 0;
+ vd->seq = 0;
+ return (0);
+ }
+
+ return (-1);
+}
+
+static void
+usage(void)
+{
+
+ printf("usage: numactl --get [--tid=<tid>] [--pid=<pid>]\n");
+ printf(" numactl --set [--tid=<tid>] [--pid=<pid>]\n");
+ printf(" [--mempolicy=<policy>] [--memdomain=<domain>]\n");
+ printf(" [--cpudomain=<domain>]\n");
+ printf(" numactl [--mempolicy=<policy>] [--memdomain=<domain>]\n");
+ printf(" [--cpudomain=<domain>] <cmd> ...\n");
+
+ exit(EX_USAGE);
+}
+
+static int
+set_numa_domain_cpuaffinity(int cpu_domain)
+{
+ int error;
+ cpuset_t set;
+ error = cpuset_getaffinity(CPU_LEVEL_WHICH,
+ CPU_WHICH_DOMAIN,
+ cpu_domain,
+ sizeof(set),
+ &set);
+ if (error != 0)
+ err(EXIT_FAILURE, "cpuset_getaffinity");
+ error = cpuset_setaffinity(CPU_LEVEL_WHICH,
+ CPU_WHICH_PID,
+ -1,
+ sizeof(set),
+ &set);
+ if (error != 0)
+ err(EXIT_FAILURE, "cpuset_setaffinity");
+
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ id_t id;
+ cpuwhich_t which;
+ struct vm_domain_policy vd;
+ int error;
+ int is_set = 0, is_get = 0;
+ int mem_policy_set = 0;
+ lwpid_t tid = -1;
+ pid_t pid = -1;
+ int ch;
+ int cpu_domain = -1;
+
+ while ((ch = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
+ switch (ch) {
+ case OPT_TID:
+ tid = atoi(optarg);
+ break;
+ case OPT_PID:
+ pid = atoi(optarg);
+ break;
+ case OPT_CPUDOMAIN:
+ cpu_domain = atoi(optarg);
+ break;
+ case OPT_MEMDOMAIN:
+ if (mem_policy_set == 0) {
+ fprintf(stderr, "Error: set policy first before domain\n");
+ exit(EXIT_FAILURE);
+ }
+ vd.domain = atoi(optarg);
+ break;
+ case OPT_MEMPOLICY:
+ if (parse_policy(&vd, optarg) != 0) {
+ fprintf(stderr, "Could not parse policy: '%s'\n", optarg);
+ exit(EXIT_FAILURE);
+ }
+ mem_policy_set = 1;
+ break;
+ case OPT_SET:
+ is_set = 1;
+ break;
+ case OPT_GET:
+ is_get = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Handle the user wishing to run a command */
+ if (argc) {
+ /* Ensure that a policy was set */
+ if (mem_policy_set == 0) {
+ fprintf(stderr, "Error: no policy given\n");
+ usage();
+ }
+
+ /* Set current memory process policy, will be inherited */
+ if (numa_setaffinity(CPU_WHICH_PID, -1, &vd) != 0)
+ err(EXIT_FAILURE, "numa_setaffinity");
+
+ /* If a CPU domain policy was given, include that too */
+ if (cpu_domain != -1)
+ (void) set_numa_domain_cpuaffinity(cpu_domain);
+
+ errno = 0;
+ execvp(*argv, argv);
+ err(errno == ENOENT ? 127 : 126, "%s", *argv);
+ }
+
+ /* Figure out which */
+ if (tid != -1) {
+ which = CPU_WHICH_TID;
+ id = tid;
+ } else if (pid != -1) {
+ which = CPU_WHICH_PID;
+ id = pid;
+ }
+
+ /* Sanity checks */
+ if (is_set && is_get) {
+ fprintf(stderr, "Error: can't set both 'set' and 'get'\n");
+ usage();
+ }
+
+ if (is_set && ! mem_policy_set) {
+ fprintf(stderr, "Error: --set given, but no policy\n");
+ usage();
+ }
+
+ if (tid == -1 && pid == -1) {
+ fprintf(stderr, "Error: no TID or PID given\n");
+ usage();
+ }
+
+ /* If it's get, then get the policy and return */
+ if (is_get) {
+ error = numa_getaffinity(which, id, &vd);
+ if (error != 0)
+ err(EXIT_FAILURE, "numa_getaffinity");
+ printf(" Policy: %s; domain: %d\n",
+ policy_to_str(vd.policy),
+ vd.domain);
+ exit(EXIT_SUCCESS);
+ }
+
+ /* Assume it's set */
+
+ /* Syscall */
+ error = numa_setaffinity(which, id, &vd);
+ if (error != 0)
+ err(EXIT_FAILURE, "numa_setaffinity");
+
+ /* If a CPU domain policy was given, include that too */
+ if (cpu_domain != -1)
+ (void) set_numa_domain_cpuaffinity(cpu_domain);
+
+ exit(EXIT_SUCCESS);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Aug 27, 10:58 PM (11 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29475120
Default Alt Text
D2559.1787871531.diff (71 KB)
Attached To
Mode
D2559: Add initial process/thread NUMA policy configuration and management utility
Attached
Detach File
Event Timeline
Log In to Comment