On Mon, 2011-05-09 at 21:49 +0200, Karel Zak wrote: > sched_getaffinity(pid, ....); > print_affinity(...., tid, ....); > > Do you see the bug? You have to call sched_getaffinity() for each > "tid", otherwise you print the same cpumask for all tasks. > > [...] > > > + if (all_tasks) { > > + pid_t tid; > > + struct proc_tasks *ts = proc_open_tasks(pid); > > + > > + if (!ts) > > + err(EXIT_FAILURE, "cannot obtain the list of tasks"); > > + while (!proc_next_tid(ts, &tid)) > > + if (sched_setaffinity(tid, new_setsize, new_set) < 0) > > + err(EXIT_FAILURE, _("failed to set tid %d's affinity"), tid); > > + proc_close_tasks(ts); > > + } > > + else > > + if (sched_setaffinity(pid, new_setsize, new_set) < 0) > > + err(EXIT_FAILURE, _("failed to set pid %d's affinity"), pid); > > [...] > > The another problem is that the code uses two separate loops to print > and set the masks, so it's possible that you will call sched_getaffinity() > for completely different set of tasks than sched_setaffinity(). It would > be better to use: > > do_taskset(pid_t tid, ...) > { > sched_getaffinity(tid, ...); /* current */ > print_affinity(tid, ...); > > sched_setaffinity(tid, ...); /* new */ > print_affinity(tid, ...); > } > > main() > { > if (all_tasks) { > struct proc_tasks *ts = proc_open_tasks(pid); > while (!proc_next_tid(ts, &tid)) > do_taskset(tid, ...); > proc_close_tasks(ts); > } else > do_taskset(pid, ...); > } > > The output will be also more readable: > > pid 100's current affinity: FOO > pid 100's new affinity: BAR > pid 200's current affinity: FOO > pid 200's new affinity: BAR > ... Ok, good observations. Below is version 2. From: Davidlohr Bueso <dave@xxxxxxx> Date: Tue, 10 May 2011 17:57:22 -0400 Subject: [PATCH] taskset: make threads aware Add a new '-a' option to view/modify the CPU affinity for an entire group of threads belonging to a given PID. We create two new functions, print_affinity() and do_taskset() for code simplification. Example: zeus@jilguero:~/src/util-linux/schedutils$ ./taskset -a -p 01 3142 pid 3142's current affinity mask: 2 pid 3142's new affinity mask: 1 pid 3164's current affinity mask: 2 pid 3164's new affinity mask: 1 pid 854's current affinity mask: 2 pid 854's new affinity mask: 1 Signed-off-by: Davidlohr Bueso <dave@xxxxxxx> Tested-by: Jonathan Gonzalez <zeus@xxxxxxx> --- schedutils/taskset.1 | 3 ++ schedutils/taskset.c | 90 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 30 deletions(-) diff --git a/schedutils/taskset.1 b/schedutils/taskset.1 index f374b62..4aa5e2c 100644 --- a/schedutils/taskset.1 +++ b/schedutils/taskset.1 @@ -72,6 +72,9 @@ returns, it is guaranteed that the given program has been scheduled to a legal CPU. .SH OPTIONS .TP +.BR \-a ,\ \-\-all-tasks +set or retrieve the CPU affinity of all the tasks (threads) for a given PID. +.TP .BR \-p ,\ \-\-pid operate on an existing PID and not launch a new task .TP diff --git a/schedutils/taskset.c b/schedutils/taskset.c index a861a90..357ab4c 100644 --- a/schedutils/taskset.c +++ b/schedutils/taskset.c @@ -28,6 +28,7 @@ #include "cpuset.h" #include "nls.h" #include "strutils.h" +#include "procutils.h" #include "c.h" static void __attribute__((__noreturn__)) usage(FILE *out) @@ -38,6 +39,7 @@ static void __attribute__((__noreturn__)) usage(FILE *out) fprintf(out, _( "Options:\n" + " -a, --all-tasks operate on all the tasks (threads) for a given pid\n" " -p, --pid operate on existing given pid\n" " -c, --cpu-list display and specify cpus in list format\n" " -h, --help display this help\n" @@ -61,16 +63,57 @@ static void __attribute__((__noreturn__)) usage(FILE *out) exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } +static void print_affinity(char *state, int c_opt, pid_t pid, char *buf, size_t buflen, + cpu_set_t *set, size_t setsize) +{ + char *cpuset, *str; + + if (c_opt) { + cpuset = cpulist_create(buf, buflen, set, setsize); + str = "list"; + } else { + cpuset = cpumask_create(buf, buflen, set, setsize); + str = "mask"; + } + + printf(_("pid %d's %s affinity %s: %s\n"), pid, state, str, cpuset); + +} + +static void do_taskset(pid_t pid, int get_only, cpu_set_t *new_set, size_t new_setsize, + cpu_set_t *cur_set, size_t cur_setsize, int c_opt, char *buf, size_t buflen) +{ + if (pid) { + /* current */ + if (sched_getaffinity(pid, cur_setsize, cur_set) < 0) + err(EXIT_FAILURE, _("failed to get pid %d's affinity"), pid); + print_affinity("current", c_opt, pid, buf, buflen, cur_set, cur_setsize); + } + + if (get_only) + return; + + /* new */ + if (sched_setaffinity(pid, new_setsize, new_set) < 0) + err(EXIT_FAILURE, _("failed to set pid %d's affinity"), pid); + if (pid) { + if (sched_getaffinity(pid, cur_setsize, cur_set) < 0) + err(EXIT_FAILURE, _("failed to get pid %d's affinity"), pid); + print_affinity("new", c_opt, pid, buf, buflen, cur_set, cur_setsize); + } +} + int main(int argc, char *argv[]) { cpu_set_t *new_set, *cur_set; pid_t pid = 0; - int opt, c_opt = 0, rc; + int opt, c_opt = 0, rc, get_only = 0, all_tasks = 0; char *buf; unsigned int ncpus; size_t new_setsize, cur_setsize, cur_nbits, buflen; static const struct option longopts[] = { + { "all-tasks", 0, NULL, 'a' }, { "pid", 0, NULL, 'p' }, { "cpu-list", 0, NULL, 'c' }, { "help", 0, NULL, 'h' }, @@ -82,8 +125,11 @@ int main(int argc, char *argv[]) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); - while ((opt = getopt_long(argc, argv, "+pchV", longopts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "+apchV", longopts, NULL)) != -1) { switch (opt) { + case 'a': + all_tasks = 1; + break; case 'p': pid = strtol_or_err(argv[argc - 1], _("failed to parse pid")); break; @@ -133,20 +179,8 @@ int main(int argc, char *argv[]) if (!new_set) err(EXIT_FAILURE, _("cpuset_alloc failed")); - if (pid) { - if (sched_getaffinity(pid, cur_setsize, cur_set) < 0) - err(EXIT_FAILURE, _("failed to get pid %d's affinity"), pid); - - if (c_opt) - printf(_("pid %d's current affinity list: %s\n"), pid, - cpulist_create(buf, buflen, cur_set, cur_setsize)); - else - printf(_("pid %d's current affinity mask: %s\n"), pid, - cpumask_create(buf, buflen, cur_set, cur_setsize)); - - if (argc - optind == 1) - return EXIT_SUCCESS; - } + if (argc - optind == 1) + get_only = 1; rc = c_opt ? cpulist_parse(argv[optind], new_set, new_setsize) : cpumask_parse(argv[optind], new_set, new_setsize); @@ -156,20 +190,16 @@ int main(int argc, char *argv[]) c_opt ? _("CPU list") : _("CPU mask"), argv[optind]); - if (sched_setaffinity(pid, new_setsize, new_set) < 0) - err(EXIT_FAILURE, _("failed to set pid %d's affinity"), pid); - - if (sched_getaffinity(pid, cur_setsize, cur_set) < 0) - err(EXIT_FAILURE, _("failed to get pid %d's affinity"), pid); - - if (pid) { - if (c_opt) - printf(_("pid %d's new affinity list: %s\n"), pid, - cpulist_create(buf, buflen, cur_set, cur_setsize)); - else - printf(_("pid %d's new affinity mask: %s\n"), pid, - cpumask_create(buf, buflen, cur_set, cur_setsize)); - } + if (all_tasks) { + pid_t tid; + struct proc_tasks *ts = proc_open_tasks(pid); + while (!proc_next_tid(ts, &tid)) + do_taskset(tid, get_only, new_set, new_setsize, cur_set, cur_setsize, + c_opt, buf, buflen); + proc_close_tasks(ts); + } else + do_taskset(pid, get_only, new_set, new_setsize, cur_set, cur_setsize, + c_opt, buf, buflen); free(buf); cpuset_free(cur_set); -- 1.7.4.1 -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html