Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Jan 2018 01:00:47 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r327507 - in user/jeff/numa: sys/kern sys/sys sys/vm usr.bin/cpuset
Message-ID:  <201801030100.w0310lxs059378@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Wed Jan  3 01:00:47 2018
New Revision: 327507
URL: https://svnweb.freebsd.org/changeset/base/327507

Log:
  Implement a preferred domain policy

Modified:
  user/jeff/numa/sys/kern/kern_cpuset.c
  user/jeff/numa/sys/sys/domainset.h
  user/jeff/numa/sys/vm/vm_domainset.c
  user/jeff/numa/usr.bin/cpuset/cpuset.c

Modified: user/jeff/numa/sys/kern/kern_cpuset.c
==============================================================================
--- user/jeff/numa/sys/kern/kern_cpuset.c	Wed Jan  3 01:00:20 2018	(r327506)
+++ user/jeff/numa/sys/kern/kern_cpuset.c	Wed Jan  3 01:00:47 2018	(r327507)
@@ -127,6 +127,8 @@ SYSCTL_INT(_kern_sched, OID_AUTO, cpusetsize, CTLFLAG_
 cpuset_t *cpuset_root;
 cpuset_t cpuset_domain[MAXMEMDOM];
 
+static int domainset_valid(const struct domainset *, const struct domainset *);
+
 /*
  * Find the first non-anonymous set starting from 'set'.
  */
@@ -289,7 +291,7 @@ _cpuset_create(struct cpuset *set, struct cpuset *pare
 	if (!CPU_OVERLAP(&parent->cs_mask, mask))
 		return (EDEADLK);
 	/* The domain must be prepared ahead of time. */
-	if (!DOMAINSET_SUBSET(&parent->cs_domain->ds_mask, &domain->ds_mask))
+	if (!domainset_valid(parent->cs_domain, domain))
 		return (EDEADLK);
 	CPU_COPY(mask, &set->cs_mask);
 	LIST_INIT(&set->cs_children);
@@ -402,6 +404,7 @@ domainset_copy(const struct domainset *from, struct do
 
 	DOMAINSET_COPY(&from->ds_mask, &to->ds_mask);
 	to->ds_policy = from->ds_policy;
+	to->ds_prefer = from->ds_prefer;
 }
 
 /* Return 1 if mask and policy are equal, otherwise 0. */
@@ -410,9 +413,19 @@ domainset_equal(const struct domainset *one, const str
 {
 
 	return (DOMAINSET_CMP(&one->ds_mask, &two->ds_mask) == 0 &&
-	    one->ds_policy == two->ds_policy);
+	    one->ds_policy == two->ds_policy &&
+	    one->ds_prefer == two->ds_prefer);
 }
 
+/* Return 1 if child is a valid subset of parent. */
+static int
+domainset_valid(const struct domainset *parent, const struct domainset *child)
+{
+	if (child->ds_policy != DOMAINSET_POLICY_PREFER)
+		return (DOMAINSET_SUBSET(&parent->ds_mask, &child->ds_mask));
+	return (DOMAINSET_ISSET(child->ds_prefer, &parent->ds_mask));
+}
+
 /*
  * Lookup or create a domainset.  The key is provided in ds_mask and
  * ds_policy.  If the domainset does not yet exist the storage in
@@ -705,12 +718,17 @@ cpuset_modify_domain(struct cpuset *set, struct domain
 		/*
 		 * Verify that we have access to this set of domains.
 		 */
-		if (root &&
-		    !DOMAINSET_SUBSET(&dset->ds_mask, &domain->ds_mask)) {
+		if (root && !domainset_valid(dset, domain)) {
 			error = EINVAL;
 			goto out;
 		}
 		/*
+		 * If applying prefer we keep the current set as the fallback.
+		 */
+		if (domain->ds_policy == DOMAINSET_POLICY_PREFER)
+			DOMAINSET_COPY(&set->cs_domain->ds_mask,
+			    &domain->ds_mask);
+		/*
 		 * Determine whether we can apply this set of domains and
 		 * how many new domain structures it will require.
 		 */
@@ -842,8 +860,7 @@ cpuset_testshadow(struct cpuset *set, const cpuset_t *
 	 * parent or invalid domains have been specified.
 	 */
 	dset = parent->cs_domain;
-	if (domain != NULL &&
-	    !DOMAINSET_SUBSET(&dset->ds_mask, &domain->ds_mask))
+	if (domain != NULL && !domainset_valid(dset, domain))
 		return (EINVAL);
 
 	return (0);
@@ -1315,6 +1332,7 @@ domainset_zero(void)
 	for (i = 0; i < vm_ndomains; i++)
 		DOMAINSET_SET(i, &dset->ds_mask);
 	dset->ds_policy = DOMAINSET_POLICY_ROUNDROBIN;
+	dset->ds_prefer = -1;
 	curthread->td_domain.dr_policy = _domainset_create(dset, NULL);
 	kernel_object->domain.dr_policy = curthread->td_domain.dr_policy;
 }
@@ -1841,13 +1859,13 @@ int
 kern_cpuset_getdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
     id_t id, size_t domainsetsize, domainset_t *maskp, int *policyp)
 {
+	struct domainset outset;
 	struct thread *ttd;
 	struct cpuset *nset;
 	struct cpuset *set;
 	struct domainset *dset;
 	struct proc *p;
 	domainset_t *mask;
-	int policy;
 	int error;
 	size_t size;
 
@@ -1863,9 +1881,9 @@ kern_cpuset_getdomain(struct thread *td, cpulevel_t le
 	    if (id != -1)
 		return (ECAPMODE);
 	}
-	policy = 0;
 	size = domainsetsize;
 	mask = malloc(size, M_TEMP, M_WAITOK | M_ZERO);
+	bzero(&outset, sizeof(outset));
 	error = cpuset_which(which, id, &p, &ttd, &set);
 	if (error)
 		goto out;
@@ -1894,9 +1912,7 @@ kern_cpuset_getdomain(struct thread *td, cpulevel_t le
 		else
 			nset = cpuset_refbase(set);
 		/* Fetch once for a coherent result. */
-		dset = nset->cs_domain;
-		DOMAINSET_COPY(&dset->ds_mask, mask);
-		policy = dset->ds_policy;
+		domainset_copy(nset->cs_domain, &outset);
 		cpuset_rel(nset);
 		break;
 	case CPU_LEVEL_WHICH:
@@ -1904,9 +1920,7 @@ kern_cpuset_getdomain(struct thread *td, cpulevel_t le
 		case CPU_WHICH_TID:
 			thread_lock(ttd);
 			/* Fetch once for a coherent result. */
-			dset = ttd->td_cpuset->cs_domain;
-			DOMAINSET_COPY(&dset->ds_mask, mask);
-			policy = dset->ds_policy;
+			domainset_copy(ttd->td_cpuset->cs_domain, &outset);
 			thread_unlock(ttd);
 			break;
 		case CPU_WHICH_PID:
@@ -1914,17 +1928,16 @@ kern_cpuset_getdomain(struct thread *td, cpulevel_t le
 				thread_lock(ttd);
 				dset = ttd->td_cpuset->cs_domain;
 				/* Show all domains in the proc. */
-				DOMAINSET_OR(mask, &dset->ds_mask);
+				DOMAINSET_OR(&outset.ds_mask, &dset->ds_mask);
 				/* Last policy wins. */
-				policy = dset->ds_policy;
+				outset.ds_policy = dset->ds_policy;
+				outset.ds_prefer = dset->ds_prefer;
 				thread_unlock(ttd);
 			}
 			break;
 		case CPU_WHICH_CPUSET:
 		case CPU_WHICH_JAIL:
-			dset = set->cs_domain;
-			policy = dset->ds_policy;
-			DOMAINSET_OR(mask, &dset->ds_mask);
+			domainset_copy(set->cs_domain, &outset);
 			break;
 		case CPU_WHICH_IRQ:
 		case CPU_WHICH_INTRHANDLER:
@@ -1942,10 +1955,19 @@ kern_cpuset_getdomain(struct thread *td, cpulevel_t le
 		cpuset_rel(set);
 	if (p)
 		PROC_UNLOCK(p);
+	/*
+	 * Translate prefer into a set containing only the preferred domain,
+	 * not the entire fallback set.
+	 */
+	if (outset.ds_policy == DOMAINSET_POLICY_PREFER) {
+		DOMAINSET_ZERO(&outset.ds_mask);
+		DOMAINSET_SET(outset.ds_prefer, &outset.ds_mask);
+	}
+	DOMAINSET_COPY(&outset.ds_mask, mask);
 	if (error == 0)
 		error = copyout(mask, maskp, size);
 	if (error == 0)
-		error = copyout(&policy, policyp, sizeof(*policyp));
+		error = copyout(&outset.ds_policy, policyp, sizeof(*policyp));
 out:
 	free(mask, M_TEMP);
 	return (error);
@@ -2022,6 +2044,16 @@ kern_cpuset_setdomain(struct thread *td, cpulevel_t le
 	    policy > DOMAINSET_POLICY_MAX)
 		return (EINVAL);
 
+	/* Translate preferred policy into a mask and fallback. */
+	if (policy == DOMAINSET_POLICY_PREFER) {
+		/* Only support a single preferred domain. */
+		if (DOMAINSET_COUNT(&domain.ds_mask) != 1)
+			return (EINVAL);
+		domain.ds_prefer = DOMAINSET_FFS(&domain.ds_mask) - 1;
+		/* This will be constrained by domainset_shadow(). */
+		DOMAINSET_FILL(&domain.ds_mask);
+	}
+
 	switch (level) {
 	case CPU_LEVEL_ROOT:
 	case CPU_LEVEL_CPUSET:
@@ -2130,8 +2162,8 @@ DB_SHOW_COMMAND(cpusets, db_show_cpusets)
 		db_printf("  cpu mask=");
 		ddb_display_cpuset(&set->cs_mask);
 		db_printf("\n");
-		db_printf("  domain policy %d mask=",
-		    set->cs_domain->ds_policy);
+		db_printf("  domain policy %d prefer %d mask=",
+		    set->cs_domain->ds_policy, set->cs_domain->ds_prefer);
 		ddb_display_domainset(&set->cs_domain->ds_mask);
 		db_printf("\n");
 		if (db_pager_quit)
@@ -2144,8 +2176,9 @@ DB_SHOW_COMMAND(domainsets, db_show_domainsets)
 	struct domainset *set;
 
 	LIST_FOREACH(set, &cpuset_domains, ds_link) {
-		db_printf("set=%p policy %d cnt %d max %d\n",
-		    set, set->ds_policy, set->ds_cnt, set->ds_max);
+		db_printf("set=%p policy %d prefer %d cnt %d max %d\n",
+		    set, set->ds_policy, set->ds_prefer, set->ds_cnt,
+		    set->ds_max);
 		db_printf("  mask =");
 		ddb_display_domainset(&set->ds_mask);
 		db_printf("\n");

Modified: user/jeff/numa/sys/sys/domainset.h
==============================================================================
--- user/jeff/numa/sys/sys/domainset.h	Wed Jan  3 01:00:20 2018	(r327506)
+++ user/jeff/numa/sys/sys/domainset.h	Wed Jan  3 01:00:47 2018	(r327507)
@@ -72,7 +72,8 @@
 #define	DOMAINSET_POLICY_INVALID	0
 #define	DOMAINSET_POLICY_ROUNDROBIN	1
 #define	DOMAINSET_POLICY_FIRSTTOUCH	2
-#define	DOMAINSET_POLICY_MAX		DOMAINSET_POLICY_FIRSTTOUCH
+#define	DOMAINSET_POLICY_PREFER		3
+#define	DOMAINSET_POLICY_MAX		DOMAINSET_POLICY_PREFER
 
 #ifdef _KERNEL
 #include <sys/queue.h>
@@ -81,9 +82,10 @@ LIST_HEAD(domainlist, domainset);
 struct domainset {
 	LIST_ENTRY(domainset)	ds_link;
 	domainset_t	ds_mask;	/* allowed domains. */
+	uint16_t	ds_policy;	/* Policy type. */
+	int16_t		ds_prefer;	/* Preferred domain or -1. */
 	uint16_t	ds_cnt;		/* popcnt from above. */
 	uint16_t	ds_max;		/* Maximum domain in set. */
-	uint16_t	ds_policy;	/* Policy type. */
 };
 
 void domainset_zero(void);

Modified: user/jeff/numa/sys/vm/vm_domainset.c
==============================================================================
--- user/jeff/numa/sys/vm/vm_domainset.c	Wed Jan  3 01:00:20 2018	(r327506)
+++ user/jeff/numa/sys/vm/vm_domainset.c	Wed Jan  3 01:00:47 2018	(r327507)
@@ -90,6 +90,19 @@ vm_domainset_iter_rr(struct vm_domainset_iter *di, int
 }
 
 static void
+vm_domainset_iter_prefer(struct vm_domainset_iter *di, int *domain)
+{
+	int d;
+
+	d = *di->di_iter;
+	do {
+		d = (d + 1) % di->di_domain->ds_max;
+	} while (!DOMAINSET_ISSET(d, &di->di_domain->ds_mask) || 
+	    d == di->di_domain->ds_prefer);
+	*di->di_iter = *domain = d;
+}
+
+static void
 vm_domainset_iter_next(struct vm_domainset_iter *di, int *domain)
 {
 
@@ -103,6 +116,9 @@ vm_domainset_iter_next(struct vm_domainset_iter *di, i
 	case DOMAINSET_POLICY_ROUNDROBIN:
 		vm_domainset_iter_rr(di, domain);
 		break;
+	case DOMAINSET_POLICY_PREFER:
+		vm_domainset_iter_prefer(di, domain);
+		break;
 	default:
 		panic("vm_domainset_iter_first: Unknown policy %d",
 		    di->di_domain->ds_policy);
@@ -130,6 +146,10 @@ vm_domainset_iter_first(struct vm_domainset_iter *di, 
 	case DOMAINSET_POLICY_ROUNDROBIN:
 		di->di_n = di->di_domain->ds_cnt;
 		vm_domainset_iter_rr(di, domain);
+		break;
+	case DOMAINSET_POLICY_PREFER:
+		*domain = di->di_domain->ds_prefer;
+		di->di_n = di->di_domain->ds_cnt;
 		break;
 	default:
 		panic("vm_domainset_iter_first: Unknown policy %d",

Modified: user/jeff/numa/usr.bin/cpuset/cpuset.c
==============================================================================
--- user/jeff/numa/usr.bin/cpuset/cpuset.c	Wed Jan  3 01:00:20 2018	(r327506)
+++ user/jeff/numa/usr.bin/cpuset/cpuset.c	Wed Jan  3 01:00:47 2018	(r327507)
@@ -78,6 +78,7 @@ static struct numa_policy policies[] = {
 	{ "rr", DOMAINSET_POLICY_ROUNDROBIN },
 	{ "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
 	{ "ft", DOMAINSET_POLICY_FIRSTTOUCH },
+	{ "prefer", DOMAINSET_POLICY_PREFER },
 	{ NULL, DOMAINSET_POLICY_INVALID }
 };
 
@@ -235,7 +236,8 @@ printset(struct bitset *mask, int size)
 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" };
+static const char *policynames[] = { "invalid", "round-robin", "first-touch",
+				    "prefer" };
 
 static void
 printaffinity(void)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201801030100.w0310lxs059378>