1/* taskset.c - Retrieve or set the CPU affinity of a process. 2 * 3 * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com> 4 5USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_BIN|TOYFLAG_STAYROOT)) 6USE_NPROC(NEWTOY(nproc, "(all)", TOYFLAG_USR|TOYFLAG_BIN)) 7 8config NPROC 9 bool "nproc" 10 default y 11 help 12 usage: nproc [--all] 13 14 Print number of processors. 15 16 --all Show all processors, not just ones this task can run on 17 18config TASKSET 19 bool "taskset" 20 default y 21 help 22 usage: taskset [-ap] [mask] [PID | cmd [args...]] 23 24 Launch a new task which may only run on certain processors, or change 25 the processor affinity of an exisitng PID. 26 27 Mask is a hex string where each bit represents a processor the process 28 is allowed to run on. PID without a mask displays existing affinity. 29 30 -p Set/get the affinity of given PID instead of a new command 31 -a Set/get the affinity of all threads of the PID 32*/ 33 34#define FOR_taskset 35#include "toys.h" 36 37#include <sys/syscall.h> 38#define sched_setaffinity(pid, size, cpuset) \ 39 syscall(__NR_sched_setaffinity, (pid_t)pid, (size_t)size, (void *)cpuset) 40#define sched_getaffinity(pid, size, cpuset) \ 41 syscall(__NR_sched_getaffinity, (pid_t)pid, (size_t)size, (void *)cpuset) 42 43// mask is an array of long, which makes the layout a bit weird on big 44// endian systems but as long as it's consistent... 45 46static void do_taskset(pid_t pid, int quiet) 47{ 48 unsigned long *mask = (unsigned long *)toybuf; 49 char *s = *toys.optargs, *failed = "failed to %s %d's affinity"; 50 int i, j, k; 51 52 for (i=0; ; i++) { 53 if (!quiet) { 54 int j = sizeof(toybuf), flag = 0; 55 56 if (-1 == sched_getaffinity(pid, sizeof(toybuf), (void *)mask)) 57 perror_exit(failed, "get", pid); 58 59 printf("pid %d's %s affinity mask: ", pid, i ? "new" : "current"); 60 61 while (j--) { 62 int x = 255 & (mask[j/sizeof(long)] >> (8*(j&(sizeof(long)-1)))); 63 64 if (flag) printf("%02x", x); 65 else if (x) { 66 flag++; 67 printf("%x", x); 68 } 69 } 70 putchar('\n'); 71 } 72 73 if (i || toys.optc < 2) return; 74 75 memset(toybuf, 0, sizeof(toybuf)); 76 k = strlen(s = *toys.optargs); 77 s += k; 78 for (j = 0; j<k; j++) { 79 unsigned long digit = *(--s) - '0'; 80 81 if (digit > 9) digit = 10 + tolower(*s)-'a'; 82 if (digit > 15) error_exit("bad mask '%s'", *toys.optargs); 83 mask[j/(2*sizeof(long))] |= digit << 4*(j&((2*sizeof(long))-1)); 84 } 85 86 if (-1 == sched_setaffinity(pid, sizeof(toybuf), (void *)mask)) 87 perror_exit(failed, "set", pid); 88 } 89} 90 91static int task_callback(struct dirtree *new) 92{ 93 if (!new->parent) return DIRTREE_RECURSE; 94 if (isdigit(*new->name)) do_taskset(atoi(new->name), 0); 95 96 return 0; 97} 98 99void taskset_main(void) 100{ 101 if (!(toys.optflags & FLAG_p)) { 102 if (toys.optc < 2) error_exit("Needs 2 args"); 103 do_taskset(getpid(), 1); 104 xexec(toys.optargs+1); 105 } else { 106 char *c; 107 pid_t pid = strtol(toys.optargs[toys.optc-1], &c, 10); 108 109 if (*c) error_exit("Not int %s", toys.optargs[1]); 110 111 if (toys.optflags & FLAG_a) { 112 char buf[33]; 113 sprintf(buf, "/proc/%ld/task/", (long)pid); 114 dirtree_read(buf, task_callback); 115 } else do_taskset(pid, 0); 116 } 117} 118 119void nproc_main(void) 120{ 121 unsigned i, j, nproc = 0; 122 123 // This can only detect 32768 processors. Call getaffinity and count bits. 124 if (!toys.optflags && -1!=sched_getaffinity(getpid(), 4096, toybuf)) { 125 for (i = 0; i<4096; i++) 126 if (toybuf[i]) for (j=0; j<8; j++) if (toybuf[i]&(1<<j)) nproc++; 127 } 128 129 // If getaffinity failed or --all, count cpu entries in proc 130 if (!nproc) nproc = sysconf(_SC_NPROCESSORS_CONF); 131 132 xprintf("%u\n", nproc); 133} 134