From dde58a67db34eda9ebd9cf95d835ec0ba3e68db7 Mon Sep 17 00:00:00 2001
From: Wei Jiangang <weijg.fnst@cn.fujitsu.com>
Date: Sun, 13 May 2012 20:07:01 +0800
Subject: [PATCH] add an option -t for command runq

The option "-t" dispaly the timestamp information about the runqueue each
of cpu. The timestamp information, which according to kernel version,
may be the value of runqueue's member. For example, rq.clock or
rq.timestamp_last_tick, even runqueue.timestamp_last_tick.
Signed-off-by: Wei Jiangang <weijg.fnst@cn.fujitsu.com>
---
 defs.h   |    1 +
 help.c   |   11 ++++++++++
 kernel.c |   15 +++++++++++--
 task.c   |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/defs.h b/defs.h
index 77a623d..73e2168 100755
--- a/defs.h
+++ b/defs.h
@@ -1557,6 +1557,7 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long rq_cfs;
 	long rq_rt;
 	long rq_nr_running;
+	long rq_timestamp;
 	long cfs_rq_rb_leftmost;
 	long cfs_rq_nr_running;
 	long cfs_rq_tasks_timeline;
diff --git a/help.c b/help.c
index 8ce8247..aa60182 100755
--- a/help.c
+++ b/help.c
@@ -2140,7 +2140,13 @@ char *help_runq[] = {
 "runq",
 "run queue",
 " ",
+"  [-t] ",
 "  This command displays the tasks on the run queues of each cpu.",
+"  The arguments are as follows:\n",
+"  -t Display the timestamp information about the runqueue each of cpu.",
+"     the timstamp information may be the value of rq.clock or",
+"        rq.timestamp_last_tick, which according to kernel version.",
+" ",
 "\nEXAMPLES",
 "    %s> runq",
 "    CPU 0 RUNQUEUE: ffff880001cdb460",
@@ -2157,6 +2163,11 @@ char *help_runq[] = {
 "         [115] PID: 1779   TASK: ffff88003207a860  COMMAND: \"klogd\"",
 "      EXPIRED PRIO_ARRAY: ffff880001ce3db8",
 "         [no tasks queued]",
+"    %s> runq -t ",
+"    CPU 0: 67393251944103",
+"    [67393251944103]  PID: 14776  TASK: ea54aab0  COMMAND: \"crash\"",
+"    CPU 1: 66789719628339",
+"    [67393251858710]  PID: 14769  TASK: f4bdc030  COMMAND: \"crash\"",
 NULL               
 };
 
diff --git a/kernel.c b/kernel.c
index 4342bce..9873f98 100755
--- a/kernel.c
+++ b/kernel.c
@@ -67,6 +67,7 @@ kernel_init()
 	char *p1, *p2, buf[BUFSIZE];
 	struct syment *sp1, *sp2;
 	char *rqstruct;
+	char *rq_timestamp_name = NULL;
 	char *irq_desc_type_name;	
 	ulong pv_init_ops;
 
@@ -225,11 +226,18 @@ kernel_init()
 			&kt->__per_cpu_offset[0]);
                 kt->flags |= PER_CPU_OFF;
 	}
