Branch data 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 : 24 : spdk_cpuset_alloc(void)
11 : : {
12 : 24 : return (struct spdk_cpuset *)calloc(1, sizeof(struct spdk_cpuset));
13 : : }
14 : :
15 : : void
16 : 24 : spdk_cpuset_free(struct spdk_cpuset *set)
17 : : {
18 : 24 : free(set);
19 : 24 : }
20 : :
21 : : bool
22 : 1114 : spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
23 : : {
24 [ - + ]: 1114 : assert(set1 != NULL);
25 [ - + ]: 1114 : assert(set2 != NULL);
26 [ - + - + ]: 1114 : return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
27 : : }
28 : :
29 : : void
30 : 26314 : spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
31 : : {
32 [ - + ]: 26314 : assert(dst != NULL);
33 [ - + ]: 26314 : assert(src != NULL);
34 [ - + - + ]: 26314 : memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
35 : 26314 : }
36 : :
37 : : void
38 : 2679 : spdk_cpuset_negate(struct spdk_cpuset *set)
39 : : {
40 : : unsigned int i;
41 [ - + ]: 2679 : assert(set != NULL);
42 [ + + ]: 345591 : for (i = 0; i < sizeof(set->cpus); i++) {
43 : 342912 : set->cpus[i] = ~set->cpus[i];
44 : : }
45 : 2679 : }
46 : :
47 : : void
48 : 7671 : spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
49 : : {
50 : : unsigned int i;
51 [ - + ]: 7671 : assert(dst != NULL);
52 [ - + ]: 7671 : assert(src != NULL);
53 [ + + ]: 989559 : for (i = 0; i < sizeof(src->cpus); i++) {
54 : 981888 : dst->cpus[i] &= src->cpus[i];
55 : : }
56 : 7671 : }
57 : :
58 : : void
59 : 1194 : spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
60 : : {
61 : : unsigned int i;
62 [ - + ]: 1194 : assert(dst != NULL);
63 [ - + ]: 1194 : assert(src != NULL);
64 [ + + ]: 154026 : for (i = 0; i < sizeof(src->cpus); i++) {
65 : 152832 : dst->cpus[i] |= src->cpus[i];
66 : : }
67 : 1194 : }
68 : :
69 : : void
70 : 7356 : spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
71 : : {
72 : : unsigned int i;
73 [ - + ]: 7356 : assert(dst != NULL);
74 [ - + ]: 7356 : assert(src != NULL);
75 [ + + ]: 948924 : for (i = 0; i < sizeof(src->cpus); i++) {
76 : 941568 : dst->cpus[i] ^= src->cpus[i];
77 : : }
78 : 7356 : }
79 : :
80 : : void
81 : 19146 : spdk_cpuset_zero(struct spdk_cpuset *set)
82 : : {
83 [ - + ]: 19146 : assert(set != NULL);
84 [ - + ]: 19146 : memset(set->cpus, 0, sizeof(set->cpus));
85 : 19146 : }
86 : :
87 : : void
88 : 56145 : spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
89 : : {
90 [ - + ]: 56145 : assert(set != NULL);
91 [ - + ]: 56145 : assert(cpu < sizeof(set->cpus) * 8);
92 [ + + ]: 56145 : if (state) {
93 [ - + ]: 55909 : set->cpus[cpu / 8] |= (1U << (cpu % 8));
94 : : } else {
95 [ - + ]: 236 : set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
96 : : }
97 : 56145 : }
98 : :
99 : : bool
100 : 26508570 : spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
101 : : {
102 [ - + ]: 26508570 : assert(set != NULL);
103 [ - + ]: 26508570 : assert(cpu < sizeof(set->cpus) * 8);
104 [ - + ]: 26508570 : return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
105 : : }
106 : :
107 : : void
108 : 8550 : 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 [ + + ]: 1102950 : for (i = 0; i < sizeof(set->cpus); i++) {
114 : 1094400 : n = set->cpus[i];
115 [ + + ]: 9849600 : for (j = 0; j < 8; j++) {
116 [ + + + + ]: 8755200 : if (n & (1 << j)) {
117 : 14939 : fn(ctx, i * 8 + j);
118 : : }
119 : : }
120 : : }
121 : 8550 : }
122 : :
123 : : static void
124 : 14887 : count_fn(void *ctx, uint32_t cpu)
125 : : {
126 : 14887 : uint32_t *count = ctx;
127 : :
128 : 14887 : (*count)++;
129 : 14887 : }
130 : :
131 : : uint32_t
132 : 8546 : spdk_cpuset_count(const struct spdk_cpuset *set)
133 : : {
134 : 8546 : uint32_t count = 0;
135 : :
136 : 8546 : spdk_cpuset_for_each_cpu(set, count_fn, &count);
137 : 8546 : return count;
138 : : }
139 : :
140 : : const char *
141 : 2328 : spdk_cpuset_fmt(struct spdk_cpuset *set)
142 : : {
143 : 2328 : uint32_t lcore, lcore_max = 0;
144 : : int val, i, n;
145 : : char *ptr;
146 : : static const char *hex = "0123456789abcdef";
147 : :
148 [ - + ]: 2328 : assert(set != NULL);
149 : :
150 [ + + ]: 2386200 : for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
151 [ + + ]: 2383872 : if (spdk_cpuset_get_cpu(set, lcore)) {
152 : 8475 : lcore_max = lcore;
153 : : }
154 : : }
155 : :
156 : 2328 : ptr = set->str;
157 : 2328 : n = lcore_max / 8;
158 : 2328 : val = set->cpus[n];
159 : :
160 : : /* Store first number only if it is not leading zero */
161 [ + + ]: 2328 : if ((val & 0xf0) != 0) {
162 : 234 : *(ptr++) = hex[(val & 0xf0) >> 4];
163 : : }
164 : 2328 : *(ptr++) = hex[val & 0x0f];
165 : :
166 [ + + ]: 3768 : for (i = n - 1; i >= 0; i--) {
167 : 1440 : val = set->cpus[i];
168 : 1440 : *(ptr++) = hex[(val & 0xf0) >> 4];
169 : 1440 : *(ptr++) = hex[val & 0x0f];
170 : : }
171 : 2328 : *ptr = '\0';
172 : :
173 : 2328 : return set->str;
174 : : }
175 : :
176 : : static int
177 : 2235 : 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 : 2235 : return val[c] - 1;
189 : : }
190 : :
191 : : static int
192 : 49 : parse_list(const char *mask, struct spdk_cpuset *set)
193 : : {
194 : 46 : char *end;
195 : 49 : const char *ptr = mask;
196 : : uint32_t lcore;
197 : : uint32_t lcore_min, lcore_max;
198 : :
199 : 49 : spdk_cpuset_zero(set);
200 : 49 : lcore_min = UINT32_MAX;
201 : :
202 : 49 : ptr++;
203 : 49 : end = (char *)ptr;
204 : : do {
205 [ - + ]: 91 : while (isblank(*ptr)) {
206 : 0 : ptr++;
207 : : }
208 [ + + + + : 91 : if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
+ + + + ]
209 : 20 : goto invalid_character;
210 : : }
211 : :
212 : 71 : errno = 0;
213 [ - + ]: 71 : lcore = strtoul(ptr, &end, 10);
214 [ + + ]: 71 : if (errno) {
215 : 4 : SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
216 : 4 : return -1;
217 : : }
218 : :
219 [ + + ]: 67 : if (lcore >= sizeof(set->cpus) * 8) {
220 : 4 : SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
221 : 4 : return -1;
222 : : }
223 : :
224 [ - + ]: 63 : while (isblank(*end)) {
225 : 0 : end++;
226 : : }
227 : :
228 [ + + ]: 63 : if (*end == '-') {
229 : 24 : lcore_min = lcore;
230 [ + + + - ]: 39 : } else if (*end == ',' || *end == ']') {
231 : 39 : lcore_max = lcore;
232 [ + + ]: 39 : if (lcore_min == UINT32_MAX) {
233 : 19 : lcore_min = lcore;
234 : : }
235 [ + + ]: 39 : if (lcore_min > lcore_max) {
236 : 4 : SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
237 : : lcore_min, lcore_max);
238 : 4 : return -1;
239 : : }
240 [ + + ]: 4710 : for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
241 : 4675 : spdk_cpuset_set_cpu(set, lcore, true);
242 : : }
243 : 35 : lcore_min = UINT32_MAX;
244 : : } else {
245 : 0 : goto invalid_character;
246 : : }
247 : :
248 : 59 : ptr = end + 1;
249 : :
250 [ + + ]: 59 : } while (*end != ']');
251 : :
252 : 17 : return 0;
253 : :
254 : 20 : invalid_character:
255 [ + + ]: 20 : if (*end == '\0') {
256 : 4 : SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
257 : : } else {
258 : 16 : SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
259 : : }
260 : 20 : return -1;
261 : : }
262 : :
263 : : static int
264 : 457 : parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
265 : : {
266 : : int i, j;
267 : : char c;
268 : : int val;
269 : 457 : uint32_t lcore = 0;
270 : :
271 [ + + + + : 457 : if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
- + ]
272 : 325 : mask += 2;
273 : 325 : len -= 2;
274 : : }
275 : :
276 : 457 : spdk_cpuset_zero(set);
277 [ + + ]: 2892 : for (i = len - 1; i >= 0; i--) {
278 : 2435 : c = mask[i];
279 [ + + ]: 2435 : if (c == ',') {
280 : : /* Linux puts comma delimiters in its cpumasks, just skip them. */
281 : 200 : continue;
282 : : }
283 : 2235 : val = hex_value(c);
284 [ - + ]: 2235 : 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 [ + + + - ]: 11175 : for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
290 [ + + + + ]: 8940 : if ((1 << j) & val) {
291 : 1418 : spdk_cpuset_set_cpu(set, lcore, true);
292 : : }
293 : : }
294 : : }
295 : :
296 : 457 : return 0;
297 : : }
298 : :
299 : : int
300 : 518 : spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
301 : : {
302 : : int ret;
303 : : size_t len;
304 : :
305 [ + + + + ]: 518 : if (mask == NULL || set == NULL) {
306 : 8 : return -1;
307 : : }
308 : :
309 [ - + ]: 510 : while (isblank(*mask)) {
310 : 0 : mask++;
311 : : }
312 : :
313 [ - + ]: 510 : len = strlen(mask);
314 [ + + - + ]: 510 : while (len > 0 && isblank(mask[len - 1])) {
315 : 0 : len--;
316 : : }
317 : :
318 [ + + ]: 510 : if (len == 0) {
319 : 4 : return -1;
320 : : }
321 : :
322 [ + + ]: 506 : if (mask[0] == '[') {
323 : 49 : ret = parse_list(mask, set);
324 : : } else {
325 : 457 : ret = parse_mask(mask, set, len);
326 : : }
327 : :
328 : 506 : return ret;
329 : : }
|