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);