-	if (STRUCT_EXISTS("runqueue"))
+	if (STRUCT_EXISTS("runqueue")) {
 		rqstruct = "runqueue";
-	else if (STRUCT_EXISTS("rq"))
+		rq_timestamp_name = "timestamp_last_tick";
+	} else if (STRUCT_EXISTS("rq")) {
 		rqstruct = "rq";
-	else {
+		if (MEMBER_EXISTS("rq", "clock"))
+			rq_timestamp_name = "clock";
+		else if (MEMBER_EXISTS("rq", "most_recent_timestamp"))
+			rq_timestamp_name = "most_recent_timestamp";
+		else if (MEMBER_EXISTS("rq", "timestamp_last_tick"))
+			rq_timestamp_name = "timestamp_last_tick";
+	} else {
 		rqstruct = NULL;
 		error(FATAL, "neither runqueue nor rq structures exist\n");
 	}
@@ -275,6 +283,7 @@ kernel_init()
 	MEMBER_OFFSET_INIT(runqueue_active, rqstruct, "active");
 	MEMBER_OFFSET_INIT(runqueue_expired, rqstruct, "expired");
 	MEMBER_OFFSET_INIT(runqueue_arrays, rqstruct, "arrays");
+	MEMBER_OFFSET_INIT(rq_timestamp, rqstruct, rq_timestamp_name);
 	MEMBER_OFFSET_INIT(prio_array_queue, "prio_array", "queue");
         MEMBER_OFFSET_INIT(prio_array_nr_active, "prio_array", "nr_active");
 	STRUCT_SIZE_INIT(runqueue, rqstruct); 
diff --git a/task.c b/task.c
index 002e8b6..3e8d936 100755
--- a/task.c
+++ b/task.c
@@ -53,6 +53,7 @@ static ulong get_curr_task(int, char *);
 static long rq_idx(int);
 static long cpu_idx(int);
 static void dump_runq(void);
+static void dump_on_rq_timestamp(void);
 static void dump_runqueues(void);
 static void dump_prio_array(int, ulong, char *);
 struct rb_root;
@@ -7000,13 +7001,17 @@ cmd_runq(void)
 {
         int c;
 	int sched_debug = 0;
+	int dump_timestamp_flag = 0;
 
-        while ((c = getopt(argcnt, args, "d")) != EOF) {
+        while ((c = getopt(argcnt, args, "dt")) != EOF) {
                 switch(c)
                 {
 		case 'd':
 			sched_debug = 1;
 			break;
+		case 't':
+			dump_timestamp_flag = 1;
+			break;
                 default:
                         argerrs++;
                         break;
@@ -7017,6 +7022,12 @@ cmd_runq(void)
         if (argerrs)
                 cmd_usage(pc->curcmd, SYNOPSIS);
 
+	if (dump_timestamp_flag) {
+                dump_on_rq_timestamp();
+                return;
+        }
+
+
 	if (sched_debug) {
 		dump_on_rq_tasks();
 		return;
@@ -7026,6 +7037,56 @@ cmd_runq(void)
 }
 
 /*
+ *  Displays the timestamp information about the runqueue each of cpu
+ */
+void
+dump_on_rq_timestamp(void)
+{
+	struct task_context *tcp;
+	char format[15];
+	ulong runq;
+	char buf[BUFSIZE];
+	struct syment *rq_sp;
+	struct task_context *tc;
+	int cpu, c;
+	ulonglong timestamp;
+
+	runq = 0;
+	tcp = FIRST_CONTEXT();
+	sprintf(buf, pc->output_radix == 10 ? "%lld" : "%llx",
+		task_last_run(tcp->task));
+	c = strlen(buf);
+
+	if (!(rq_sp = per_cpu_symbol_search("per_cpu__runqueues")))
+		error(FATAL, "per-cpu runqueues does not exist\n");
+
+	for (cpu = 0; cpu < kt->cpus; cpu++) {
+		if ((kt->flags & SMP) && (kt->flags &PER_CPU_OFF))
+			runq = rq_sp->value + kt->__per_cpu_offset[cpu];
+		else
+			runq = rq_sp->value;
+
+		readmem(runq + OFFSET(rq_timestamp), KVADDR, &timestamp,
+			sizeof(ulonglong), "per-cpu rq timestamp",
+			FAULT_ON_ERROR);
+
+		sprintf(format, " CPU%2d: %c%dll%c\n", cpu, '%', c,
+			pc->output_radix == 10 ? 'u' : 'x');
+		fprintf(fp, format, timestamp);
+
+		if((tc = task_to_context(tt->active_set[cpu]))){
+			sprintf(format, "[%c%dll%c]  ", '%', c,
+				pc->output_radix == 10 ? 'u' : 'x');
+			fprintf(fp, format, task_last_run(tc->task));
+			fprintf(fp, "PID: %-5ld  TASK: %lx  COMMAND: \"%s\"\n",
+				tc->pid, tc->task, tc->comm);
+		} else
+			fprintf(fp, "%lx\n", tt->active_set[cpu]);
+
+	}
+}
+
+/*
  *  Dump the task run queue on behalf cmd_runq().
  */
 
-- 
1.7.1

