4 * cpuset - (libc) cpu_set_t data structure represents set of CPUs
5 * cpumask - string with hex mask (e.g. "0x00000001")
6 * cpulist - string with CPU ranges (e.g. "0-3,5,7,8")
8 * Based on code from taskset.c and Linux kernel.
10 * This file may be redistributed under the terms of the
11 * GNU Lesser General Public License.
13 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
23 #include <sys/syscall.h>
28 static inline int val_to_char(int v
)
32 if (v
>= 10 && v
< 16)
33 return ('a' - 10) + v
;
37 static inline int char_to_val(int c
)
41 if (c
>= '0' && c
<= '9')
44 if (cl
>= 'a' && cl
<= 'f')
45 return cl
+ (10 - 'a');
49 static const char *nexttoken(const char *q
, int sep
)
59 * Number of bits in a CPU bitmask on current system
61 int get_max_number_of_cpus(void)
63 #ifdef SYS_sched_getaffinity
66 cpu_set_t
*set
= cpuset_alloc(cpus
, &setsize
, NULL
);
69 return -1; /* error */
72 CPU_ZERO_S(setsize
, set
);
74 /* the library version does not return size of cpumask_t */
75 n
= syscall(SYS_sched_getaffinity
, 0, setsize
, set
);
77 if (n
< 0 && errno
== EINVAL
&& cpus
< 1024 * 1024) {
80 set
= cpuset_alloc(cpus
, &setsize
, NULL
);
82 return -1; /* error */
93 * Allocates a new set for ncpus and returns size in bytes and size in bits
95 cpu_set_t
*cpuset_alloc(int ncpus
, size_t *setsize
, size_t *nbits
)
97 cpu_set_t
*set
= CPU_ALLOC(ncpus
);
102 *setsize
= CPU_ALLOC_SIZE(ncpus
);
104 *nbits
= cpuset_nbits(CPU_ALLOC_SIZE(ncpus
));
108 void cpuset_free(cpu_set_t
*set
)
113 #if !HAVE_DECL_CPU_ALLOC
114 /* Please, use CPU_COUNT_S() macro. This is fallback */
115 int __cpuset_count_s(size_t setsize
, const cpu_set_t
*set
)
118 const __cpu_mask
*p
= set
->__bits
;
119 const __cpu_mask
*end
= &set
->__bits
[setsize
/ sizeof (__cpu_mask
)];
127 l
= (l
& 0x5555555555555555ul
) + ((l
>> 1) & 0x5555555555555555ul
);
128 l
= (l
& 0x3333333333333333ul
) + ((l
>> 2) & 0x3333333333333333ul
);
129 l
= (l
& 0x0f0f0f0f0f0f0f0ful
) + ((l
>> 4) & 0x0f0f0f0f0f0f0f0ful
);
130 l
= (l
& 0x00ff00ff00ff00fful
) + ((l
>> 8) & 0x00ff00ff00ff00fful
);
131 l
= (l
& 0x0000ffff0000fffful
) + ((l
>> 16) & 0x0000ffff0000fffful
);
132 l
= (l
& 0x00000000fffffffful
) + ((l
>> 32) & 0x00000000fffffffful
);
134 l
= (l
& 0x55555555ul
) + ((l
>> 1) & 0x55555555ul
);
135 l
= (l
& 0x33333333ul
) + ((l
>> 2) & 0x33333333ul
);
136 l
= (l
& 0x0f0f0f0ful
) + ((l
>> 4) & 0x0f0f0f0ful
);
137 l
= (l
& 0x00ff00fful
) + ((l
>> 8) & 0x00ff00fful
);
138 l
= (l
& 0x0000fffful
) + ((l
>> 16) & 0x0000fffful
);
147 * Returns human readable representation of the cpuset. The output format is
148 * a list of CPUs with ranges (for example, "0,1,3-9").
150 char *cpulist_create(char *str
, size_t len
,
151 cpu_set_t
*set
, size_t setsize
)
156 size_t max
= cpuset_nbits(setsize
);
158 for (i
= 0; i
< max
; i
++) {
159 if (CPU_ISSET_S(i
, setsize
, set
)) {
163 for (j
= i
+ 1; j
< max
; j
++) {
164 if (CPU_ISSET_S(j
, setsize
, set
))
170 rlen
= snprintf(ptr
, len
, "%zu,", i
);
172 rlen
= snprintf(ptr
, len
, "%zu,%zu,", i
, i
+ 1);
175 rlen
= snprintf(ptr
, len
, "%zu-%zu,", i
, i
+ run
);
178 if (rlen
< 0 || (size_t) rlen
>= len
)
191 * Returns string with CPU mask.
193 char *cpumask_create(char *str
, size_t len
,
194 cpu_set_t
*set
, size_t setsize
)
200 for (cpu
= cpuset_nbits(setsize
) - 4; cpu
>= 0; cpu
-= 4) {
203 if (len
== (size_t) (ptr
- str
))
206 if (CPU_ISSET_S(cpu
, setsize
, set
))
208 if (CPU_ISSET_S(cpu
+ 1, setsize
, set
))
210 if (CPU_ISSET_S(cpu
+ 2, setsize
, set
))
212 if (CPU_ISSET_S(cpu
+ 3, setsize
, set
))
217 *ptr
++ = val_to_char(val
);
220 return ret
? ret
: ptr
- 1;
224 * Parses string with CPUs mask.
226 int cpumask_parse(const char *str
, cpu_set_t
*set
, size_t setsize
)
228 int len
= strlen(str
);
229 const char *ptr
= str
+ len
- 1;
232 /* skip 0x, it's all hex anyway */
233 if (len
> 1 && !memcmp(str
, "0x", 2L))
236 CPU_ZERO_S(setsize
, set
);
241 /* cpu masks in /sys uses comma as a separator */
245 val
= char_to_val(*ptr
);
246 if (val
== (char) -1)
249 CPU_SET_S(cpu
, setsize
, set
);
251 CPU_SET_S(cpu
+ 1, setsize
, set
);
253 CPU_SET_S(cpu
+ 2, setsize
, set
);
255 CPU_SET_S(cpu
+ 3, setsize
, set
);
263 static int nextnumber(const char *str
, char **end
, unsigned int *result
)
266 if (str
== NULL
|| *str
== '\0' || !isdigit(*str
))
268 *result
= (unsigned int) strtoul(str
, end
, 10);
277 * Parses string with list of CPU ranges.
278 * Returns 0 on success.
279 * Returns 1 on error.
280 * Returns 2 if fail is set and a cpu number passed in the list doesn't fit
281 * into the cpu_set. If fail is not set cpu numbers that do not fit are
282 * ignored and 0 is returned instead.
284 int cpulist_parse(const char *str
, cpu_set_t
*set
, size_t setsize
, int fail
)
286 size_t max
= cpuset_nbits(setsize
);
291 CPU_ZERO_S(setsize
, set
);
293 while (p
= q
, q
= nexttoken(q
, ','), p
) {
294 unsigned int a
; /* beginning of range */
295 unsigned int b
; /* end of range */
296 unsigned int s
; /* stride */
299 if (nextnumber(p
, &end
, &a
) != 0)
305 c1
= nexttoken(p
, '-');
306 c2
= nexttoken(p
, ',');
308 if (c1
!= NULL
&& (c2
== NULL
|| c1
< c2
)) {
309 if (nextnumber(c1
, &end
, &b
) != 0)
312 c1
= end
&& *end
? nexttoken(end
, ':') : NULL
;
314 if (c1
!= NULL
&& (c2
== NULL
|| c1
< c2
)) {
315 if (nextnumber(c1
, &end
, &s
) != 0)
325 if (fail
&& (a
>= max
))
327 CPU_SET_S(a
, setsize
, set
);
337 #ifdef TEST_PROGRAM_CPUSET
341 int main(int argc
, char *argv
[])
344 size_t setsize
, buflen
, nbits
;
345 char *buf
, *mask
= NULL
, *range
= NULL
;
346 int ncpus
= 2048, rc
, c
;
348 static const struct option longopts
[] = {
349 { "ncpus", 1, NULL
, 'n' },
350 { "mask", 1, NULL
, 'm' },
351 { "range", 1, NULL
, 'r' },
355 while ((c
= getopt_long(argc
, argv
, "n:m:r:", longopts
, NULL
)) != -1) {
358 ncpus
= atoi(optarg
);
361 mask
= strdup(optarg
);
364 range
= strdup(optarg
);
374 set
= cpuset_alloc(ncpus
, &setsize
, &nbits
);
376 err(EXIT_FAILURE
, "failed to allocate cpu set");
379 fprintf(stderr, "ncpus: %d, cpuset bits: %zd, cpuset bytes: %zd\n",
380 ncpus, nbits, setsize);
384 buf
= malloc(buflen
);
386 err(EXIT_FAILURE
, "failed to allocate cpu set buffer");
389 rc
= cpumask_parse(mask
, set
, setsize
);
391 rc
= cpulist_parse(range
, set
, setsize
, 0);
394 errx(EXIT_FAILURE
, "failed to parse string: %s", mask
? : range
);
396 printf("%-15s = %15s ", mask
? : range
,
397 cpumask_create(buf
, buflen
, set
, setsize
));
398 printf("[%s]\n", cpulist_create(buf
, buflen
, set
, setsize
));
409 "usage: %s [--ncpus <num>] --mask <mask> | --range <list>\n",
410 program_invocation_short_name
);