[PATCH 07/14] sched: add schedstats for -deadline tasks.

From: Juri Lelli
Date: Thu Nov 07 2013 - 08:46:10 EST


From: Dario Faggioli <raistlin@xxxxxxxx>

Add some typical sched-debug output to dl_rq(s) and some
schedstats to -deadline tasks. This helps spotting problems
with queue and dequeue operations (incorrect ordering) and
gives hints about system status (one can have an idea if the
system is overloaded, if tasks are missing their deadlines
and the entity of such anomalies).

Signed-off-by: Dario Faggioli <raistlin@xxxxxxxx>
Signed-off-by: Juri Lelli <juri.lelli@xxxxxxxxx>
---
include/linux/sched.h | 13 +++++++++++++
kernel/sched/deadline.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
kernel/sched/debug.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
kernel/sched/sched.h | 9 ++++++++-
4 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/include/linux/sched.h b/include/linux/sched.h
index 90517bc..3064319 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1058,6 +1058,15 @@ struct sched_rt_entity {
#endif
};

+#ifdef CONFIG_SCHEDSTATS
+struct sched_stats_dl {
+ u64 last_dmiss;
+ u64 last_rorun;
+ u64 dmiss_max;
+ u64 rorun_max;
+};
+#endif
+
struct sched_dl_entity {
struct rb_node rb_node;

@@ -1097,6 +1106,10 @@ struct sched_dl_entity {
* own bandwidth to be enforced, thus we need one timer per task.
*/
struct hrtimer dl_timer;
+
+#ifdef CONFIG_SCHEDSTATS
+ struct sched_stats_dl stats;
+#endif
};

struct rcu_node;
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 3e0e6e3..a4b86b0 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -518,6 +518,27 @@ int dl_runtime_exceeded(struct rq *rq, struct sched_dl_entity *dl_se)
if (!rorun && !dmiss)
return 0;

+#ifdef CONFIG_SCHEDSTATS
+ /*
+ * Record statistics about last and maximum deadline
+ * misses and runtime overruns.
+ */
+ if (dmiss) {
+ u64 damount = rq_clock(rq) - dl_se->deadline;
+
+ schedstat_set(dl_se->stats.last_dmiss, damount);
+ schedstat_set(dl_se->stats.dmiss_max,
+ max(dl_se->stats.dmiss_max, damount));
+ }
+ if (rorun) {
+ u64 ramount = -dl_se->runtime;
+
+ schedstat_set(dl_se->stats.last_rorun, ramount);
+ schedstat_set(dl_se->stats.rorun_max,
+ max(dl_se->stats.rorun_max, ramount));
+ }
+#endif
+
/*
* If we are beyond our current deadline and we are still
* executing, then we have already used some of the runtime of
@@ -561,6 +582,7 @@ static void update_curr_dl(struct rq *rq)
max(curr->se.statistics.exec_max, delta_exec));

curr->se.sum_exec_runtime += delta_exec;
+ schedstat_add(&rq->dl, exec_clock, delta_exec);
account_group_exec_runtime(curr, delta_exec);

curr->se.exec_start = rq_clock_task(rq);
@@ -912,6 +934,18 @@ static void start_hrtick_dl(struct rq *rq, struct task_struct *p)
}
#endif

+#ifdef CONFIG_SCHED_DEBUG
+struct sched_dl_entity *__pick_dl_last_entity(struct dl_rq *dl_rq)
+{
+ struct rb_node *last = rb_last(&dl_rq->rb_root);
+
+ if (!last)
+ return NULL;
+
+ return rb_entry(last, struct sched_dl_entity, rb_node);
+}
+#endif /* CONFIG_SCHED_DEBUG */
+
static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq,
struct dl_rq *dl_rq)
{
@@ -1593,3 +1627,16 @@ const struct sched_class dl_sched_class = {
.switched_from = switched_from_dl,
.switched_to = switched_to_dl,
};
+
+#ifdef CONFIG_SCHED_DEBUG
+extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq);
+
+void print_dl_stats(struct seq_file *m, int cpu)
+{
+ struct dl_rq *dl_rq = &cpu_rq(cpu)->dl;
+
+ rcu_read_lock();
+ print_dl_rq(m, cpu, dl_rq);
+ rcu_read_unlock();
+}
+#endif /* CONFIG_SCHED_DEBUG */
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index 1965599..811b025 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -253,6 +253,45 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
#undef P
}

+extern struct sched_dl_entity *__pick_dl_last_entity(struct dl_rq *dl_rq);
+extern void print_dl_stats(struct seq_file *m, int cpu);
+
+void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq)
+{
+ s64 min_deadline = -1, max_deadline = -1;
+ struct rq *rq = cpu_rq(cpu);
+ struct sched_dl_entity *last;
+ unsigned long flags;
+
+ SEQ_printf(m, "\ndl_rq[%d]:\n", cpu);
+
+ raw_spin_lock_irqsave(&rq->lock, flags);
+ if (dl_rq->rb_leftmost)
+ min_deadline = (rb_entry(dl_rq->rb_leftmost,
+ struct sched_dl_entity,
+ rb_node))->deadline;
+ last = __pick_dl_last_entity(dl_rq);
+ if (last)
+ max_deadline = last->deadline;
+ raw_spin_unlock_irqrestore(&rq->lock, flags);
+
+#define P(x) \
+ SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(dl_rq->x))
+#define __PN(x) \
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(x))
+#define PN(x) \
+ SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(dl_rq->x))
+
+ P(dl_nr_running);
+ PN(exec_clock);
+ __PN(min_deadline);
+ __PN(max_deadline);
+
+#undef PN
+#undef __PN
+#undef P
+}
+
extern __read_mostly int sched_clock_running;

static void print_cpu(struct seq_file *m, int cpu)
@@ -320,6 +359,7 @@ do { \
spin_lock_irqsave(&sched_debug_lock, flags);
print_cfs_stats(m, cpu);
print_rt_stats(m, cpu);
+ print_dl_stats(m, cpu);

rcu_read_lock();
print_rq(m, rq, cpu);
@@ -540,6 +580,12 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
P(se.statistics.nr_wakeups_affine_attempts);
P(se.statistics.nr_wakeups_passive);
P(se.statistics.nr_wakeups_idle);
+ if (dl_task(p)) {
+ PN(dl.stats.last_dmiss);
+ PN(dl.stats.dmiss_max);
+ PN(dl.stats.last_rorun);
+ PN(dl.stats.rorun_max);
+ }

{
u64 avg_atom, avg_per_cpu;
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 70d0030..b04aeed 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -384,6 +384,8 @@ struct dl_rq {

unsigned long dl_nr_running;

+ u64 exec_clock;
+
#ifdef CONFIG_SMP
/*
* Deadline values of the currently executing and the
@@ -410,6 +412,11 @@ struct dl_rq {
#endif
};

+#ifdef CONFIG_SCHED_DEBUG
+struct sched_dl_entity *__pick_dl_last_entity(struct dl_rq *dl_rq);
+void print_dl_stats(struct seq_file *m, int cpu);
+#endif
+
#ifdef CONFIG_SMP

/*
@@ -1366,7 +1373,7 @@ extern void print_rt_stats(struct seq_file *m, int cpu);

extern void init_cfs_rq(struct cfs_rq *cfs_rq);
extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq);
-extern void init_dl_rq(struct dl_rq *rt_rq, struct rq *rq);
+extern void init_dl_rq(struct dl_rq *dl_rq, struct rq *rq);

extern void account_cfs_bandwidth_used(int enabled, int was_enabled);

--
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/