Hi Oleksandr,
I finally got around to doing a code review today, and ended up making a few
minor changes to your patch:
(1) Instead of defaulting to NORMAL, invalid arguments generate a FATAL
error.
(2) I reworded the help page entry, and moved it up into the restricted
process section instead of down in the "alternatives" section.
(3) I moved the offset_table[] and size_table[] task_struct_policy members
to the end of the arrays to prevent any breakage of pre-compiled
extension modules.
(4) Display the task_struct_policy offset and size table values in the
dump_offset_table() function for "help -o".
(5) Replaced the strdup() call with STRDUPBUF(), calloc() with GETBUF(),
and free() calls with FREEBUF() to avoid using them during runtime.
But I need you to re-work your sched_policy_bit_from_str() function so that it
will accept a hexadecimal number, i.e, "ps -y 0x2". Granted it's not explicitly
allowed in the help page, but a user may see the policy expressed as a
hexadecimal
value by "task" or "struct", and it seems too picky to just disallow it.
I've attached an updated version of the patch with the changes above.
Thanks,
Dave
----- Original Message -----
> While analyzing vmcores from customers sometimes we want
> to filter tasks by scheduling policy, for instance, to identify
> if customer runs realtime tasks. Doing this via foreach grepping
> and then feeding back pointers to task_struct and grepping it again
> is very slow, especially if customer runs thousands of tasks.
>
> So, let's add another option for ps to filter tasks by scheduling
> policy.
>
> Changes in v3:
>
> * fix snprintf format specifier for ulong
> * fix snprintf block indentation
> * add one more comma to help output
>
> Changes in v2:
>
> * handle task_struct.policy member size correctly
> * accept comma-separated list of policies
> instead of requiring multiple -y arguments
> * policy can be specified as a number too
> * policy name is case-insensitive now
> * warn about incorrect policy name
> * fix help message formatting
> * mark upper_case() source string pointer as a const
> (minor cleanup)
>
> Oleksandr Natalenko (1):
> task: also filter ps output by ->policy
>
> defs.h | 15 +++++++-
> help.c | 7 +++-
> task.c | 135
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
> tools.c | 5 ++-
> 4 files changed, 152 insertions(+), 10 deletions(-)
>
> --
> 2.14.2
>
>
diff --git a/defs.h b/defs.h
index 76e5512..4b4e331 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 {
@@ -1992,6 +1994,7 @@ struct offset_table { /* stash of commonly-used offsets */
long mod_arch_specific_num_orcs;
long mod_arch_specific_orc_unwind_ip;
long mod_arch_specific_orc_unwind;
+ long task_struct_policy;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2141,6 +2144,7 @@ struct size_table { /* stash of commonly-used sizes */
long sk_buff_head_qlen;
long sk_buff_len;
long orc_entry;
+ long task_struct_policy;
};
struct array_table {
@@ -4576,6 +4580,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_)
@@ -4603,6 +4614,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)
@@ -4620,6 +4632,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))
@@ -4823,7 +4836,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..efa55e0 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|-y policy] [-s] [-p|-c|-t|-[l|m][-C cpu]|-a|-g|-r|-S]\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",
@@ -1267,6 +1267,16 @@ char *help_ps[] = {
" -k restrict the output to only kernel threads.",
" -u restrict the output to only user tasks.",
" -G display only the thread group leader in a thread group.",
+" -y policy restrict the output to tasks having a specified scheduling policy",
+" expressed by its integer value or by its (case-insensitive) name;",
+" multiple policies may be entered in a comma-separated list:",
+" 0 or NORMAL",
+" 1 or FIFO",
+" 2 or RR",
+" 3 or BATCH",
+" 4 or ISO",
+" 5 or IDLE",
+" 6 or DEADLINE",
" ",
" The process identifier types may be mixed. For each task, the following",
" items are displayed:",
diff --git a/symbols.c b/symbols.c
index b2f2796..f7599e8 100644
--- a/symbols.c
+++ b/symbols.c
@@ -8584,6 +8584,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(task_struct_prio));
fprintf(fp, " task_struct_on_rq: %ld\n",
OFFSET(task_struct_on_rq));
+ fprintf(fp, " task_struct_policy: %ld\n",
+ OFFSET(task_struct_policy));
fprintf(fp, " thread_info_task: %ld\n",
OFFSET(thread_info_task));
@@ -10211,6 +10213,7 @@ dump_offset_table(char *spec, ulong makestruct)
fprintf(fp, " pt_regs: %ld\n", SIZE(pt_regs));
fprintf(fp, " task_struct: %ld\n", SIZE(task_struct));
fprintf(fp, " task_struct_flags: %ld\n", SIZE(task_struct_flags));
+ fprintf(fp, " task_struct_policy: %ld\n", SIZE(task_struct_policy));
fprintf(fp, " thread_info: %ld\n", SIZE(thread_info));
fprintf(fp, " softirq_state: %ld\n",
SIZE(softirq_state));
diff --git a/task.c b/task.c
index 362822c..ab33211 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;
@@ -5366,6 +5393,27 @@ task_flags(ulong task)
}
/*
+ * 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.
*/
ulong
@@ -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
*/
@@ -7389,6 +7446,70 @@ is_kernel_thread(ulong task)
}
/*
+ * 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 = GETBUF(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;
+ }
+ }
+
+ FREEBUF(upper);
+
+ if (!found)
+ error(FATAL,
+ "%s: invalid scheduling policy\n", policy_str);
+
+ 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 = STRDUPBUF(policy_str);
+ orig = iter;
+
+ while ((cur = strsep(&iter, ",")))
+ policy |= sched_policy_bit_from_str(cur);
+
+ FREEBUF(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
* junk in everything after the first entry on a single CPU box, so the
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;
--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility