Signed-off-by: Oleksandr Natalenko <oleksandr(a)redhat.com>
---
help.c | 4 ++-
task.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 95 insertions(+), 2 deletions(-)
diff --git a/help.c b/help.c
index f7f61a1..6c1db63 100644
--- a/help.c
+++ b/help.c
@@ -2532,7 +2532,7 @@ NULL
char *help_runq[] = {
"runq",
"run queue",
-"[-t] [-m] [-g] [-c cpu(s)]",
+"[-t] [-T] [-m] [-g] [-c cpu(s)]",
" With no argument, this command displays the tasks on the run queues",
" of each cpu.",
" ",
@@ -2541,6 +2541,8 @@ char *help_runq[] = {
" whichever applies; following each cpu timestamp is the last_run or
",
" timestamp value of the active task on that cpu, whichever applies,
",
" along with the task identification.",
+" -T Display lag of each CPU that is relative to the most recent
runqueue",
+" timestamp.",
" -m Display the amount of time that the active task on each cpu has
been",
" running, expressed in a format consisting of days, hours, minutes,
",
" seconds and milliseconds.",
diff --git a/task.c b/task.c
index 5754159..e367c94 100644
--- a/task.c
+++ b/task.c
@@ -55,6 +55,7 @@ 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_on_rq_lag(void);
static void dump_on_rq_milliseconds(void);
static void dump_runqueues(void);
static void dump_prio_array(int, ulong, char *);
@@ -8045,10 +8046,11 @@ cmd_runq(void)
ulong *cpus = NULL;
int sched_debug = 0;
int dump_timestamp_flag = 0;
+ int dump_lag_flag = 0;
int dump_task_group_flag = 0;
int dump_milliseconds_flag = 0;
- while ((c = getopt(argcnt, args, "dtgmc:")) != EOF) {
+ while ((c = getopt(argcnt, args, "dtTgmc:")) != EOF) {
switch(c)
{
case 'd':
@@ -8057,6 +8059,9 @@ cmd_runq(void)
case 't':
dump_timestamp_flag = 1;
break;
+ case 'T':
+ dump_lag_flag = 1;
+ break;
case 'm':
dump_milliseconds_flag = 1;
break;
@@ -8092,6 +8097,8 @@ cmd_runq(void)
if (dump_timestamp_flag)
dump_on_rq_timestamp();
+ else if (dump_lag_flag)
+ dump_on_rq_lag();
else if (dump_milliseconds_flag)
dump_on_rq_milliseconds();
else if (sched_debug)
@@ -8176,6 +8183,90 @@ dump_on_rq_timestamp(void)
}
}
+/*
+ * Runqueue timestamp struct for dump_on_rq_lag().
+ */
+struct runq_ts_info {
+ int cpu;
+ ulonglong ts;
+};
+
+/*
+ * Comparison function for dump_on_rq_lag().
+ * Sorts runqueue timestamps in a descending order.
+ */
+static int
+compare_runq_ts(const void *p1, const void *p2)
+{
+ const struct runq_ts_info *ts1 = p1;
+ const struct runq_ts_info *ts2 = p2;
+
+ if (ts1->ts > ts2->ts)
+ return -1;
+
+ if (ts1->ts < ts2->ts)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Calculates integer log10
+ */
+static ulong
+__log10ul(ulong x)
+{
+ ulong ret = 1;
+
+ while (x > 9) {
+ ret++;
+ x /= 10;
+ }
+
+ return ret;
+}
+
+/*
+ * Displays relative CPU lag.
+ */
+static void
+dump_on_rq_lag(void)
+{
+ struct syment *rq_sp;
+ int cpu;
+ ulong runq;
+ ulonglong timestamp;
+ struct runq_ts_info runq_ts[kt->cpus];
+
+ if (!(rq_sp = per_cpu_symbol_search("per_cpu__runqueues")))
+ error(FATAL, "per-cpu runqueues do not exist\n");
+ if (INVALID_MEMBER(rq_timestamp))
+ option_not_supported('T');
+
+ 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, ×tamp,
+ sizeof(ulonglong), "per-cpu rq timestamp",
+ FAULT_ON_ERROR);
+
+ runq_ts[cpu].cpu = cpu;
+ runq_ts[cpu].ts = timestamp;
+ }
+
+ qsort(runq_ts, (size_t)kt->cpus, sizeof(struct runq_ts_info), compare_runq_ts);
+
+ for (cpu = 0; cpu < kt->cpus; cpu++) {
+ fprintf(fp, "%sCPU %d: %.2lf secs\n",
+ space(2 + __log10ul(kt->cpus) - __log10ul(runq_ts[cpu].cpu)),
+ runq_ts[cpu].cpu,
+ ((double)runq_ts[0].ts - (double)runq_ts[cpu].ts) / 1000000000.0);
+ }
+}
+
/*
* Displays the runqueue and active task timestamps of each cpu.
*/
--
2.15.0