24
16
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26
18
* Copyright (C) 2004 Robert Love
19
* Copyright (C) 2010 Karel Zak <kzak@redhat.com>
30
23
#include <stdlib.h>
31
24
#include <unistd.h>
32
25
#include <getopt.h>
37
#include <sys/syscall.h>
44
static void show_usage(const char *cmd)
46
fprintf(stderr, "taskset (%s)\n", PACKAGE_STRING);
47
fprintf(stderr, "usage: %s [options] [mask | cpu-list] [pid |"\
48
" cmd [args...]]\n", cmd);
49
fprintf(stderr, "set or get the affinity of a process\n\n");
50
fprintf(stderr, " -p, --pid "
51
"operate on existing given pid\n");
52
fprintf(stderr, " -c, --cpu-list "\
53
"display and specify cpus in list format\n");
54
fprintf(stderr, " -h, --help display this help\n");
55
fprintf(stderr, " -V, --version "\
56
"output version information\n\n");
57
fprintf(stderr, "The default behavior is to run a new command:\n");
58
fprintf(stderr, " %s 03 sshd -b 1024\n", cmd);
59
fprintf(stderr, "You can retrieve the mask of an existing task:\n");
60
fprintf(stderr, " %s -p 700\n", cmd);
61
fprintf(stderr, "Or set it:\n");
62
fprintf(stderr, " %s -p 03 700\n", cmd);
63
fprintf(stderr, "List format uses a comma-separated list instead"\
65
fprintf(stderr, " %s -pc 0,3,7-11 700\n", cmd);
66
fprintf(stderr, "Ranges in list format can take a stride argument:\n");
67
fprintf(stderr, " e.g. 0-31:2 is equivalent to mask 0x55555555\n\n");
70
static inline int val_to_char(int v)
74
else if (v >= 10 && v < 16)
75
return ('a' - 10) + v;
81
* The following bitmask declarations, bitmask_*() routines, and associated
82
* _setbit() and _getbit() routines are:
83
* Copyright (c) 2004 Silicon Graphics, Inc. (SGI) All rights reserved.
84
* SGI publishes it under the terms of the GNU General Public License, v2,
85
* as published by the Free Software Foundation.
87
#define howmany(x,y) (((x)+((y)-1))/(y))
88
#define bitsperlong (8 * sizeof(unsigned long))
89
#define longsperbits(n) howmany(n, bitsperlong)
90
#define bytesperbits(x) ((x+7)/8)
92
static unsigned int _getbit(const struct bitmask *bmp, unsigned int n)
95
return (bmp->maskp[n/bitsperlong] >> (n % bitsperlong)) & 1;
100
static void _setbit(struct bitmask *bmp, unsigned int n, unsigned int v)
104
bmp->maskp[n/bitsperlong] |= 1UL << (n % bitsperlong);
106
bmp->maskp[n/bitsperlong] &= ~(1UL << (n % bitsperlong));
110
int bitmask_isbitset(const struct bitmask *bmp, unsigned int i)
112
return _getbit(bmp, i);
115
struct bitmask *bitmask_clearall(struct bitmask *bmp)
118
for (i = 0; i < bmp->size; i++)
123
struct bitmask *bitmask_setbit(struct bitmask *bmp, unsigned int i)
129
unsigned int bitmask_nbytes(struct bitmask *bmp)
131
return longsperbits(bmp->size) * sizeof(unsigned long);
134
static char * cpuset_to_str(struct bitmask *mask, char *str)
140
for (base = mask->size - 4; base >= 0; base -= 4) {
142
if (bitmask_isbitset(mask, base))
144
if (bitmask_isbitset(mask, base + 1))
146
if (bitmask_isbitset(mask, base + 2))
148
if (bitmask_isbitset(mask, base + 3))
152
*ptr++ = val_to_char(val);
155
return ret ? ret : ptr - 1;
158
struct bitmask *bitmask_alloc(unsigned int n)
162
bmp = malloc(sizeof(*bmp));
166
bmp->maskp = calloc(longsperbits(n), sizeof(unsigned long));
174
static char * cpuset_to_cstr(struct bitmask *mask, char *str)
180
for (i = 0; i < mask->size; i++) {
181
if (bitmask_isbitset(mask, i)) {
185
for (j = i + 1; j < mask->size; j++) {
186
if (bitmask_isbitset(mask, j))
192
sprintf(ptr, "%d,", i);
194
sprintf(ptr, "%d,%d,", i, i + 1);
197
sprintf(ptr, "%d-%d,", i, i + run);
210
static inline int char_to_val(int c)
215
if (c >= '0' && c <= '9')
217
else if (cl >= 'a' && cl <= 'f')
218
return cl + (10 - 'a');
223
static int str_to_cpuset(struct bitmask *mask, const char* str)
225
int len = strlen(str);
226
const char *ptr = str + len - 1;
229
/* skip 0x, it's all hex anyway */
230
if (len > 1 && !memcmp(str, "0x", 2L))
233
bitmask_clearall(mask);
235
char val = char_to_val(*ptr);
236
if (val == (char) -1)
239
bitmask_setbit(mask, base);
241
bitmask_setbit(mask, base + 1);
243
bitmask_setbit(mask, base + 2);
245
bitmask_setbit(mask, base + 3);
254
static const char *nexttoken(const char *q, int sep)
263
static int cstr_to_cpuset(struct bitmask *mask, const char* str)
267
bitmask_clearall(mask);
269
while (p = q, q = nexttoken(q, ','), p) {
270
unsigned int a; /* beginning of range */
271
unsigned int b; /* end of range */
272
unsigned int s; /* stride */
275
if (sscanf(p, "%u", &a) < 1)
280
c1 = nexttoken(p, '-');
281
c2 = nexttoken(p, ',');
282
if (c1 != NULL && (c2 == NULL || c1 < c2)) {
283
if (sscanf(c1, "%u", &b) < 1)
285
c1 = nexttoken(c1, ':');
286
if (c1 != NULL && (c2 == NULL || c1 < c2))
287
if (sscanf(c1, "%u", &s) < 1) {
295
bitmask_setbit(mask, a);
304
* Number of bits in a CPU bitmask on current system
307
max_number_of_cpus(void)
313
unsigned long buffer[longsperbits(cpus)];
314
memset(buffer, 0, sizeof(buffer));
315
/* the library version does not return size of cpumask_t */
316
n = syscall(SYS_sched_getaffinity, 0, bytesperbits(cpus),
318
if (n < 0 && errno == EINVAL && cpus < 1024*1024) {
324
fprintf (stderr, "cannot determine NR_CPUS; aborting");
34
static void __attribute__((__noreturn__)) usage(FILE *out)
37
_("Usage: %s [options] [mask | cpu-list] [pid|cmd [args...]]\n\n"),
38
program_invocation_short_name);
42
" -p, --pid operate on existing given pid\n"
43
" -c, --cpu-list display and specify cpus in list format\n"
44
" -h, --help display this help\n"
45
" -V, --version output version information\n\n"));
48
"The default behavior is to run a new command:\n"
49
" %1$s 03 sshd -b 1024\n"
50
"You can retrieve the mask of an existing task:\n"
54
"List format uses a comma-separated list instead of a mask:\n"
55
" %1$s -pc 0,3,7-11 700\n"
56
"Ranges in list format can take a stride argument:\n"
57
" e.g. 0-31:2 is equivalent to mask 0x55555555\n"),
58
program_invocation_short_name);
60
fprintf(out, _("\nFor more information see taskset(1).\n"));
62
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
329
65
int main(int argc, char *argv[])
331
struct bitmask *new_mask, *cur_mask;
67
cpu_set_t *new_set, *cur_set;
337
unsigned int cpus_configured;
338
int new_mask_byte_size, cur_mask_byte_size;
69
int opt, c_opt = 0, rc;
72
size_t new_setsize, cur_setsize, cur_nbits, buflen;
340
74
struct option longopts[] = {
341
75
{ "pid", 0, NULL, 'p' },
345
79
{ NULL, 0, NULL, 0 }
82
setlocale(LC_ALL, "");
83
bindtextdomain(PACKAGE, LOCALEDIR);
348
86
while ((opt = getopt_long(argc, argv, "+pchV", longopts, NULL)) != -1) {
353
pid = atoi(argv[argc - 1]);
89
pid = strtol_or_err(argv[argc - 1], _("failed to parse pid"));
359
95
printf("taskset (%s)\n", PACKAGE_STRING);
369
106
if ((!pid && argc - optind < 2)
370
|| (pid && (argc - optind < 1 || argc - optind > 2))) {
107
|| (pid && (argc - optind < 1 || argc - optind > 2)))
375
cpus_configured = max_number_of_cpus();
110
ncpus = get_max_number_of_cpus();
112
errx(EXIT_FAILURE, _("cannot determine NR_CPUS; aborting"));
378
* cur_mask is always used for the sched_getaffinity call
115
* cur_set is always used for the sched_getaffinity call
379
116
* On the sched_getaffinity the kernel demands a user mask of
380
117
* at least the size of its own cpumask_t.
382
cur_mask = bitmask_alloc(cpus_configured);
384
fprintf (stderr, "bitmask_alloc failed\n");
387
cur_mask_byte_size = bitmask_nbytes(cur_mask);
388
mstr = malloc(1 + cur_mask->size / 4);
389
cstr = malloc(7 * cur_mask->size);
119
cur_set = cpuset_alloc(ncpus, &cur_setsize, &cur_nbits);
121
err(EXIT_FAILURE, _("cpuset_alloc failed"));
123
buflen = 7 * cur_nbits;
124
buf = malloc(buflen);
126
err(EXIT_FAILURE, _("malloc failed"));
392
* new_mask is always used for the sched_setaffinity call
129
* new_set is always used for the sched_setaffinity call
393
130
* On the sched_setaffinity the kernel will zero-fill its
394
131
* cpumask_t if the user's mask is shorter.
396
new_mask = bitmask_alloc(cpus_configured);
398
fprintf (stderr, "bitmask_alloc failed\n");
401
new_mask_byte_size = bitmask_nbytes(new_mask);
133
new_set = cpuset_alloc(ncpus, &new_setsize, NULL);
135
err(EXIT_FAILURE, _("cpuset_alloc failed"));
404
if (sched_getaffinity(pid, cur_mask_byte_size,
405
(cpu_set_t *)cur_mask->maskp) < 0) {
406
perror("sched_getaffinity");
407
fprintf(stderr, "failed to get pid %d's affinity\n",
138
if (sched_getaffinity(pid, cur_setsize, cur_set) < 0)
139
err(EXIT_FAILURE, _("failed to get pid %d's affinity"), pid);
412
printf("pid %d's current affinity list: %s\n", pid,
413
cpuset_to_cstr(cur_mask, cstr));
142
printf(_("pid %d's current affinity list: %s\n"), pid,
143
cpulist_create(buf, buflen, cur_set, cur_setsize));
415
printf("pid %d's current affinity mask: %s\n", pid,
416
cpuset_to_str(cur_mask, mstr));
145
printf(_("pid %d's current affinity mask: %s\n"), pid,
146
cpumask_create(buf, buflen, cur_set, cur_setsize));
418
148
if (argc - optind == 1)
423
err = cstr_to_cpuset(new_mask, argv[optind]);
425
err = str_to_cpuset(new_mask, argv[optind]);
429
fprintf(stderr, "failed to parse CPU list %s\n",
432
fprintf(stderr, "failed to parse CPU mask %s\n",
437
if (sched_setaffinity(pid, new_mask_byte_size,
438
(cpu_set_t *) new_mask->maskp) < 0) {
439
perror("sched_setaffinity");
440
fprintf(stderr, "failed to set pid %d's affinity.\n", pid);
444
if (sched_getaffinity(pid, cur_mask_byte_size,
445
(cpu_set_t *)cur_mask->maskp) < 0) {
446
perror("sched_getaffinity");
447
fprintf(stderr, "failed to get pid %d's affinity.\n", pid);
152
rc = c_opt ? cpulist_parse(argv[optind], new_set, new_setsize) :
153
cpumask_parse(argv[optind], new_set, new_setsize);
156
errx(EXIT_FAILURE, _("failed to parse %s %s"),
157
c_opt ? _("CPU list") : _("CPU mask"),
160
if (sched_setaffinity(pid, new_setsize, new_set) < 0)
161
err(EXIT_FAILURE, _("failed to set pid %d's affinity"), pid);
163
if (sched_getaffinity(pid, cur_setsize, cur_set) < 0)
164
err(EXIT_FAILURE, _("failed to get pid %d's affinity"), pid);
453
printf("pid %d's new affinity list: %s\n", pid,
454
cpuset_to_cstr(cur_mask, cstr));
168
printf(_("pid %d's new affinity list: %s\n"), pid,
169
cpulist_create(buf, buflen, cur_set, cur_setsize));
456
printf("pid %d's new affinity mask: %s\n", pid,
457
cpuset_to_str(cur_mask, mstr));
171
printf(_("pid %d's new affinity mask: %s\n"), pid,
172
cpumask_create(buf, buflen, cur_set, cur_setsize));
176
cpuset_free(cur_set);
177
cpuset_free(new_set);
459
180
argv += optind + 1;
460
181
execvp(argv[0], argv);
462
fprintf(stderr, "failed to execute %s\n", argv[0]);
182
err(EXIT_FAILURE, _("executing %s failed"), argv[0]);