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