/* taskset.c - Retrieve or set the CPU affinity of a process. * * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com> USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_BIN|TOYFLAG_STAYROOT)) USE_NPROC(NEWTOY(nproc, "(all)", TOYFLAG_USR|TOYFLAG_BIN)) config NPROC bool "nproc" default y help usage: nproc [--all] Print number of processors. --all Show all processors, not just ones this task can run on. config TASKSET bool "taskset" default y help usage: taskset [-ap] [mask] [PID | cmd [args...]] Launch a new task which may only run on certain processors, or change the processor affinity of an exisitng PID. Mask is a hex string where each bit represents a processor the process is allowed to run on. PID without a mask displays existing affinity. -p Set/get the affinity of given PID instead of a new command. -a Set/get the affinity of all threads of the PID. */ #define FOR_taskset #include "toys.h" #include <sys/syscall.h> #define sched_setaffinity(pid, size, cpuset) \ syscall(__NR_sched_setaffinity, (pid_t)pid, (size_t)size, (void *)cpuset) #define sched_getaffinity(pid, size, cpuset) \ syscall(__NR_sched_getaffinity, (pid_t)pid, (size_t)size, (void *)cpuset) // mask is an array of long, which makes the layout a bit weird on big // endian systems but as long as it's consistent... static void do_taskset(pid_t pid, int quiet) { unsigned long *mask = (unsigned long *)toybuf; char *s = *toys.optargs, *failed = "failed to %s %d's affinity"; int i, j, k; for (i=0; ; i++) { if (!quiet) { int j = sizeof(toybuf), flag = 0; if (-1 == sched_getaffinity(pid, sizeof(toybuf), (void *)mask)) perror_exit(failed, "get", pid); printf("pid %d's %s affinity mask: ", pid, i ? "new" : "current"); while (j--) { int x = 255 & (mask[j/sizeof(long)] >> (8*(j&(sizeof(long)-1)))); if (flag) printf("%02x", x); else if (x) { flag++; printf("%x", x); } } putchar('\n'); } if (i || toys.optc < 2) return; memset(toybuf, 0, sizeof(toybuf)); k = strlen(s = *toys.optargs); s += k; for (j = 0; j<k; j++) { unsigned long digit = *(--s) - '0'; if (digit > 9) digit = 10 + tolower(*s)-'a'; if (digit > 15) error_exit("bad mask '%s'", *toys.optargs); mask[j/(2*sizeof(long))] |= digit << 4*(j&((2*sizeof(long))-1)); } if (-1 == sched_setaffinity(pid, sizeof(toybuf), (void *)mask)) perror_exit(failed, "set", pid); } } static int task_callback(struct dirtree *new) { if (!new->parent) return DIRTREE_RECURSE; if (isdigit(*new->name)) do_taskset(atoi(new->name), 0); return 0; } void taskset_main(void) { if (!(toys.optflags & FLAG_p)) { if (toys.optc < 2) error_exit("Needs 2 args"); do_taskset(getpid(), 1); xexec(toys.optargs+1); } else { char *c; pid_t pid = strtol(toys.optargs[toys.optc-1], &c, 10); if (*c) error_exit("Not int %s", toys.optargs[1]); if (toys.optflags & FLAG_a) { char buf[33]; sprintf(buf, "/proc/%ld/task/", (long)pid); dirtree_read(buf, task_callback); } else do_taskset(pid, 0); } } void nproc_main(void) { unsigned i, j, nproc = 0; // This can only detect 32768 processors. Call getaffinity and count bits. if (!toys.optflags && -1!=sched_getaffinity(getpid(), 4096, toybuf)) { for (i = 0; i<4096; i++) if (toybuf[i]) for (j=0; j<8; j++) if (toybuf[i]&(1<<j)) nproc++; } // If getaffinity failed or --all, count cpu entries in proc if (!nproc) nproc = sysconf(_SC_NPROCESSORS_CONF); xprintf("%u\n", nproc); }