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 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
20 #include <sys/syscall.h>
24 static inline int val_to_char(int v
)
28 else if (v
>= 10 && v
< 16)
29 return ('a' - 10) + v
;
34 static inline int char_to_val(int c
)
39 if (c
>= '0' && c
<= '9')
41 else if (cl
>= 'a' && cl
<= 'f')
42 return cl
+ (10 - 'a');
47 static const char *nexttoken(const char *q
, int sep
)
57 * Number of bits in a CPU bitmask on current system
59 int get_max_number_of_cpus(void)
63 cpu_set_t
*set
= cpuset_alloc(cpus
, &setsize
, NULL
);
66 return -1; /* error */
69 CPU_ZERO_S(setsize
, set
);
71 /* the library version does not return size of cpumask_t */
72 n
= syscall(SYS_sched_getaffinity
, 0, setsize
, set
);
74 if (n
< 0 && errno
== EINVAL
&& cpus
< 1024 * 1024) {
77 set
= cpuset_alloc(cpus
, &setsize
, NULL
);
79 return -1; /* error */
89 * Allocates a new set for ncpus and returns size in bytes and size in bits
91 cpu_set_t
*cpuset_alloc(int ncpus
, size_t *setsize
, size_t *nbits
)
93 cpu_set_t
*set
= CPU_ALLOC(ncpus
);
98 *setsize
= CPU_ALLOC_SIZE(ncpus
);
100 *nbits
= cpuset_nbits(CPU_ALLOC_SIZE(ncpus
));
104 void cpuset_free(cpu_set_t
*set
)
109 #if !HAVE_DECL_CPU_ALLOC
110 /* Please, use CPU_COUNT_S() macro. This is fallback */
111 int __cpuset_count_s(size_t setsize
, const cpu_set_t
*set
)
114 const __cpu_mask
*p
= set
->__bits
;
115 const __cpu_mask
*end
= &set
->__bits
[setsize
/ sizeof (__cpu_mask
)];
123 l
= (l
& 0x5555555555555555ul
) + ((l
>> 1) & 0x5555555555555555ul
);
124 l
= (l
& 0x3333333333333333ul
) + ((l
>> 2) & 0x3333333333333333ul
);
125 l
= (l
& 0x0f0f0f0f0f0f0f0ful
) + ((l
>> 4) & 0x0f0f0f0f0f0f0f0ful
);
126 l
= (l
& 0x00ff00ff00ff00fful
) + ((l
>> 8) & 0x00ff00ff00ff00fful
);
127 l
= (l
& 0x0000ffff0000fffful
) + ((l
>> 16) & 0x0000ffff0000fffful
);
128 l
= (l
& 0x00000000fffffffful
) + ((l
>> 32) & 0x00000000fffffffful
);
130 l
= (l
& 0x55555555ul
) + ((l
>> 1) & 0x55555555ul
);
131 l
= (l
& 0x33333333ul
) + ((l
>> 2) & 0x33333333ul
);
132 l
= (l
& 0x0f0f0f0ful
) + ((l
>> 4) & 0x0f0f0f0ful
);
133 l
= (l
& 0x00ff00fful
) + ((l
>> 8) & 0x00ff00fful
);
134 l
= (l
& 0x0000fffful
) + ((l
>> 16) & 0x0000fffful
);
143 * Returns human readable representation of the cpuset. The output format is
144 * a list of CPUs with ranges (for example, "0,1,3-9").
146 char *cpulist_create(char *str
, size_t len
,
147 cpu_set_t
*set
, size_t setsize
)
152 size_t max
= cpuset_nbits(setsize
);
154 for (i
= 0; i
< max
; i
++) {
155 if (CPU_ISSET_S(i
, setsize
, set
)) {
159 for (j
= i
+ 1; j
< max
; j
++) {
160 if (CPU_ISSET_S(j
, setsize
, set
))
166 rlen
= snprintf(ptr
, len
, "%d,", i
);
168 rlen
= snprintf(ptr
, len
, "%d,%d,", i
, i
+ 1);
171 rlen
= snprintf(ptr
, len
, "%d-%d,", i
, i
+ run
);
174 if (rlen
< 0 || rlen
+ 1 > len
)
187 * Returns string with CPU mask.
189 char *cpumask_create(char *str
, size_t len
,
190 cpu_set_t
*set
, size_t setsize
)
196 for (cpu
= cpuset_nbits(setsize
) - 4; cpu
>= 0; cpu
-= 4) {
199 if (len
== (ptr
- str
))
202 if (CPU_ISSET_S(cpu
, setsize
, set
))
204 if (CPU_ISSET_S(cpu
+ 1, setsize
, set
))
206 if (CPU_ISSET_S(cpu
+ 2, setsize
, set
))
208 if (CPU_ISSET_S(cpu
+ 3, setsize
, set
))
213 *ptr
++ = val_to_char(val
);
216 return ret
? ret
: ptr
- 1;
220 * Parses string with list of CPU ranges.
222 int cpumask_parse(const char *str
, cpu_set_t
*set
, size_t setsize
)
224 int len
= strlen(str
);
225 const char *ptr
= str
+ len
- 1;
228 /* skip 0x, it's all hex anyway */
229 if (len
> 1 && !memcmp(str
, "0x", 2L))
232 CPU_ZERO_S(setsize
, set
);
237 /* cpu masks in /sys uses comma as a separator */
241 val
= char_to_val(*ptr
);
242 if (val
== (char) -1)
245 CPU_SET_S(cpu
, setsize
, set
);
247 CPU_SET_S(cpu
+ 1, setsize
, set
);
249 CPU_SET_S(cpu
+ 2, setsize
, set
);
251 CPU_SET_S(cpu
+ 3, setsize
, set
);
261 * Parses string with CPUs mask.
263 int cpulist_parse(const char *str
, cpu_set_t
*set
, size_t setsize
)
268 CPU_ZERO_S(setsize
, set
);
270 while (p
= q
, q
= nexttoken(q
, ','), p
) {
271 unsigned int a
; /* beginning of range */
272 unsigned int b
; /* end of range */
273 unsigned int s
; /* stride */
276 if (sscanf(p
, "%u", &a
) < 1)
281 c1
= nexttoken(p
, '-');
282 c2
= nexttoken(p
, ',');
283 if (c1
!= NULL
&& (c2
== NULL
|| c1
< c2
)) {
284 if (sscanf(c1
, "%u", &b
) < 1)
286 c1
= nexttoken(c1
, ':');
287 if (c1
!= NULL
&& (c2
== NULL
|| c1
< c2
))
288 if (sscanf(c1
, "%u", &s
) < 1) {
296 CPU_SET_S(a
, setsize
, set
);
309 int main(int argc
, char *argv
[])
312 size_t setsize
, buflen
, nbits
;
313 char *buf
, *mask
= NULL
, *range
= NULL
;
314 int ncpus
= 2048, rc
, c
;
316 struct option longopts
[] = {
317 { "ncpus", 1, 0, 'n' },
318 { "mask", 1, 0, 'm' },
319 { "range", 1, 0, 'r' },
323 while ((c
= getopt_long(argc
, argv
, "n:m:r:", longopts
, NULL
)) != -1) {
326 ncpus
= atoi(optarg
);
329 mask
= strdup(optarg
);
332 range
= strdup(optarg
);
342 set
= cpuset_alloc(ncpus
, &setsize
, &nbits
);
344 err(EXIT_FAILURE
, "failed to allocate cpu set");
347 fprintf(stderr, "ncpus: %d, cpuset bits: %zd, cpuset bytes: %zd\n",
348 ncpus, nbits, setsize);
352 buf
= malloc(buflen
);
354 err(EXIT_FAILURE
, "failed to allocate cpu set buffer");
357 rc
= cpumask_parse(mask
, set
, setsize
);
359 rc
= cpulist_parse(range
, set
, setsize
);
362 errx(EXIT_FAILURE
, "failed to parse string: %s", mask
? : range
);
364 printf("%-15s = %15s ", mask
? : range
,
365 cpumask_create(buf
, buflen
, set
, setsize
));
366 printf("[%s]\n", cpulist_create(buf
, buflen
, set
, setsize
));
375 "usage: %s [--ncpus <num>] --mask <mask> | --range <list>",
376 program_invocation_short_name
);