[Crash-utility] [PATCH v3 1/1] task: also filter ps output by ->policy

Oleksandr Natalenko oleksandr at redhat.com
Tue Oct 24 06:23:19 UTC 2017


This patch introduces -y option for ps builtin to filter
tasks by scheduling policy. Applicable to both standalone
ps invocation as well as via foreach.

Signed-off-by: Oleksandr Natalenko <oleksandr at redhat.com>
---
 defs.h  |  15 +++++++-
 help.c  |   7 +++-
 task.c  | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 tools.c |   5 ++-
 4 files changed, 152 insertions(+), 10 deletions(-)

diff --git a/defs.h b/defs.h
index a694a66..e0e2c2b 100644
--- a/defs.h
+++ b/defs.h
@@ -1139,6 +1139,7 @@ extern struct machdep_table *machdep;
 #define FOREACH_a_FLAG   (0x4000000)
 #define FOREACH_G_FLAG   (0x8000000)
 #define FOREACH_F_FLAG2 (0x10000000)
+#define FOREACH_y_FLAG  (0x20000000)
 
 #define FOREACH_PS_EXCLUSIVE \
   (FOREACH_g_FLAG|FOREACH_a_FLAG|FOREACH_t_FLAG|FOREACH_c_FLAG|FOREACH_p_FLAG|FOREACH_l_FLAG|FOREACH_r_FLAG|FOREACH_m_FLAG)
