xref: /spdk/lib/util/cpuset.c (revision cdeecfb8d22e5a40290b01972ba74744b2120a29)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation. All rights reserved.
3601bcbcfSTomasz Kulasek  *   All rights reserved.
4601bcbcfSTomasz Kulasek  */
5601bcbcfSTomasz Kulasek 
6601bcbcfSTomasz Kulasek #include "spdk/cpuset.h"
7601bcbcfSTomasz Kulasek #include "spdk/log.h"
8601bcbcfSTomasz Kulasek 
9601bcbcfSTomasz Kulasek struct spdk_cpuset *
spdk_cpuset_alloc(void)10601bcbcfSTomasz Kulasek spdk_cpuset_alloc(void)
11601bcbcfSTomasz Kulasek {
12746549cfSCody Cheng 	return (struct spdk_cpuset *)calloc(1, sizeof(struct spdk_cpuset));
13601bcbcfSTomasz Kulasek }
14601bcbcfSTomasz Kulasek 
15601bcbcfSTomasz Kulasek void
spdk_cpuset_free(struct spdk_cpuset * set)16601bcbcfSTomasz Kulasek spdk_cpuset_free(struct spdk_cpuset *set)
17601bcbcfSTomasz Kulasek {
18601bcbcfSTomasz Kulasek 	free(set);
19601bcbcfSTomasz Kulasek }
20601bcbcfSTomasz Kulasek 
21601bcbcfSTomasz Kulasek bool
spdk_cpuset_equal(const struct spdk_cpuset * set1,const struct spdk_cpuset * set2)22601bcbcfSTomasz Kulasek spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
23601bcbcfSTomasz Kulasek {
24601bcbcfSTomasz Kulasek 	assert(set1 != NULL);
25601bcbcfSTomasz Kulasek 	assert(set2 != NULL);
26601bcbcfSTomasz Kulasek 	return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
27601bcbcfSTomasz Kulasek }
28601bcbcfSTomasz Kulasek 
29601bcbcfSTomasz Kulasek void
spdk_cpuset_copy(struct spdk_cpuset * dst,const struct spdk_cpuset * src)3060d48787SDarek Stojaczyk spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
31601bcbcfSTomasz Kulasek {
3260d48787SDarek Stojaczyk 	assert(dst != NULL);
3360d48787SDarek Stojaczyk 	assert(src != NULL);
3460d48787SDarek Stojaczyk 	memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
35601bcbcfSTomasz Kulasek }
36601bcbcfSTomasz Kulasek 
37601bcbcfSTomasz Kulasek void
spdk_cpuset_negate(struct spdk_cpuset * set)38ebce385dSTomasz Kulasek spdk_cpuset_negate(struct spdk_cpuset *set)
39ebce385dSTomasz Kulasek {
40ebce385dSTomasz Kulasek 	unsigned int i;
41ebce385dSTomasz Kulasek 	assert(set != NULL);
42ebce385dSTomasz Kulasek 	for (i = 0; i < sizeof(set->cpus); i++) {
43ebce385dSTomasz Kulasek 		set->cpus[i] = ~set->cpus[i];
44ebce385dSTomasz Kulasek 	}
45ebce385dSTomasz Kulasek }
46ebce385dSTomasz Kulasek 
47ebce385dSTomasz Kulasek void
spdk_cpuset_and(struct spdk_cpuset * dst,const struct spdk_cpuset * src)4860d48787SDarek Stojaczyk spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
49601bcbcfSTomasz Kulasek {
50601bcbcfSTomasz Kulasek 	unsigned int i;
5160d48787SDarek Stojaczyk 	assert(dst != NULL);
5260d48787SDarek Stojaczyk 	assert(src != NULL);
5360d48787SDarek Stojaczyk 	for (i = 0; i < sizeof(src->cpus); i++) {
5460d48787SDarek Stojaczyk 		dst->cpus[i] &= src->cpus[i];
55601bcbcfSTomasz Kulasek 	}
56601bcbcfSTomasz Kulasek }
57601bcbcfSTomasz Kulasek 
58601bcbcfSTomasz Kulasek void
spdk_cpuset_or(struct spdk_cpuset * dst,const struct spdk_cpuset * src)5960d48787SDarek Stojaczyk spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
60601bcbcfSTomasz Kulasek {
61601bcbcfSTomasz Kulasek 	unsigned int i;
6260d48787SDarek Stojaczyk 	assert(dst != NULL);
6360d48787SDarek Stojaczyk 	assert(src != NULL);
6460d48787SDarek Stojaczyk 	for (i = 0; i < sizeof(src->cpus); i++) {
6560d48787SDarek Stojaczyk 		dst->cpus[i] |= src->cpus[i];
66601bcbcfSTomasz Kulasek 	}
67601bcbcfSTomasz Kulasek }
68601bcbcfSTomasz Kulasek 
69601bcbcfSTomasz Kulasek void
spdk_cpuset_xor(struct spdk_cpuset * dst,const struct spdk_cpuset * src)7060d48787SDarek Stojaczyk spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
71ebce385dSTomasz Kulasek {
72ebce385dSTomasz Kulasek 	unsigned int i;
7360d48787SDarek Stojaczyk 	assert(dst != NULL);
7460d48787SDarek Stojaczyk 	assert(src != NULL);
7560d48787SDarek Stojaczyk 	for (i = 0; i < sizeof(src->cpus); i++) {
7660d48787SDarek Stojaczyk 		dst->cpus[i] ^= src->cpus[i];
77ebce385dSTomasz Kulasek 	}
78ebce385dSTomasz Kulasek }
79ebce385dSTomasz Kulasek 
80ebce385dSTomasz Kulasek void
spdk_cpuset_zero(struct spdk_cpuset * set)81601bcbcfSTomasz Kulasek spdk_cpuset_zero(struct spdk_cpuset *set)
82601bcbcfSTomasz Kulasek {
83601bcbcfSTomasz Kulasek 	assert(set != NULL);
84601bcbcfSTomasz Kulasek 	memset(set->cpus, 0, sizeof(set->cpus));
85601bcbcfSTomasz Kulasek }
86601bcbcfSTomasz Kulasek 
87601bcbcfSTomasz Kulasek void
spdk_cpuset_set_cpu(struct spdk_cpuset * set,uint32_t cpu,bool state)88601bcbcfSTomasz Kulasek spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
89601bcbcfSTomasz Kulasek {
90601bcbcfSTomasz Kulasek 	assert(set != NULL);
91601bcbcfSTomasz Kulasek 	assert(cpu < sizeof(set->cpus) * 8);
92601bcbcfSTomasz Kulasek 	if (state) {
93601bcbcfSTomasz Kulasek 		set->cpus[cpu / 8] |= (1U << (cpu % 8));
94601bcbcfSTomasz Kulasek 	} else {
95601bcbcfSTomasz Kulasek 		set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
96601bcbcfSTomasz Kulasek 	}
97601bcbcfSTomasz Kulasek }
98601bcbcfSTomasz Kulasek 
99601bcbcfSTomasz Kulasek bool
spdk_cpuset_get_cpu(const struct spdk_cpuset * set,uint32_t cpu)100601bcbcfSTomasz Kulasek spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
101601bcbcfSTomasz Kulasek {
102601bcbcfSTomasz Kulasek 	assert(set != NULL);
103601bcbcfSTomasz Kulasek 	assert(cpu < sizeof(set->cpus) * 8);
104601bcbcfSTomasz Kulasek 	return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
105601bcbcfSTomasz Kulasek }
106601bcbcfSTomasz Kulasek 
107*cdeecfb8SJim Harris void
spdk_cpuset_for_each_cpu(const struct spdk_cpuset * set,void (* fn)(void * ctx,uint32_t cpu),void * ctx)108*cdeecfb8SJim Harris spdk_cpuset_for_each_cpu(const struct spdk_cpuset *set,
109*cdeecfb8SJim Harris 			 void (*fn)(void *ctx, uint32_t cpu), void *ctx)
110601bcbcfSTomasz Kulasek {
111601bcbcfSTomasz Kulasek 	uint8_t n;
112b1923f4dSJim Harris 	unsigned int i, j;
113601bcbcfSTomasz Kulasek 	for (i = 0; i < sizeof(set->cpus); i++) {
114601bcbcfSTomasz Kulasek 		n = set->cpus[i];
115b1923f4dSJim Harris 		for (j = 0; j < 8; j++) {
116b1923f4dSJim Harris 			if (n & (1 << j)) {
117*cdeecfb8SJim Harris 				fn(ctx, i * 8 + j);
118601bcbcfSTomasz Kulasek 			}
119601bcbcfSTomasz Kulasek 		}
120b1923f4dSJim Harris 	}
121*cdeecfb8SJim Harris }
122*cdeecfb8SJim Harris 
123*cdeecfb8SJim Harris static void
count_fn(void * ctx,uint32_t cpu)124*cdeecfb8SJim Harris count_fn(void *ctx, uint32_t cpu)
125*cdeecfb8SJim Harris {
126*cdeecfb8SJim Harris 	uint32_t *count = ctx;
127*cdeecfb8SJim Harris 
128*cdeecfb8SJim Harris 	(*count)++;
129*cdeecfb8SJim Harris }
130*cdeecfb8SJim Harris 
131*cdeecfb8SJim Harris uint32_t
spdk_cpuset_count(const struct spdk_cpuset * set)132*cdeecfb8SJim Harris spdk_cpuset_count(const struct spdk_cpuset *set)
133*cdeecfb8SJim Harris {
134*cdeecfb8SJim Harris 	uint32_t count = 0;
135*cdeecfb8SJim Harris 
136*cdeecfb8SJim Harris 	spdk_cpuset_for_each_cpu(set, count_fn, &count);
137601bcbcfSTomasz Kulasek 	return count;
138601bcbcfSTomasz Kulasek }
139601bcbcfSTomasz Kulasek 
140e7285749SPawel Wodkowski const char *
spdk_cpuset_fmt(struct spdk_cpuset * set)141601bcbcfSTomasz Kulasek spdk_cpuset_fmt(struct spdk_cpuset *set)
142601bcbcfSTomasz Kulasek {
143601bcbcfSTomasz Kulasek 	uint32_t lcore, lcore_max = 0;
144601bcbcfSTomasz Kulasek 	int val, i, n;
145601bcbcfSTomasz Kulasek 	char *ptr;
146601bcbcfSTomasz Kulasek 	static const char *hex = "0123456789abcdef";
147601bcbcfSTomasz Kulasek 
148601bcbcfSTomasz Kulasek 	assert(set != NULL);
149601bcbcfSTomasz Kulasek 
150601bcbcfSTomasz Kulasek 	for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
151601bcbcfSTomasz Kulasek 		if (spdk_cpuset_get_cpu(set, lcore)) {
152601bcbcfSTomasz Kulasek 			lcore_max = lcore;
153601bcbcfSTomasz Kulasek 		}
154601bcbcfSTomasz Kulasek 	}
155601bcbcfSTomasz Kulasek 
156601bcbcfSTomasz Kulasek 	ptr = set->str;
157601bcbcfSTomasz Kulasek 	n = lcore_max / 8;
158601bcbcfSTomasz Kulasek 	val = set->cpus[n];
159601bcbcfSTomasz Kulasek 
160601bcbcfSTomasz Kulasek 	/* Store first number only if it is not leading zero */
161601bcbcfSTomasz Kulasek 	if ((val & 0xf0) != 0) {
162601bcbcfSTomasz Kulasek 		*(ptr++) = hex[(val & 0xf0) >> 4];
163601bcbcfSTomasz Kulasek 	}
164601bcbcfSTomasz Kulasek 	*(ptr++) = hex[val & 0x0f];
165601bcbcfSTomasz Kulasek 
166601bcbcfSTomasz Kulasek 	for (i = n - 1; i >= 0; i--) {
167601bcbcfSTomasz Kulasek 		val = set->cpus[i];
168601bcbcfSTomasz Kulasek 		*(ptr++) = hex[(val & 0xf0) >> 4];
169601bcbcfSTomasz Kulasek 		*(ptr++) = hex[val & 0x0f];
170601bcbcfSTomasz Kulasek 	}
171601bcbcfSTomasz Kulasek 	*ptr = '\0';
172601bcbcfSTomasz Kulasek 
173601bcbcfSTomasz Kulasek 	return set->str;
174601bcbcfSTomasz Kulasek }
175601bcbcfSTomasz Kulasek 
176601bcbcfSTomasz Kulasek static int
hex_value(uint8_t c)177601bcbcfSTomasz Kulasek hex_value(uint8_t c)
178601bcbcfSTomasz Kulasek {
179601bcbcfSTomasz Kulasek #define V(x, y) [x] = y + 1
180601bcbcfSTomasz Kulasek 	static const int8_t val[256] = {
181601bcbcfSTomasz Kulasek 		V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
182601bcbcfSTomasz Kulasek 		V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
183601bcbcfSTomasz Kulasek 		V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
184601bcbcfSTomasz Kulasek 		V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
185601bcbcfSTomasz Kulasek 	};
186601bcbcfSTomasz Kulasek #undef V
187601bcbcfSTomasz Kulasek 
188601bcbcfSTomasz Kulasek 	return val[c] - 1;
189601bcbcfSTomasz Kulasek }
190601bcbcfSTomasz Kulasek 
191601bcbcfSTomasz Kulasek static int
parse_list(const char * mask,struct spdk_cpuset * set)192601bcbcfSTomasz Kulasek parse_list(const char *mask, struct spdk_cpuset *set)
193601bcbcfSTomasz Kulasek {
194601bcbcfSTomasz Kulasek 	char *end;
195601bcbcfSTomasz Kulasek 	const char *ptr = mask;
196601bcbcfSTomasz Kulasek 	uint32_t lcore;
197601bcbcfSTomasz Kulasek 	uint32_t lcore_min, lcore_max;
198601bcbcfSTomasz Kulasek 
199601bcbcfSTomasz Kulasek 	spdk_cpuset_zero(set);
200601bcbcfSTomasz Kulasek 	lcore_min = UINT32_MAX;
201601bcbcfSTomasz Kulasek 
202601bcbcfSTomasz Kulasek 	ptr++;
203601bcbcfSTomasz Kulasek 	end = (char *)ptr;
204601bcbcfSTomasz Kulasek 	do {
205601bcbcfSTomasz Kulasek 		while (isblank(*ptr)) {
206601bcbcfSTomasz Kulasek 			ptr++;
207601bcbcfSTomasz Kulasek 		}
208601bcbcfSTomasz Kulasek 		if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
209601bcbcfSTomasz Kulasek 			goto invalid_character;
210601bcbcfSTomasz Kulasek 		}
211601bcbcfSTomasz Kulasek 
212601bcbcfSTomasz Kulasek 		errno = 0;
213601bcbcfSTomasz Kulasek 		lcore = strtoul(ptr, &end, 10);
214601bcbcfSTomasz Kulasek 		if (errno) {
215601bcbcfSTomasz Kulasek 			SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
216601bcbcfSTomasz Kulasek 			return -1;
217601bcbcfSTomasz Kulasek 		}
218601bcbcfSTomasz Kulasek 
219601bcbcfSTomasz Kulasek 		if (lcore >= sizeof(set->cpus) * 8) {
220601bcbcfSTomasz Kulasek 			SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
221601bcbcfSTomasz Kulasek 			return -1;
222601bcbcfSTomasz Kulasek 		}
223601bcbcfSTomasz Kulasek 
224601bcbcfSTomasz Kulasek 		while (isblank(*end)) {
225601bcbcfSTomasz Kulasek 			end++;
226601bcbcfSTomasz Kulasek 		}
227601bcbcfSTomasz Kulasek 
228601bcbcfSTomasz Kulasek 		if (*end == '-') {
229601bcbcfSTomasz Kulasek 			lcore_min = lcore;
230601bcbcfSTomasz Kulasek 		} else if (*end == ',' || *end == ']') {
231601bcbcfSTomasz Kulasek 			lcore_max = lcore;
232601bcbcfSTomasz Kulasek 			if (lcore_min == UINT32_MAX) {
233601bcbcfSTomasz Kulasek 				lcore_min = lcore;
234601bcbcfSTomasz Kulasek 			}
235601bcbcfSTomasz Kulasek 			if (lcore_min > lcore_max) {
236601bcbcfSTomasz Kulasek 				SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
237601bcbcfSTomasz Kulasek 					    lcore_min, lcore_max);
238601bcbcfSTomasz Kulasek 				return -1;
239601bcbcfSTomasz Kulasek 			}
240601bcbcfSTomasz Kulasek 			for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
241601bcbcfSTomasz Kulasek 				spdk_cpuset_set_cpu(set, lcore, true);
242601bcbcfSTomasz Kulasek 			}
243601bcbcfSTomasz Kulasek 			lcore_min = UINT32_MAX;
244601bcbcfSTomasz Kulasek 		} else {
245601bcbcfSTomasz Kulasek 			goto invalid_character;
246601bcbcfSTomasz Kulasek 		}
247601bcbcfSTomasz Kulasek 
248601bcbcfSTomasz Kulasek 		ptr = end + 1;
249601bcbcfSTomasz Kulasek 
250601bcbcfSTomasz Kulasek 	} while (*end != ']');
251601bcbcfSTomasz Kulasek 
252601bcbcfSTomasz Kulasek 	return 0;
253601bcbcfSTomasz Kulasek 
254601bcbcfSTomasz Kulasek invalid_character:
255601bcbcfSTomasz Kulasek 	if (*end == '\0') {
256601bcbcfSTomasz Kulasek 		SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
257601bcbcfSTomasz Kulasek 	} else {
258601bcbcfSTomasz Kulasek 		SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
259601bcbcfSTomasz Kulasek 	}
260601bcbcfSTomasz Kulasek 	return -1;
261601bcbcfSTomasz Kulasek }
262601bcbcfSTomasz Kulasek 
263601bcbcfSTomasz Kulasek static int
parse_mask(const char * mask,struct spdk_cpuset * set,size_t len)264601bcbcfSTomasz Kulasek parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
265601bcbcfSTomasz Kulasek {
266601bcbcfSTomasz Kulasek 	int i, j;
267601bcbcfSTomasz Kulasek 	char c;
268601bcbcfSTomasz Kulasek 	int val;
269601bcbcfSTomasz Kulasek 	uint32_t lcore = 0;
270601bcbcfSTomasz Kulasek 
271601bcbcfSTomasz Kulasek 	if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
272601bcbcfSTomasz Kulasek 		mask += 2;
273601bcbcfSTomasz Kulasek 		len -= 2;
274601bcbcfSTomasz Kulasek 	}
275601bcbcfSTomasz Kulasek 
276601bcbcfSTomasz Kulasek 	spdk_cpuset_zero(set);
277601bcbcfSTomasz Kulasek 	for (i = len - 1; i >= 0; i--) {
278601bcbcfSTomasz Kulasek 		c = mask[i];
279a44a9620SJim Harris 		if (c == ',') {
280a44a9620SJim Harris 			/* Linux puts comma delimiters in its cpumasks, just skip them. */
281a44a9620SJim Harris 			continue;
282a44a9620SJim Harris 		}
283601bcbcfSTomasz Kulasek 		val = hex_value(c);
284601bcbcfSTomasz Kulasek 		if (val < 0) {
285601bcbcfSTomasz Kulasek 			/* Invalid character */
286601bcbcfSTomasz Kulasek 			SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
287601bcbcfSTomasz Kulasek 			return -1;
288601bcbcfSTomasz Kulasek 		}
289150339ccSJim Harris 		for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
290601bcbcfSTomasz Kulasek 			if ((1 << j) & val) {
291601bcbcfSTomasz Kulasek 				spdk_cpuset_set_cpu(set, lcore, true);
292601bcbcfSTomasz Kulasek 			}
293601bcbcfSTomasz Kulasek 		}
294601bcbcfSTomasz Kulasek 	}
295601bcbcfSTomasz Kulasek 
296601bcbcfSTomasz Kulasek 	return 0;
297601bcbcfSTomasz Kulasek }
298601bcbcfSTomasz Kulasek 
299601bcbcfSTomasz Kulasek int
spdk_cpuset_parse(struct spdk_cpuset * set,const char * mask)300601bcbcfSTomasz Kulasek spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
301601bcbcfSTomasz Kulasek {
302601bcbcfSTomasz Kulasek 	int ret;
303601bcbcfSTomasz Kulasek 	size_t len;
304601bcbcfSTomasz Kulasek 
305601bcbcfSTomasz Kulasek 	if (mask == NULL || set == NULL) {
306601bcbcfSTomasz Kulasek 		return -1;
307601bcbcfSTomasz Kulasek 	}
308601bcbcfSTomasz Kulasek 
309601bcbcfSTomasz Kulasek 	while (isblank(*mask)) {
310601bcbcfSTomasz Kulasek 		mask++;
311601bcbcfSTomasz Kulasek 	}
312601bcbcfSTomasz Kulasek 
313601bcbcfSTomasz Kulasek 	len = strlen(mask);
314601bcbcfSTomasz Kulasek 	while (len > 0 && isblank(mask[len - 1])) {
315601bcbcfSTomasz Kulasek 		len--;
316601bcbcfSTomasz Kulasek 	}
317601bcbcfSTomasz Kulasek 
318601bcbcfSTomasz Kulasek 	if (len == 0) {
319601bcbcfSTomasz Kulasek 		return -1;
320601bcbcfSTomasz Kulasek 	}
321601bcbcfSTomasz Kulasek 
322601bcbcfSTomasz Kulasek 	if (mask[0] == '[') {
323601bcbcfSTomasz Kulasek 		ret = parse_list(mask, set);
324601bcbcfSTomasz Kulasek 	} else {
325601bcbcfSTomasz Kulasek 		ret = parse_mask(mask, set, len);
326601bcbcfSTomasz Kulasek 	}
327601bcbcfSTomasz Kulasek 
328601bcbcfSTomasz Kulasek 	return ret;
329601bcbcfSTomasz Kulasek }
330