xref: /spdk/lib/util/cpuset.c (revision 712a3f69d32632bf6c862f00200f7f437d3f7529)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/cpuset.h"
35 #include "spdk/log.h"
36 
37 struct spdk_cpuset *
38 spdk_cpuset_alloc(void)
39 {
40 	return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1);
41 }
42 
43 void
44 spdk_cpuset_free(struct spdk_cpuset *set)
45 {
46 	free(set);
47 }
48 
49 bool
50 spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
51 {
52 	assert(set1 != NULL);
53 	assert(set2 != NULL);
54 	return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
55 }
56 
57 void
58 spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
59 {
60 	assert(dst != NULL);
61 	assert(src != NULL);
62 	memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
63 }
64 
65 void
66 spdk_cpuset_negate(struct spdk_cpuset *set)
67 {
68 	unsigned int i;
69 	assert(set != NULL);
70 	for (i = 0; i < sizeof(set->cpus); i++) {
71 		set->cpus[i] = ~set->cpus[i];
72 	}
73 }
74 
75 void
76 spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
77 {
78 	unsigned int i;
79 	assert(dst != NULL);
80 	assert(src != NULL);
81 	for (i = 0; i < sizeof(src->cpus); i++) {
82 		dst->cpus[i] &= src->cpus[i];
83 	}
84 }
85 
86 void
87 spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
88 {
89 	unsigned int i;
90 	assert(dst != NULL);
91 	assert(src != NULL);
92 	for (i = 0; i < sizeof(src->cpus); i++) {
93 		dst->cpus[i] |= src->cpus[i];
94 	}
95 }
96 
97 void
98 spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
99 {
100 	unsigned int i;
101 	assert(dst != NULL);
102 	assert(src != NULL);
103 	for (i = 0; i < sizeof(src->cpus); i++) {
104 		dst->cpus[i] ^= src->cpus[i];
105 	}
106 }
107 
108 void
109 spdk_cpuset_zero(struct spdk_cpuset *set)
110 {
111 	assert(set != NULL);
112 	memset(set->cpus, 0, sizeof(set->cpus));
113 }
114 
115 void
116 spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
117 {
118 	assert(set != NULL);
119 	assert(cpu < sizeof(set->cpus) * 8);
120 	if (state) {
121 		set->cpus[cpu / 8] |= (1U << (cpu % 8));
122 	} else {
123 		set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
124 	}
125 }
126 
127 bool
128 spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
129 {
130 	assert(set != NULL);
131 	assert(cpu < sizeof(set->cpus) * 8);
132 	return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
133 }
134 
135 uint32_t
136 spdk_cpuset_count(const struct spdk_cpuset *set)
137 {
138 	uint32_t count = 0;
139 	uint8_t n;
140 	unsigned int i;
141 	for (i = 0; i < sizeof(set->cpus); i++) {
142 		n = set->cpus[i];
143 		while (n) {
144 			n &= (n - 1);
145 			count++;
146 		}
147 	}
148 	return count;
149 }
150 
151 const char *
152 spdk_cpuset_fmt(struct spdk_cpuset *set)
153 {
154 	uint32_t lcore, lcore_max = 0;
155 	int val, i, n;
156 	char *ptr;
157 	static const char *hex = "0123456789abcdef";
158 
159 	assert(set != NULL);
160 
161 	for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
162 		if (spdk_cpuset_get_cpu(set, lcore)) {
163 			lcore_max = lcore;
164 		}
165 	}
166 
167 	ptr = set->str;
168 	n = lcore_max / 8;
169 	val = set->cpus[n];
170 
171 	/* Store first number only if it is not leading zero */
172 	if ((val & 0xf0) != 0) {
173 		*(ptr++) = hex[(val & 0xf0) >> 4];
174 	}
175 	*(ptr++) = hex[val & 0x0f];
176 
177 	for (i = n - 1; i >= 0; i--) {
178 		val = set->cpus[i];
179 		*(ptr++) = hex[(val & 0xf0) >> 4];
180 		*(ptr++) = hex[val & 0x0f];
181 	}
182 	*ptr = '\0';
183 
184 	return set->str;
185 }
186 
187 static int
188 hex_value(uint8_t c)
189 {
190 #define V(x, y) [x] = y + 1
191 	static const int8_t val[256] = {
192 		V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
193 		V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
194 		V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
195 		V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
196 	};
197 #undef V
198 
199 	return val[c] - 1;
200 }
201 
202 static int
203 parse_list(const char *mask, struct spdk_cpuset *set)
204 {
205 	char *end;
206 	const char *ptr = mask;
207 	uint32_t lcore;
208 	uint32_t lcore_min, lcore_max;
209 
210 	spdk_cpuset_zero(set);
211 	lcore_min = UINT32_MAX;
212 
213 	ptr++;
214 	end = (char *)ptr;
215 	do {
216 		while (isblank(*ptr)) {
217 			ptr++;
218 		}
219 		if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
220 			goto invalid_character;
221 		}
222 
223 		errno = 0;
224 		lcore = strtoul(ptr, &end, 10);
225 		if (errno) {
226 			SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
227 			return -1;
228 		}
229 
230 		if (lcore >= sizeof(set->cpus) * 8) {
231 			SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
232 			return -1;
233 		}
234 
235 		while (isblank(*end)) {
236 			end++;
237 		}
238 
239 		if (*end == '-') {
240 			lcore_min = lcore;
241 		} else if (*end == ',' || *end == ']') {
242 			lcore_max = lcore;
243 			if (lcore_min == UINT32_MAX) {
244 				lcore_min = lcore;
245 			}
246 			if (lcore_min > lcore_max) {
247 				SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
248 					    lcore_min, lcore_max);
249 				return -1;
250 			}
251 			for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
252 				spdk_cpuset_set_cpu(set, lcore, true);
253 			}
254 			lcore_min = UINT32_MAX;
255 		} else {
256 			goto invalid_character;
257 		}
258 
259 		ptr = end + 1;
260 
261 	} while (*end != ']');
262 
263 	return 0;
264 
265 invalid_character:
266 	if (*end == '\0') {
267 		SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
268 	} else {
269 		SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
270 	}
271 	return -1;
272 }
273 
274 static int
275 parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
276 {
277 	int i, j;
278 	char c;
279 	int val;
280 	uint32_t lcore = 0;
281 
282 	if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
283 		mask += 2;
284 		len -= 2;
285 	}
286 
287 	spdk_cpuset_zero(set);
288 	for (i = len - 1; i >= 0; i--) {
289 		c = mask[i];
290 		val = hex_value(c);
291 		if (val < 0) {
292 			/* Invalid character */
293 			SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
294 			return -1;
295 		}
296 		for (j = 0; j < 4 && lcore < sizeof(set->cpus); j++, lcore++) {
297 			if ((1 << j) & val) {
298 				spdk_cpuset_set_cpu(set, lcore, true);
299 			}
300 		}
301 	}
302 
303 	return 0;
304 }
305 
306 int
307 spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
308 {
309 	int ret;
310 	size_t len;
311 
312 	if (mask == NULL || set == NULL) {
313 		return -1;
314 	}
315 
316 	while (isblank(*mask)) {
317 		mask++;
318 	}
319 
320 	len = strlen(mask);
321 	while (len > 0 && isblank(mask[len - 1])) {
322 		len--;
323 	}
324 
325 	if (len == 0) {
326 		return -1;
327 	}
328 
329 	if (mask[0] == '[') {
330 		ret = parse_list(mask, set);
331 	} else {
332 		ret = parse_mask(mask, set, len);
333 	}
334 
335 	return ret;
336 }
337