@@ -1162,6 +1163,7 @@ struct foreach_data {
 	int comms;
 	int args;
 	int regexs;
+	int policy;
 };
 
 struct reference {       
@@ -1201,6 +1203,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long task_struct_pidhash_next;
 	long task_struct_next_run;
 	long task_struct_flags;
+	long task_struct_policy;
 	long task_struct_sig;
 	long task_struct_signal;
 	long task_struct_blocked;
@@ -2134,6 +2137,7 @@ struct size_table {         /* stash of commonly-used sizes */
 	long tnt;
 	long trace_print_flags;
 	long task_struct_flags;
+	long task_struct_policy;
 	long timer_base;
 	long taint_flag;
 	long nlmsghdr;
@@ -4573,6 +4577,13 @@ enum type_code {
  */
 #define PF_EXITING 0x00000004  /* getting shut down */
 #define PF_KTHREAD 0x00200000  /* I am a kernel thread */
+#define SCHED_NORMAL	0
+#define SCHED_FIFO	1
+#define SCHED_RR	2
+#define SCHED_BATCH	3
+#define SCHED_ISO	4
+#define SCHED_IDLE	5
+#define SCHED_DEADLINE	6
 
 extern long _ZOMBIE_;
 #define IS_ZOMBIE(task)   (task_state(task) & _ZOMBIE_)
@@ -4600,6 +4611,7 @@ extern long _ZOMBIE_;
 #define PS_NO_HEADER  (0x10000)
 #define PS_MSECS      (0x20000)
 #define PS_SUMMARY    (0x40000)
+#define PS_POLICY     (0x80000)
 
 #define PS_EXCLUSIVE (PS_TGID_LIST|PS_ARGV_ENVP|PS_TIMES|PS_CHILD_LIST|PS_PPID_LIST|PS_LAST_RUN|PS_RLIMIT|PS_MSECS|PS_SUMMARY)
 
@@ -4617,6 +4629,7 @@ struct psinfo {
 	} regex_data[MAX_PS_ARGS];
 	int regexs;
 	ulong *cpus;
+	int policy;
 };
 
 #define IS_A_NUMBER(X)      (decimal(X, 0) || hexadecimal(X, 0))
@@ -4820,7 +4833,7 @@ char *strip_ending_char(char *, char);
 char *strip_beginning_char(char *, char);
 char *strip_comma(char *);
 char *strip_hex(char *);
-char *upper_case(char *, char *);
+char *upper_case(const char *, char *);
 char *first_nonspace(char *);
 char *first_space(char *);
 char *replace_string(char *, char *, char);
diff --git a/help.c b/help.c
index f9c5792..69502b9 100644
--- a/help.c
+++ b/help.c
@@ -844,7 +844,7 @@ char *help_foreach[] = {
 "             net  run the \"net\" command  (optional flags: -s -S -R -d -x)",
 "             set  run the \"set\" command",
 "              ps  run the \"ps\" command  (optional flags: -G -s -p -c -t -l -a",
-"                  -g -r)",
+"                  -g -r -y)",
 "             sig  run the \"sig\" command (optional flag: -g)",
 "            vtop  run the \"vtop\" command  (optional flags: -c -u -k)\n",
 "     flag  Pass this optional flag to the command selected.",
@@ -1250,7 +1250,7 @@ NULL
 char *help_ps[] = {
 "ps",
 "display process status information",
-"[-k|-u|-G] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S]\n     [pid | task | command] ...",
+"[-k|-u|-G] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S|-y policy]\n     [pid | task | command] ...",
 "  This command displays process status for selected, or all, processes" ,
 "  in the system.  If no arguments are entered, the process data is",
 "  is displayed for all processes.  Specific processes may be selected",
@@ -1318,6 +1318,9 @@ char *help_ps[] = {
 "       -g  display tasks by thread group, of selected, or all, tasks.",
 "       -r  display resource limits (rlimits) of selected, or all, tasks.",
 "       -S  display a summary consisting of the number of tasks in a task state.",
+"-y policy  filter tasks by comma-separated list of scheduling policies.",
+"           Acceptable values: NORMAL, FIFO, RR, BATCH, ISO, IDLE, DEADLINE",
+"           (case-insensitive) or integer equivalents, from 0 to 6.",
 "\nEXAMPLES",
 "  Show the process status of all current tasks:\n",
 "    %s> ps",
diff --git a/task.c b/task.c
index 362822c..090e454 100644
--- a/task.c
+++ b/task.c
@@ -109,6 +109,24 @@ static void show_ps_summary(ulong);
 static void irqstacks_init(void);
 static void parse_task_thread(int argcnt, char *arglist[], struct task_context *);
 static void stack_overflow_check_init(void);
+static int has_sched_policy(ulong, ulong);
+static ulong task_policy(ulong);
+static ulong sched_policy_bit_from_str(const char *);
+static ulong make_sched_policy(const char *);
+
+static struct sched_policy_info {
+	ulong value;
+	char *name;
+} sched_policy_info[] = {
+	{ SCHED_NORMAL,		"NORMAL" },
+	{ SCHED_FIFO,		"FIFO" },
+	{ SCHED_RR,		"RR" },
+	{ SCHED_BATCH,		"BATCH" },
+	{ SCHED_ISO,		"ISO" },
+	{ SCHED_IDLE,		"IDLE" },
+	{ SCHED_DEADLINE,	"DEADLINE" },
+	{ ULONG_MAX,		NULL }
+};
 
 /*
  *  Figure out how much space will be required to hold the task context
@@ -273,6 +291,8 @@ task_init(void)
 	MEMBER_OFFSET_INIT(task_struct_next_run, "task_struct", "next_run");
 	MEMBER_OFFSET_INIT(task_struct_flags, "task_struct", "flags");
 	MEMBER_SIZE_INIT(task_struct_flags, "task_struct", "flags");
+	MEMBER_OFFSET_INIT(task_struct_policy, "task_struct", "policy");
+	MEMBER_SIZE_INIT(task_struct_policy, "task_struct", "policy");
         MEMBER_OFFSET_INIT(task_struct_pidhash_next,
                 "task_struct", "pidhash_next");
 	MEMBER_OFFSET_INIT(task_struct_pgrp, "task_struct", "pgrp");
@@ -2974,7 +2994,7 @@ cmd_ps(void)
 	cpuspec = NULL;
 	flag = 0;
 
-        while ((c = getopt(argcnt, args, "SgstcpkuGlmarC:")) != EOF) {
+        while ((c = getopt(argcnt, args, "SgstcpkuGlmarC:y:")) != EOF) {
                 switch(c)
 		{
 		case 'k':
@@ -3075,6 +3095,11 @@ cmd_ps(void)
 			make_cpumask(cpuspec, psinfo.cpus, FAULT_ON_ERROR, NULL);
 			break;
 
+		case 'y':
+			flag |= PS_POLICY;
+			psinfo.policy = make_sched_policy(optarg);
+			break;
+
 		default:
 			argerrs++;
 			break;
@@ -3218,6 +3243,8 @@ show_ps_data(ulong flag, struct task_context *tc, struct psinfo *psi)
 		return;
 	if ((flag & PS_KERNEL) && !is_kernel_thread(tc->task))
 		return;
+	if ((flag & PS_POLICY) && !has_sched_policy(tc->task, psi->policy))
+		return;
 	if (flag & PS_GROUP) {
 		if (flag & (PS_LAST_RUN|PS_MSECS))
 			error(FATAL, "-G not supported with -%c option\n",
@@ -3336,7 +3363,7 @@ show_ps(ulong flag, struct psinfo *psi)
 
 		tc = FIRST_CONTEXT();
 		for (i = 0; i < RUNNING_TASKS(); i++, tc++)
-			show_ps_data(flag, tc, NULL);
+			show_ps_data(flag, tc, psi);
 		
 		return;
 	}
@@ -3391,7 +3418,7 @@ show_ps(ulong flag, struct psinfo *psi)
 				if (flag & PS_TIMES) 
 					show_task_times(tc, flag);
 				else
-					show_ps_data(flag, tc, NULL);
+					show_ps_data(flag, tc, psi);
 			}
 		}
 	}
@@ -3546,7 +3573,7 @@ show_milliseconds(struct task_context *tc, struct psinfo *psi)
 	sprintf(format, "[%c%dll%c] ", '%', c, 
 		pc->output_radix == 10 ? 'u' : 'x');
 
-	if (psi) {
+	if (psi && psi->cpus) {
 		for (c = others = 0; c < kt->cpus; c++) {
 			if (!NUM_IN_BITMAP(psi->cpus, c))
 				continue;
@@ -5365,6 +5392,27 @@ task_flags(ulong task)
 	return flags;
 }
 
+/*
+ * Return task's policy as bitmask bit.
+ */
+static ulong
+task_policy(ulong task)
+{
+	ulong policy = 0;
+
+	fill_task_struct(task);
+
+	if (!tt->last_task_read)
+		return policy;
+
+	if (SIZE(task_struct_policy) == sizeof(unsigned int))
+		policy = 1 << UINT(tt->task_struct + OFFSET(task_struct_policy));
+	else
+		policy = 1 << ULONG(tt->task_struct + OFFSET(task_struct_policy));
+
+	return policy;
+}
+
 /*
  *  Return a task's tgid.
  */
@@ -5797,7 +5845,7 @@ cmd_foreach(void)
 	BZERO(&foreach_data, sizeof(struct foreach_data));
 	fd = &foreach_data;
 
-        while ((c = getopt(argcnt, args, "R:vomlgersStTpukcfFxhdaG")) != EOF) {
+        while ((c = getopt(argcnt, args, "R:vomlgersStTpukcfFxhdaGy:")) != EOF) {
                 switch(c)
 		{
 		case 'R':
@@ -5892,6 +5940,11 @@ cmd_foreach(void)
 			fd->flags |= FOREACH_G_FLAG;
 			break;
 
+		case 'y':
+			fd->flags |= FOREACH_y_FLAG;
+			fd->policy = make_sched_policy(optarg);
+			break;
+
 		default:
 			argerrs++;
 			break;
@@ -6554,6 +6607,10 @@ foreach(struct foreach_data *fd)
 					cmdflags |= PS_GROUP;
 				if (fd->flags & FOREACH_s_FLAG)
 					cmdflags |= PS_KSTACKP;
+				if (fd->flags & FOREACH_y_FLAG) {
+					cmdflags |= PS_POLICY;
+					psinfo.policy = fd->policy;
+				}
 				/*
 				 * mutually exclusive flags
 				 */ 
@@ -7388,6 +7445,74 @@ is_kernel_thread(ulong task)
 	return FALSE;
 }
 
+/*
+ * Checks if task policy corresponds to given mask.
+ */
+static int
+has_sched_policy(ulong task, ulong policy)
+{
+	return !!(task_policy(task) & policy);
+}
+
+/*
+ * Converts sched policy name into mask bit.
+ */
+static ulong
+sched_policy_bit_from_str(const char *policy_str)
+{
+	struct sched_policy_info *info = NULL;
+	ulong policy = 0;
+	int found = 0;
+	char *upper = NULL;
+	char digit[2] = { 0, 0 };
+
+	upper = calloc(1, strlen(policy_str) + 1);
+	upper_case(policy_str, upper);
+
+	for (info = sched_policy_info; info->name; info++) {
+		snprintf(digit, sizeof digit, "%lu", info->value);
+		if (strncmp(upper, info->name, strlen(info->name)) == 0 ||
+			strncmp(upper, digit, sizeof digit) == 0) {
+			policy = 1 << info->value;
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		error(INFO,
+			"Scheduling policy \"%s\" is incorrect, defaulting to %s\n",
+			policy_str, sched_policy_info[0].name);
+		policy = 1 << sched_policy_info[0].value;
+	}
+
+	free(upper);
+
+	return policy;
+}
+
+/*
+ * Converts sched policy string set into bitmask.
+ */
+static ulong
+make_sched_policy(const char *policy_str)
+{
+	ulong policy = 0;
+	char *iter = NULL;
+	char *orig = NULL;
+	char *cur = NULL;
+
+	iter = strdup(policy_str);
+	orig = iter;
+
+	while ((cur = strsep(&iter, ",")))
+		policy |= sched_policy_bit_from_str(cur);
+
+	free(orig);
+
+	return policy;
+}
+
 /*
  *  Gather an arry of pointers to the per-cpu idle tasks.  The tasklist
  *  argument must be at least the size of ulong[NR_CPUS].  There may be
diff --git a/tools.c b/tools.c
index 886d7fb..186b703 100644
--- a/tools.c
+++ b/tools.c
@@ -423,9 +423,10 @@ strip_hex(char *line)
  *  Turn a string into upper-case.
  */
 char *
-upper_case(char *s, char *buf)
+upper_case(const char *s, char *buf)
 {
-	char *p1, *p2;
+	const char *p1;
+	char *p2;
 
 	p1 = s;
 	p2 = buf;
-- 
2.14.2




More information about the Crash-utility mailing list