Hello all,

In attach you can find an initial version of 'taskset'. It allows setting the cpu affinity of a given PID (or all tasks related with a given PID/TID). cpu affinity should be entered in hex, when no affinity is given the affinity for the process or the group of tasks is displayed.

I tested it (a.o.) with a yes > /dev/null and a top which shows the cpu load per core, and then you can see yes jump around

edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x1 20941
pid 20941's current affinity mask: ff
pid 20941's new affinity mask: 1
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x2 20941
pid 20941's current affinity mask: 1
pid 20941's new affinity mask: 2
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x4 20941
pid 20941's current affinity mask: 2
pid 20941's new affinity mask: 4
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x8 20941
pid 20941's current affinity mask: 4
pid 20941's new affinity mask: 8
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x10 20941
pid 20941's current affinity mask: 8
pid 20941's new affinity mask: 10
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x20 20941
pid 20941's current affinity mask: 10
pid 20941's new affinity mask: 20
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x30 20941
pid 20941's current affinity mask: 20
pid 20941's new affinity mask: 30
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x40 20941
pid 20941's current affinity mask: 30
pid 20941's new affinity mask: 40
edb@lapedb:~/edb-stuff/toybox/toybox$ sudo ./toybox taskset 0x80 20941
pid 20941's current affinity mask: 40
pid 20941's new affinity mask: 80

One comment, I added sched.h into the toys.h include, but I also needed a #define _GNU_SOURCE or I'd run into troubles because it failed to find the CPU_SET* macro's. So this was added in taskset.c but I'm not sure if this is the correct way to go.

my 2 cents
E.


--
Elie De Brauwer

# HG changeset patch
# User Elie De Brauwer <[email protected]>
# Date 1342351731 -7200
# Node ID a755b5cea4b99969cefafc98975fc261fedba95a
# Parent  93ef2516f15a939d845606c9687b8f04b5ea2aca
Adding initial implementation of taskset

diff -r 93ef2516f15a -r a755b5cea4b9 toys.h
--- a/toys.h	Sat Jul 14 00:59:32 2012 -0500
+++ b/toys.h	Sun Jul 15 13:28:51 2012 +0200
@@ -21,6 +21,7 @@
 #include <pwd.h>
 #include <sched.h>
 #include <setjmp.h>
+#include <sched.h>
 #include <shadow.h>
 #include <stdarg.h>
 #include <stdint.h>
diff -r 93ef2516f15a -r a755b5cea4b9 toys/taskset.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/toys/taskset.c	Sun Jul 15 13:28:51 2012 +0200
@@ -0,0 +1,134 @@
+/* vi: set sw=4 ts=4:
+ *
+ * taskset.c - Retrieve or set the CPU affinity of a process.
+ *
+ * Copyright 2012 Elie De Brauwer <[email protected]>
+ *
+ * Not in SUSv4.
+
+USE_TASKSET(NEWTOY(taskset, "<1>2a", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+
+config TASKSET
+	bool "taskset"
+	default y
+	help
+	  usage: taskset [-a] [mask] PID
+
+	  When mask is present the CPU affinity mask of a given PID will
+	  be set to this mask. When a mask is not given, the mask will
+	  be printed. A mask is a hexadecimal string where the bit position
+	..matches the cpu number.
+	  -a	Set/get the affinity of all tasks of a PID.
+*/
+
+#define _GNU_SOURCE
+#include "toys.h"
+
+static int str_to_cpu_set(char * mask, cpu_set_t *set)
+{
+	int size = strlen(mask);
+	char *ptr = mask + size - 1;
+	int cpu = 0;
+
+	CPU_ZERO(set);
+	if (size > 1 && mask[0] == '0' && mask[1] == 'x')
+		mask += 2;
+
+	while(ptr >= mask)
+	{
+		char val = 0;
+		if ( *ptr >= '0' && *ptr <= '9')
+			val = *ptr - '0';
+		else if (*ptr >= 'a' && *ptr <= 'f')
+			val = 10 + (*ptr - 'a');
+		else
+			return -1;
+
+		if (val & 1) CPU_SET(cpu,  set);
+		if (val & 2) CPU_SET(cpu + 1, set);
+		if (val & 4) CPU_SET(cpu + 2, set);
+		if (val & 8) CPU_SET(cpu + 3, set);
+
+		ptr--;
+		cpu += 4;
+	}
+	return 0;
+}
+
+static char * cpu_set_to_str(cpu_set_t *set)
+{
+	int cpu;
+	char * ptr = toybuf;
+	for (cpu=(8*sizeof(cpu_set_t) - 4); cpu >= 0; cpu -= 4)
+	{
+		char val = 0;
+		if (CPU_ISSET(cpu, set))	 val |= 1;
+		if (CPU_ISSET(cpu + 1, set)) val |= 2;
+		if (CPU_ISSET(cpu + 2, set)) val |= 4;
+		if (CPU_ISSET(cpu + 3, set)) val |= 8;
+		if (ptr != toybuf || val != 0)
+		{
+			if (val < 10)
+				*ptr = '0' + val;
+			else
+				*ptr = 'a' + (val - 10);
+			ptr++;
+		}
+	}
+	*ptr = 0;
+	return toybuf;
+}
+
+static void do_taskset(pid_t pid)
+{
+	cpu_set_t mask;
+	if (sched_getaffinity(pid, sizeof(mask), &mask))
+		perror_exit("failed to get %d's affinity", pid);
+
+	printf("pid %d's current affinity mask: %s\n", pid, cpu_set_to_str(&mask));
+
+	if (toys.optc == 2)
+	{
+		if (str_to_cpu_set(toys.optargs[0], &mask))
+			perror_exit("failed to parse CPU mask: %s", toys.optargs[0]);
+
+		if (sched_setaffinity(pid, sizeof(mask), &mask))
+			perror_exit("failed to set %d's affinity", pid);
+
+		if (sched_getaffinity(pid, sizeof(mask), &mask))
+			perror_exit("failed to get %d's affinity", pid);
+
+		printf("pid %d's new affinity mask: %s\n", pid, cpu_set_to_str(&mask));
+	}
+}
+
+static int task_cb(struct dirtree *new)
+{
+	if (S_ISDIR(new->st.st_mode))
+	{
+		if (strstr(new->name,"/task/\0") != NULL)
+			return DIRTREE_RECURSE;
+
+		pid_t tid = atoi(new->name);
+		if (tid)
+			do_taskset(tid);
+	}
+	return 0;
+}
+
+void taskset_main(void)
+{
+	char * pidstr = (toys.optc==1)?toys.optargs[0]:toys.optargs[1];
+
+	if ( toys.optflags & 0x1 )
+	{
+		sprintf(toybuf, "/proc/%s/task/", pidstr);
+		dirtree_read(toybuf, task_cb);
+	}
+	else
+	{
+		pid_t tid = atoi(pidstr);
+		if (tid)
+			do_taskset(tid);
+	}
+}
_______________________________________________
Toybox mailing list
[email protected]
http://lists.landley.net/listinfo.cgi/toybox-landley.net

Reply via email to