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(sizeof(struct spdk_cpuset), 1);
13 : }
14 :
15 : void
16 3 : spdk_cpuset_free(struct spdk_cpuset *set)
17 : {
18 3 : free(set);
19 3 : }
20 :
21 : bool
22 0 : spdk_cpuset_equal(const struct spdk_cpuset *set1, const struct spdk_cpuset *set2)
23 : {
24 0 : assert(set1 != NULL);
25 0 : assert(set2 != NULL);
26 0 : return memcmp(set1->cpus, set2->cpus, sizeof(set2->cpus)) == 0;
27 : }
28 :
29 : void
30 51 : spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
31 : {
32 51 : assert(dst != NULL);
33 51 : assert(src != NULL);
34 51 : memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
35 51 : }
36 :
37 : void
38 183 : spdk_cpuset_negate(struct spdk_cpuset *set)
39 : {
40 : unsigned int i;
41 183 : assert(set != NULL);
42 23607 : for (i = 0; i < sizeof(set->cpus); i++) {
43 23424 : set->cpus[i] = ~set->cpus[i];
44 : }
45 183 : }
46 :
47 : void
48 30 : spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
49 : {
50 : unsigned int i;
51 30 : assert(dst != NULL);
52 30 : assert(src != NULL);
53 3870 : for (i = 0; i < sizeof(src->cpus); i++) {
54 3840 : dst->cpus[i] &= src->cpus[i];
55 : }
56 30 : }
57 :
58 : void
59 0 : spdk_cpuset_or(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
60 : {
61 : unsigned int i;
62 0 : assert(dst != NULL);
63 0 : assert(src != NULL);
64 0 : for (i = 0; i < sizeof(src->cpus); i++) {
65 0 : dst->cpus[i] |= src->cpus[i];
66 : }
67 0 : }
68 :
69 : void
70 21 : spdk_cpuset_xor(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
71 : {
72 : unsigned int i;
73 21 : assert(dst != NULL);
74 21 : assert(src != NULL);
75 2709 : for (i = 0; i < sizeof(src->cpus); i++) {
76 2688 : dst->cpus[i] ^= src->cpus[i];
77 : }
78 21 : }
79 :
80 : void
81 87 : spdk_cpuset_zero(struct spdk_cpuset *set)
82 : {
83 87 : assert(set != NULL);
84 87 : memset(set->cpus, 0, sizeof(set->cpus));
85 87 : }
86 :
87 : void
88 3347 : spdk_cpuset_set_cpu(struct spdk_cpuset *set, uint32_t cpu, bool state)
89 : {
90 3347 : assert(set != NULL);
91 3347 : assert(cpu < sizeof(set->cpus) * 8);
92 3347 : if (state) {
93 3344 : set->cpus[cpu / 8] |= (1U << (cpu % 8));
94 : } else {
95 3 : set->cpus[cpu / 8] &= ~(1U << (cpu % 8));
96 : }
97 3347 : }
98 :
99 : bool
100 25690 : spdk_cpuset_get_cpu(const struct spdk_cpuset *set, uint32_t cpu)
101 : {
102 25690 : assert(set != NULL);
103 25690 : assert(cpu < sizeof(set->cpus) * 8);
104 25690 : return (set->cpus[cpu / 8] >> (cpu % 8)) & 1U;
105 : }
106 :
107 : uint32_t
108 37 : spdk_cpuset_count(const struct spdk_cpuset *set)
109 : {
110 37 : uint32_t count = 0;
111 : uint8_t n;
112 : unsigned int i;
113 4773 : for (i = 0; i < sizeof(set->cpus); i++) {
114 4736 : n = set->cpus[i];
115 5799 : while (n) {
116 1063 : n &= (n - 1);
117 1063 : count++;
118 : }
119 : }
120 37 : return count;
121 : }
122 :
123 : const char *
124 11 : spdk_cpuset_fmt(struct spdk_cpuset *set)
125 : {
126 11 : uint32_t lcore, lcore_max = 0;
127 : int val, i, n;
128 : char *ptr;
129 : static const char *hex = "0123456789abcdef";
130 :
131 11 : assert(set != NULL);
132 :
133 11275 : for (lcore = 0; lcore < sizeof(set->cpus) * 8; lcore++) {
134 11264 : if (spdk_cpuset_get_cpu(set, lcore)) {
135 1058 : lcore_max = lcore;
136 : }
137 : }
138 :
139 11 : ptr = set->str;
140 11 : n = lcore_max / 8;
141 11 : val = set->cpus[n];
142 :
143 : /* Store first number only if it is not leading zero */
144 11 : if ((val & 0xf0) != 0) {
145 1 : *(ptr++) = hex[(val & 0xf0) >> 4];
146 : }
147 11 : *(ptr++) = hex[val & 0x0f];
148 :
149 140 : for (i = n - 1; i >= 0; i--) {
150 129 : val = set->cpus[i];
151 129 : *(ptr++) = hex[(val & 0xf0) >> 4];
152 129 : *(ptr++) = hex[val & 0x0f];
153 : }
154 11 : *ptr = '\0';
155 :
156 11 : return set->str;
157 : }
158 :
159 : static int
160 56 : 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 56 : return val[c] - 1;
172 : }
173 :
174 : static int
175 11 : parse_list(const char *mask, struct spdk_cpuset *set)
176 : {
177 11 : char *end;
178 11 : const char *ptr = mask;
179 : uint32_t lcore;
180 : uint32_t lcore_min, lcore_max;
181 :
182 11 : spdk_cpuset_zero(set);
183 11 : lcore_min = UINT32_MAX;
184 :
185 11 : ptr++;
186 11 : end = (char *)ptr;
187 : do {
188 20 : while (isblank(*ptr)) {
189 0 : ptr++;
190 : }
191 20 : if (*ptr == '\0' || *ptr == ']' || *ptr == '-' || *ptr == ',') {
192 5 : goto invalid_character;
193 : }
194 :
195 15 : errno = 0;
196 15 : lcore = strtoul(ptr, &end, 10);
197 15 : if (errno) {
198 1 : SPDK_ERRLOG("Conversion of core mask in '%s' failed\n", mask);
199 1 : return -1;
200 : }
201 :
202 14 : if (lcore >= sizeof(set->cpus) * 8) {
203 1 : SPDK_ERRLOG("Core number %" PRIu32 " is out of range in '%s'\n", lcore, mask);
204 1 : return -1;
205 : }
206 :
207 13 : while (isblank(*end)) {
208 0 : end++;
209 : }
210 :
211 13 : if (*end == '-') {
212 6 : lcore_min = lcore;
213 7 : } else if (*end == ',' || *end == ']') {
214 7 : lcore_max = lcore;
215 7 : if (lcore_min == UINT32_MAX) {
216 2 : lcore_min = lcore;
217 : }
218 7 : if (lcore_min > lcore_max) {
219 1 : SPDK_ERRLOG("Invalid range of CPUs (%" PRIu32 " > %" PRIu32 ")\n",
220 : lcore_min, lcore_max);
221 1 : return -1;
222 : }
223 1172 : for (lcore = lcore_min; lcore <= lcore_max; lcore++) {
224 1166 : spdk_cpuset_set_cpu(set, lcore, true);
225 : }
226 6 : lcore_min = UINT32_MAX;
227 : } else {
228 0 : goto invalid_character;
229 : }
230 :
231 12 : ptr = end + 1;
232 :
233 12 : } while (*end != ']');
234 :
235 3 : return 0;
236 :
237 5 : invalid_character:
238 5 : if (*end == '\0') {
239 1 : SPDK_ERRLOG("Unexpected end of core list '%s'\n", mask);
240 : } else {
241 4 : SPDK_ERRLOG("Parsing of core list '%s' failed on character '%c'\n", mask, *end);
242 : }
243 5 : return -1;
244 : }
245 :
246 : static int
247 12 : parse_mask(const char *mask, struct spdk_cpuset *set, size_t len)
248 : {
249 : int i, j;
250 : char c;
251 : int val;
252 12 : uint32_t lcore = 0;
253 :
254 12 : if (mask[0] == '0' && (mask[1] == 'x' || mask[1] == 'X')) {
255 12 : mask += 2;
256 12 : len -= 2;
257 : }
258 :
259 12 : spdk_cpuset_zero(set);
260 68 : for (i = len - 1; i >= 0; i--) {
261 56 : c = mask[i];
262 56 : val = hex_value(c);
263 56 : if (val < 0) {
264 : /* Invalid character */
265 0 : SPDK_ERRLOG("Invalid character in core mask '%s' (%c)\n", mask, c);
266 0 : return -1;
267 : }
268 280 : for (j = 0; j < 4 && lcore < SPDK_CPUSET_SIZE; j++, lcore++) {
269 224 : if ((1 << j) & val) {
270 36 : spdk_cpuset_set_cpu(set, lcore, true);
271 : }
272 : }
273 : }
274 :
275 12 : return 0;
276 : }
277 :
278 : int
279 26 : spdk_cpuset_parse(struct spdk_cpuset *set, const char *mask)
280 : {
281 : int ret;
282 : size_t len;
283 :
284 26 : if (mask == NULL || set == NULL) {
285 2 : return -1;
286 : }
287 :
288 24 : while (isblank(*mask)) {
289 0 : mask++;
290 : }
291 :
292 24 : len = strlen(mask);
293 24 : while (len > 0 && isblank(mask[len - 1])) {
294 0 : len--;
295 : }
296 :
297 24 : if (len == 0) {
298 1 : return -1;
299 : }
300 :
301 23 : if (mask[0] == '[') {
302 11 : ret = parse_list(mask, set);
303 : } else {
304 12 : ret = parse_mask(mask, set, len);
305 : }
306 :
307 23 : return ret;
308 : }
|