From owner-svn-src-user@freebsd.org Wed Jan 3 01:00:49 2018 Return-Path: Delivered-To: svn-src-user@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 17497E87A67 for ; Wed, 3 Jan 2018 01:00:49 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id C17187C0C6; Wed, 3 Jan 2018 01:00:48 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w0310lPs059382; Wed, 3 Jan 2018 01:00:47 GMT (envelope-from jeff@FreeBSD.org) Received: (from jeff@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w0310lxs059378; Wed, 3 Jan 2018 01:00:47 GMT (envelope-from jeff@FreeBSD.org) Message-Id: <201801030100.w0310lxs059378@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: jeff set sender to jeff@FreeBSD.org using -f From: Jeff Roberson Date: Wed, 3 Jan 2018 01:00:47 +0000 (UTC) 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 X-SVN-Group: user X-SVN-Commit-Author: jeff X-SVN-Commit-Paths: in user/jeff/numa: sys/kern sys/sys sys/vm usr.bin/cpuset X-SVN-Commit-Revision: 327507 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 03 Jan 2018 01:00:49 -0000 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 @@ -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)