[Crash-utility] [PATCH RFC 1/1] kernel: add an ability to filter timers by CPUs

Oleksandr Natalenko oleksandr at redhat.com
Mon Oct 30 10:40:33 UTC 2017


Signed-off-by: Oleksandr Natalenko <oleksandr at redhat.com>
---
 help.c   |  4 +++-
 kernel.c | 80 +++++++++++++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 60 insertions(+), 24 deletions(-)

diff --git a/help.c b/help.c
index efa55e0..81d6b0d 100644
--- a/help.c
+++ b/help.c
@@ -2387,7 +2387,7 @@ NULL
 char *help_timer[] = {
 "timer",
 "timer queue data",
-"[-r]",
+"[-r][-C cpu]",
 "  This command displays the timer queue entries, both old- and new-style,",
 "  in chronological order.  In the case of the old-style timers, the",
 "  timer_table array index is shown; in the case of the new-style timers, ",
@@ -2397,6 +2397,8 @@ char *help_timer[] = {
 "        chronological order.  In the case of the old-style hrtimers, the",
 "        expiration time is a single value; in the new-style hrtimers, the",
 "        expiration time is a range.",
+"-C cpus restrict the output to given CPUs, where the cpu[s] can be specified",
+"        as \"1,3,5\", \"1-3\", \"1,3,5-7,10\", \"all\", or \"a\" (shortcut for \"all\").",
 "\nEXAMPLES",
 "    %s> timer",
 "    JIFFIES",
diff --git a/kernel.c b/kernel.c
index 8e95573..4638495 100644
--- a/kernel.c
+++ b/kernel.c
@@ -38,18 +38,18 @@ static void display_bh_1(void);
 static void display_bh_2(void);
 static void display_bh_3(void);
 static void display_bh_4(void);
-static void dump_hrtimer_data(void);
+static void dump_hrtimer_data(const ulong *cpus);
 static void dump_hrtimer_clock_base(const void *, const int);
 static void dump_hrtimer_base(const void *, const int);
 static void dump_active_timers(const void *, ulonglong);
 static int get_expires_len(const int, const ulong *, const int);
 static void print_timer(const void *);
 static ulonglong ktime_to_ns(const void *);
-static void dump_timer_data(void);
-static void dump_timer_data_tvec_bases_v1(void);
-static void dump_timer_data_tvec_bases_v2(void);
-static void dump_timer_data_tvec_bases_v3(void);
-static void dump_timer_data_timer_bases(void);
+static void dump_timer_data(const ulong *cpus);
+static void dump_timer_data_tvec_bases_v1(const ulong *cpus);
+static void dump_timer_data_tvec_bases_v2(const ulong *cpus);
+static void dump_timer_data_tvec_bases_v3(const ulong *cpus);
+static void dump_timer_data_timer_bases(const ulong *cpus);
 struct tv_range;
 static void init_tv_ranges(struct tv_range *, int, int, int);
 static int do_timer_list(ulong,int, ulong *, void *,ulong *,struct tv_range *);
@@ -7353,16 +7353,24 @@ cmd_timer(void)
 {
         int c;
 	int rflag;
+	char *cpuspec;
+	ulong *cpus = NULL;
 
 	rflag = 0;
 
-        while ((c = getopt(argcnt, args, "r")) != EOF) {
+        while ((c = getopt(argcnt, args, "rC:")) != EOF) {
                 switch(c)
                 {
 		case 'r':
 			rflag = 1;
 			break;
 
+		case 'C':
+			cpuspec = optarg;
+			cpus = get_cpumask_buf();
+			make_cpumask(cpuspec, cpus, FAULT_ON_ERROR, NULL);
+			break;
+
                 default:
                         argerrs++;
                         break;
@@ -7373,15 +7381,18 @@ cmd_timer(void)
                 cmd_usage(pc->curcmd, SYNOPSIS);
 
 	if (rflag)
-		dump_hrtimer_data();
+		dump_hrtimer_data(cpus);
 	else
-		dump_timer_data();
+		dump_timer_data(cpus);
+
+	if (cpus)
+		FREEBUF(cpus);
 }
 
 static void
-dump_hrtimer_data(void)
+dump_hrtimer_data(const ulong *cpus)
 {
-	int i, j;
+	int i, j, k = 0;
 	int hrtimer_max_clock_bases, max_hrtimer_bases;
 	struct syment * hrtimer_bases;
 
@@ -7405,7 +7416,10 @@ dump_hrtimer_data(void)
 	hrtimer_bases = per_cpu_symbol_search("hrtimer_bases");
 
 	for (i = 0; i < kt->cpus; i++) {
-		if (i)
+		if (cpus && !NUM_IN_BITMAP(cpus, i))
+			continue;
+
+		if (k++)
 			fprintf(fp, "\n");
 
 		if (hide_offline_cpu(i)) {
@@ -7752,7 +7766,7 @@ struct tv_range {
 #define TVN (6)
 
 static void
-dump_timer_data(void)
+dump_timer_data(const ulong *cpus)
 {
 	int i;
 	ulong timer_active;
@@ -7773,16 +7787,16 @@ dump_timer_data(void)
         struct tv_range tv[TVN];
 
 	if (kt->flags2 & TIMER_BASES) {
-		dump_timer_data_timer_bases();
+		dump_timer_data_timer_bases(cpus);
 		return;
 	} else if (kt->flags2 & TVEC_BASES_V3) {
-		dump_timer_data_tvec_bases_v3();
+		dump_timer_data_tvec_bases_v3(cpus);
 		return;
 	} else if (kt->flags & TVEC_BASES_V2) {
-		dump_timer_data_tvec_bases_v2();
+		dump_timer_data_tvec_bases_v2(cpus);
 		return;
 	} else if (kt->flags & TVEC_BASES_V1) {
-		dump_timer_data_tvec_bases_v1();
+		dump_timer_data_tvec_bases_v1(cpus);
 		return;
 	}
 		
@@ -7924,7 +7938,7 @@ dump_timer_data(void)
  */
 
 static void
-dump_timer_data_tvec_bases_v1(void)
+dump_timer_data_tvec_bases_v1(const ulong *cpus)
 {
 	int i, cpu, tdx, flen;
         struct timer_data *td;
@@ -7947,6 +7961,11 @@ dump_timer_data_tvec_bases_v1(void)
 	cpu = 0;
 
 next_cpu:
+	if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
+		if (++cpu < kt->cpus)
+			goto next_cpu;
+		return;
+	}
 
         count = 0;
         td = (struct timer_data *)NULL;
@@ -8039,7 +8058,7 @@ next_cpu:
  */
 
 static void
-dump_timer_data_tvec_bases_v2(void)
+dump_timer_data_tvec_bases_v2(const ulong *cpus)
 {
 	int i, cpu, tdx, flen;
         struct timer_data *td;
@@ -8073,6 +8092,11 @@ dump_timer_data_tvec_bases_v2(void)
 	cpu = 0;
 
 next_cpu:
+	if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
+		if (++cpu < kt->cpus)
+			goto next_cpu;
+		return;
+	}
 	/*
 	 * hide data of offline cpu and goto next cpu
 	 */
@@ -8185,7 +8209,7 @@ next_cpu:
  *  Linux 4.2 timers use new tvec_root, tvec and timer_list structures
  */
 static void
-dump_timer_data_tvec_bases_v3(void)
+dump_timer_data_tvec_bases_v3(const ulong *cpus)
 {
 	int i, cpu, tdx, flen;
 	struct timer_data *td;
@@ -8216,6 +8240,11 @@ dump_timer_data_tvec_bases_v3(void)
 	cpu = 0;
 
 next_cpu:
+	if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
+		if (++cpu < kt->cpus)
+			goto next_cpu;
+		return;
+	}
 	/*
 	 * hide data of offline cpu and goto next cpu
 	 */
@@ -8758,9 +8787,9 @@ do_timer_list_v4(struct timer_bases_data *data)
  *  Linux 4.8 timers use new timer_bases[][]
  */
 static void
-dump_timer_data_timer_bases(void)
+dump_timer_data_timer_bases(const ulong *cpus)
 {
-	int i, cpu, flen, base, nr_bases, found, display;
+	int i, cpu, flen, base, nr_bases, found, display, j = 0;
 	struct syment *sp;
 	ulong timer_base, jiffies, function;
 	struct timer_bases_data data;
@@ -8785,6 +8814,11 @@ dump_timer_data_timer_bases(void)
 		RJUST|LONG_DEC,MKSTR(jiffies)));
 
 next_cpu:
+	if (cpus && !NUM_IN_BITMAP(cpus, cpu)) {
+		if (++cpu < kt->cpus)
+			goto next_cpu;
+		goto done;
+	}
 	/*
 	 * hide data of offline cpu and goto next cpu
 	 */
@@ -8803,7 +8837,7 @@ next_cpu:
 	else
 		timer_base = sp->value;
 
-	if (cpu)
+	if (j++)
 		fprintf(fp, "\n");
 next_base:
 
-- 
2.14.3




More information about the Crash-utility mailing list