Re: [PATCH 2/2] taskset: make threads aware

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux