Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright (C) 2017 Intel Corporation. All rights reserved.
3 : * All rights reserved.
4 : */
5 :
6 : #include "spdk/cpuset.h"
7 : #include "spdk/log.h"
8 :
9 : struct spdk_cpuset *
10 3 : spdk_cpuset_alloc(void)
11 : {
12 3 : return (struct spdk_cpuset *)calloc(1, sizeof(struct spdk_cpuset));
13 : }
14 :
15 : void
16 3 : spdk_cpuset_free(struct spdk_cpuset *set)
17 : {
18 3 : free(set);
19 3 : }
20 :
21 : bool
22 3 : spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
23 : {
24 3 : assert(set1 != NULL);
25 3 : assert(set2 != NULL);
26 3 : return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
27 : }
28 :
29 : void
30 31 : spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
31 : {
32 31 : assert(dst != NULL);
33 31 : assert(src != NULL);
34 31 : memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
35 31 : }
36 :
37 : void
38 176 : spdk_cpuset_negate(struct spdk_cpuset *set)
39 : {
40 : unsigned int i;
41 176 : assert(set != NULL);
42 22704 : for (i = 0; i < sizeof(set->cpus); i++) {
43 22528 : set->cpus[i] = ~set->cpus[i];
44 22528 : }
45 176 : }
46 :
47 : void
48 13 : spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
49 : {
50 : unsigned int i;
51 13 : assert(dst != NULL);
52 13 : assert(src != NULL);
53 1677 : for (i = 0; i < sizeof(src->cpus); i++) {
54 1664 : dst->cpus[i] &= src->cpus[i];
55 1664 : }
56 13 : }
57 :
58 : void
59 3 : spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
60 : {
61 : unsigned int i;
62 3 : assert(dst != NULL);
63 3 : assert(src != NULL);
64 387 : for (i = 0; i < sizeof(src->cpus); i++) {
65 384 : dst->cpus[i] |= src->cpus[i];
66 384 : }
67 3 : }
68 :
69 : void
70 18 : spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
71 : {
72 : unsigned int i;
73 18 : assert(dst != NULL);
74 18 : assert(src != NULL);
75 2322 : for (i = 0; i < sizeof(src->cpus); i++) {
76 2304 : dst->cpus[i] ^= src->cpus[i];
77 2304 : }
78 18 : }
79 :
80 : void
81 77 : spdk_cpuset_zero(struct spdk_cpuset *set)
82 : {
83 77 : assert(set != NULL);
84 77 : memset(set->cpus, 0, sizeof(set->cpus));
85 77 : }
86 :
87 : void
88 3350 : spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
89 : {
90 3350 : assert(set != NULL);
91 3350 : assert(cpu < sizeof(set->cpus) * 8);
92 3350 : if (state) {
93 3349 : set->cpus[cpu / 8] |= (1U << (cpu % 8));
94 3349 : } else {
95 1 : set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
96 : }
97 3350 : }
98 :
99 : bool
100 19531 : spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
101 : {
102 19531 : assert(set != NULL);
103 19531 : assert(cpu < sizeof(set->cpus) * 8);
104 19531 : return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
105 : }
106 :
107 : void
108 21 : spdk_cpuset_for_each_cpu(const struct spdk_cpuset *set,
109 : void (*fn)(void *ctx, uint32_t cpu), void *ctx)
110 : {
111 : uint8_t n;
112 : unsigned int i, j;
113 2709 : for (i = 0; i < sizeof(set->cpus); i++) {
114 2688 : n = set->cpus[i];
115 24192 : for (j = 0; j < 8; j++) {
116 21504 : if (n & (1 << j)) {
117 1056 : fn(ctx, i * 8 + j);
118 1056 : }
119 21504 : }
120 2688 : }
121 21 : }
122 :
123 : static void
124 1043 : count_fn(void *ctx, uint32_t cpu)
125 : {
126 1043 : uint32_t *count = ctx;
127 :
128 1043 : (*count)++;
129 1043 : }
130 :
131 : uint32_t
132 20 : spdk_cpuset_count(const struct spdk_cpuset *set)
133 : {
134 20 : uint32_t count = 0;
135 :
136 20 : spdk_cpuset_for_each_cpu(set, count_fn, &count);
137 20 : return count;
138 : }
139 :
140 : const char *
141 3 : spdk_cpuset_fmt(struct spdk_cpuset *set)
142 : {
143 3 : uint32_t lcore, lcore_max = 0;
144 : int val, i, n;
145 : char *ptr;
146 : static const char *hex = "0123456789abcdef";
147 :
148 3 : assert(set != NULL);
149 :
150 3075 : for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
151 3072 : if (spdk_cpuset_get_cpu(set, lcore)) {
152 1031 : lcore_max = lcore;
153 1031 : }
154 3072 : }
155 :
156 3 : ptr = set->str;
157 3 : n = lcore_max / 8;
158 3 : val = set->cpus[n];
159 :
160 : /* Store first number only if it is not leading zero */
161 3 : if ((val & 0xf0) != 0) {
162 1 : *(ptr++) = hex[(val & 0xf0) >> 4];
163 1 : }
164 3 : *(ptr++) = hex[val & 0x0f];
165 :
166 132 : for (i = n - 1; i >= 0; i--) {
167 129 : val = set->cpus[i];
168 129 : *(ptr++) = hex[(val & 0xf0) >> 4];
169 129 : *(ptr++) = hex[val & 0x0f];
170 129 : }
171 3 : *ptr = '\0';
172 :
173 3 : return set->str;
174 : }
175 :
176 : static int
177 75 : hex_value(uint8_t c)
178 : {
179 : #define V(x, y) [x] = y + 1
180 : static const int8_t val[256] = {
181 : V('0', 0), V('1', 1), V('2', 2), V('3', 3), V('4', 4),
182 : V('5', 5), V('6', 6), V('7', 7), V('8', 8), V('9', 9),
183 : V('A', 0xA), V('B', 0xB), V('C', 0xC), V('D', 0xD), V('E', 0xE), V('F', 0xF),
184 : V('a', 0xA), V('b', 0xB), V('c', 0xC), V('d', 0xD), V('e', 0xE), V('f', 0xF),
185 : };
186 : #undef V
187 :
188 75 : return val[c] - 1;
189 : }
190 :
191 : static int
192 11 : parse_list(const char *mask, struct spdk_cpuset *set)
193 : {
194 : char *end;
195 11 : const char *ptr = mask;
196 : uint32_t lcore;
197 : uint32_t lcore_min, lcore_max;
198 :
199 11 : spdk_cpuset_zero(set);
200 11 : lcore_min = UINT32_MAX;
201 :
202 11 : ptr++;
203 11 : end = (char *)ptr;
204 11 : do {
205 20 : while (isblank(*ptr)) {
206 0 : ptr++;
207 : }
208 20 : if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
209 5 : goto invalid_character;
210 : }
211 :
212 15 : errno = 0;
213 15 : lcore = strtoul(ptr, &end, 10);
214 15 : if (errno) {
215 1 : SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
216 1 : return -1;
217 : }
218 :
219 14 : if (lcore >= sizeof(set->cpus) * 8) {
220 1 : SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
221 1 : return -1;
222 : }
223 :
224 13 : while (isblank(*end)) {
225 0 : end++;
226 : }
227 :
228 13 : if (*end == '-') {
229 6 : lcore_min = lcore;
230 13 : } else if (*end == ',' || *end == ']') {
231 7 : lcore_max = lcore;
232 7 : if (lcore_min == UINT32_MAX) {
233 2 : lcore_min = lcore;
234 2 : }
235 7 : if (lcore_min > lcore_max) {
236 1 : SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
237 : lcore_min, lcore_max);
238 1 : return -1;
239 : }
240 1172 : for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
241 1166 : spdk_cpuset_set_cpu(set, lcore, true);
242 1166 : }
243 6 : lcore_min = UINT32_MAX;
244 6 : } else {
245 0 : goto invalid_character;
246 : }
247 :
248 12 : ptr = end + 1;
249 :
250 12 : } while (*end != ']');
251 :
252 3 : return 0;
253 :
254 : invalid_character:
255 5 : if (*end == '\0') {
256 1 : SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
257 1 : } else {
258 4 : SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
259 : }
260 5 : return -1;
261 11 : }
262 :
263 : static int
264 5 : parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
265 : {
266 : int i, j;
267 : char c;
268 : int val;
269 5 : uint32_t lcore = 0;
270 :
271 5 : if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
272 3 : mask += 2;
273 3 : len -= 2;
274 3 : }
275 :
276 5 : spdk_cpuset_zero(set);
277 95 : for (i = len - 1; i >= 0; i--) {
278 90 : c = mask[i];
279 90 : if (c == ',') {
280 : /* Linux puts comma delimiters in its cpumasks, just skip them. */
281 15 : continue;
282 : }
283 75 : val = hex_value(c);
284 75 : if (val < 0) {
285 : /* Invalid character */
286 0 : SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
287 0 : return -1;
288 : }
289 375 : for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
290 300 : if ((1 << j) & val) {
291 47 : spdk_cpuset_set_cpu(set, lcore, true);
292 47 : }
293 300 : }
294 75 : }
295 :
296 5 : return 0;
297 5 : }
298 :
299 : int
300 19 : spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
301 : {
302 : int ret;
303 : size_t len;
304 :
305 19 : if (mask == NULL || set == NULL) {
306 2 : return -1;
307 : }
308 :
309 17 : while (isblank(*mask)) {
310 0 : mask++;
311 : }
312 :
313 17 : len = strlen(mask);
314 17 : while (len > 0 && isblank(mask[len - 1])) {
315 0 : len--;
316 : }
317 :
318 17 : if (len == 0) {
319 1 : return -1;
320 : }
321 :
322 16 : if (mask[0] == '[') {
323 11 : ret = parse_list(mask, set);
324 11 : } else {
325 5 : ret = parse_mask(mask, set, len);
326 : }
327 :
328 16 : return ret;
329 19 : }
|