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