]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/lib/util/cpuset.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / lib / util / cpuset.c
CommitLineData
11fdf7f2
TL
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
37struct spdk_cpuset {
9f95a23c 38 char str[SPDK_CPUSET_SIZE / 4 + 1];
11fdf7f2
TL
39 uint8_t cpus[SPDK_CPUSET_SIZE / 8];
40};
41
42struct spdk_cpuset *
43spdk_cpuset_alloc(void)
44{
45 return (struct spdk_cpuset *)calloc(sizeof(struct spdk_cpuset), 1);
46}
47
48void
49spdk_cpuset_free(struct spdk_cpuset *set)
50{
51 free(set);
52}
53
54bool
55spdk_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
62void
9f95a23c 63spdk_cpuset_copy(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
11fdf7f2 64{
9f95a23c
TL
65 assert(dst != NULL);
66 assert(src != NULL);
67 memcpy(&dst->cpus, &src->cpus, sizeof(src->cpus));
11fdf7f2
TL
68}
69
70void
9f95a23c 71spdk_cpuset_negate(struct spdk_cpuset *set)
11fdf7f2
TL
72{
73 unsigned int i;
9f95a23c
TL
74 assert(set != NULL);
75 for (i = 0; i < sizeof(set->cpus); i++) {
76 set->cpus[i] = ~set->cpus[i];
11fdf7f2
TL
77 }
78}
79
80void
9f95a23c 81spdk_cpuset_and(struct spdk_cpuset *dst, const struct spdk_cpuset *src)
11fdf7f2
TL
82{
83 unsigned int i;
9f95a23c
TL
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
91void
92spdk_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
102void
103spdk_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];
11fdf7f2
TL
110 }
111}
112
113void
114spdk_cpuset_zero(struct spdk_cpuset *set)
115{
116 assert(set != NULL);
117 memset(set->cpus, 0, sizeof(set->cpus));
118}
119
120void
121spdk_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
132bool
133spdk_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
140uint32_t
141spdk_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
156const char *
157spdk_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
192static int
193hex_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
207static int
208parse_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
270invalid_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
279static int
280parse_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
311int
312spdk_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}