Index: lib/libutil/cpuset.3 =================================================================== --- lib/libutil/cpuset.3 +++ lib/libutil/cpuset.3 @@ -22,11 +22,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 31, 2017 +.Dd September 08, 2024 .Dt CPUSET 3 .Os .Sh NAME -.Nm cpuset_parselist +.Nm cpuset_parselist, +.Nm domainset_parselist .Nd utility functions for .Xr cpuset 2 handling @@ -37,6 +38,8 @@ .In libutil.h .Ft int .Fn cpuset_parselist "const char *cpu-list" "cpuset_t *mask" +.Ft int +.Fn domainset_parselist "const char *domain-policy" "domainset_t *domain_mask" "int *policyp" .Sh DESCRIPTION The .Fn cpuset_parselist @@ -52,6 +55,27 @@ A special list of .Dq all may be specified in which case the list includes all CPUs from the root set. +.Pp +The +.Fn domainset_parselist +function parses a +.Xr domainset 9 +memory domain allocation policy +specified by +.Va domain-policy +filling the +.Va domain_mask +and the +.Va policyp. +A valid +.Va domain-policy +is formatted as +.Ar policy:domain-list. +See the +.Ar -n +flag in +.Xr cpuset 1 +for a list of valid domain policies. .Sh RETURN VALUES Return values can be the following .Bl -tag -width Er @@ -60,19 +84,28 @@ .It Dv CPUSET_PARSE_ERROR The .Va cpu-list +or +.Va domain-policy format is invalid .It Dv CPUSET_PARSE_GETAFFINITY The .Xr cpuset_getaffinity 2 call has failed -.It Dv CPUSET_PARSE_INVALID_CPU -The number of supported CPUs has been exceeded. +.It Dv CPUSET_PARSE_OUT_OF_RANGE +The number of supported CPUs or NUMA domains has been exceeded. The maximum number being -.Va CPU_SETSIZE . +.Va CPU_SETSIZE and +.Va DOMAINSET_SETSIZE +respectively. +.It Dv CPUSET_PARSE_GETDOMAIN +The +.Xr cpuset_getdomain 2 +call has failed .El .Sh SEE ALSO .Xr cpuset 1 , .Xr cpuset 2 , -.Xr cpuset 9 +.Xr cpuset 9 , +.Xr domainset 9 , .Sh AUTHORS .An Jeffrey Roberson Aq Mt jeff@FreeBSD.org Index: lib/libutil/cpuset.c =================================================================== --- lib/libutil/cpuset.c +++ lib/libutil/cpuset.c @@ -27,35 +27,49 @@ * SUCH DAMAGE. */ +#include +#define _WANT_FREEBSD_BITSET + #include #include +#include #include #include #include #include -int -cpuset_parselist(const char *list, cpuset_t *mask) +struct numa_policy { + const char *name; + int policy; +}; + +static struct numa_policy policies[] = { + { "round-robin", DOMAINSET_POLICY_ROUNDROBIN }, + { "rr", DOMAINSET_POLICY_ROUNDROBIN }, + { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH }, + { "ft", DOMAINSET_POLICY_FIRSTTOUCH }, + { "prefer", DOMAINSET_POLICY_PREFER }, + { "interleave", DOMAINSET_POLICY_INTERLEAVE}, + { "il", DOMAINSET_POLICY_INTERLEAVE}, + { NULL, DOMAINSET_POLICY_INVALID } +}; + +static int +parselist(const char *list, struct bitset *mask, int size) { enum { NONE, NUM, DASH } state; int lastnum; int curnum; const char *l; - if (strcasecmp(list, "all") == 0) { - if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, - sizeof(*mask), mask) != 0) - return (CPUSET_PARSE_GETAFFINITY); - return (CPUSET_PARSE_OK); - } state = NONE; curnum = lastnum = 0; for (l = list; *l != '\0';) { if (isdigit(*l)) { curnum = atoi(l); - if (curnum > CPU_SETSIZE) - return (CPUSET_PARSE_INVALID_CPU); + if (curnum >= size) + return (CPUSET_PARSE_OUT_OF_RANGE); while (isdigit(*l)) l++; switch (state) { @@ -65,7 +79,7 @@ break; case DASH: for (; lastnum <= curnum; lastnum++) - CPU_SET(lastnum, mask); + BIT_SET(size, lastnum, mask); state = NONE; break; case NUM: @@ -80,7 +94,7 @@ case NONE: break; case NUM: - CPU_SET(curnum, mask); + BIT_SET(size, curnum, mask); state = NONE; break; case DASH: @@ -102,7 +116,7 @@ case NONE: break; case NUM: - CPU_SET(curnum, mask); + BIT_SET(size, curnum, mask); break; case DASH: goto parserr; @@ -111,3 +125,55 @@ parserr: return (CPUSET_PARSE_ERROR); } + +int +domainset_parselist(const char *list, domainset_t *mask, int *policyp) +{ + domainset_t rootmask; + struct numa_policy *policy; + const char *l; + int p; + + /* + * Use the rootset's policy as the default for unspecified policies. + */ + if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(rootmask), &rootmask, &p) != 0) + return (CPUSET_PARSE_GETDOMAIN); + + if (list == NULL || strcasecmp(list, "all") == 0 || *list == '\0') { + *policyp = p; + DOMAINSET_COPY(&rootmask, mask); + return (CPUSET_PARSE_OK); + } + + + l = list; + for (policy = &policies[0]; policy->name != NULL; policy++) { + if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) { + p = policy->policy; + l += strlen(policy->name); + if (*l != ':' && *l != '\0') + return (CPUSET_PARSE_ERROR); + if (*l == ':') + l++; + break; + } + } + *policyp = p; + + return (parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE)); +} + +int +cpuset_parselist(const char *list, cpuset_t *mask) +{ + if (strcasecmp(list, "all") == 0) { + if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1, + sizeof(*mask), mask) != 0) + return (CPUSET_PARSE_GETAFFINITY); + return (CPUSET_PARSE_OK); + } + + return (parselist(list, (struct bitset *)mask, CPU_SETSIZE)); +} Index: lib/libutil/libutil.h =================================================================== --- lib/libutil/libutil.h +++ lib/libutil/libutil.h @@ -210,10 +210,12 @@ #ifdef _SYS_CPUSET_H_ int cpuset_parselist(const char *list, cpuset_t *mask); +int domainset_parselist(const char *list, domainset_t *mask, int *policyp); #define CPUSET_PARSE_OK 0 #define CPUSET_PARSE_GETAFFINITY -1 #define CPUSET_PARSE_ERROR -2 -#define CPUSET_PARSE_INVALID_CPU -3 +#define CPUSET_PARSE_OUT_OF_RANGE -3 +#define CPUSET_PARSE_GETDOMAIN -4 #endif __END_DECLS Index: lib/libutil/tests/cpuset_test.c =================================================================== --- lib/libutil/tests/cpuset_test.c +++ lib/libutil/tests/cpuset_test.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -19,7 +20,7 @@ snprintf(testvalue, sizeof(testvalue), "%d", CPU_SETSIZE + 1); - ATF_CHECK_EQ(cpuset_parselist(testvalue, &mask), CPUSET_PARSE_INVALID_CPU); + ATF_CHECK_EQ(cpuset_parselist(testvalue, &mask), CPUSET_PARSE_OUT_OF_RANGE); } ATF_TC(invalidchar);