sched: add scheduling latency tracking procfs node
Add a new procfs node /proc/sys/kernel/sched_max_latency_us to track the worst scheduling latency. It provides easier way to identify maximum scheduling latency seen across the CPUs. Change-Id: I6e435bbf825c0a4dff2eded4a1256fb93f108d0e Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
This commit is contained in:
parent
4653e0549d
commit
32851d8550
|
@ -156,6 +156,13 @@ Set sched_latency_warn_threshold_us or sched_latency_panic_threshold_us with
|
|||
non-zero threshold to warn or panic system when scheduling latency higher than
|
||||
configured threshold is detected. Default is 0 (disabled) for both.
|
||||
|
||||
/proc/sys/kernel/sched_max_latency_us
|
||||
----------------
|
||||
/proc/sys/kernel/sched_max_latency_us shows the maximum scheduling latency seen
|
||||
accross the CPUs. The file shows the maximum latency seen in microseconds along
|
||||
with the cpu number or cpu id and the task that incurred maximum latency on that
|
||||
cpu. The maximum latency can be reset by writing any value to the file.
|
||||
|
||||
A program could be easily written to make use of these extra fields to
|
||||
report on how well a particular process or set of processes is faring
|
||||
under the scheduler's policies. A simple version of such a program is
|
||||
|
|
|
@ -143,6 +143,10 @@ extern unsigned int sysctl_sched_autogroup_enabled;
|
|||
#ifdef CONFIG_SCHEDSTATS
|
||||
extern unsigned int sysctl_sched_latency_panic_threshold;
|
||||
extern unsigned int sysctl_sched_latency_warn_threshold;
|
||||
|
||||
extern int sched_max_latency_sysctl(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp,
|
||||
loff_t *ppos);
|
||||
#endif
|
||||
|
||||
extern int sched_rr_timeslice;
|
||||
|
|
|
@ -125,6 +125,14 @@ unsigned int sysctl_sched_cfs_bandwidth_slice = 5000UL;
|
|||
#ifdef CONFIG_SCHEDSTATS
|
||||
unsigned int sysctl_sched_latency_panic_threshold;
|
||||
unsigned int sysctl_sched_latency_warn_threshold;
|
||||
|
||||
struct sched_max_latency {
|
||||
unsigned int latency_us;
|
||||
char comm[TASK_COMM_LEN];
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct sched_max_latency, sched_max_latency);
|
||||
#endif /* CONFIG_SCHEDSTATS */
|
||||
|
||||
/*
|
||||
|
@ -758,6 +766,54 @@ static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_SCHEDSTATS
|
||||
int sched_max_latency_sysctl(struct ctl_table *table, int write,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos)
|
||||
{
|
||||
int ret = 0;
|
||||
int i, cpu = nr_cpu_ids;
|
||||
char msg[256];
|
||||
unsigned long flags;
|
||||
struct rq *rq;
|
||||
struct sched_max_latency max, *lat;
|
||||
|
||||
if (!write) {
|
||||
max.latency_us = 0;
|
||||
for_each_possible_cpu(i) {
|
||||
rq = cpu_rq(i);
|
||||
raw_spin_lock_irqsave(&rq->lock, flags);
|
||||
|
||||
lat = &per_cpu(sched_max_latency, i);
|
||||
if (max.latency_us < lat->latency_us) {
|
||||
max = *lat;
|
||||
cpu = i;
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&rq->lock, flags);
|
||||
}
|
||||
|
||||
if (cpu != nr_cpu_ids) {
|
||||
table->maxlen =
|
||||
snprintf(msg, sizeof(msg),
|
||||
"cpu%d comm=%s pid=%u latency=%u(us)",
|
||||
cpu, max.comm, max.pid, max.latency_us);
|
||||
table->data = msg;
|
||||
ret = proc_dostring(table, write, buffer, lenp, ppos);
|
||||
}
|
||||
} else {
|
||||
for_each_possible_cpu(i) {
|
||||
rq = cpu_rq(i);
|
||||
raw_spin_lock_irqsave(&rq->lock, flags);
|
||||
|
||||
memset(&per_cpu(sched_max_latency, i), 0,
|
||||
sizeof(struct sched_max_latency));
|
||||
|
||||
raw_spin_unlock_irqrestore(&rq->lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void check_for_high_latency(struct task_struct *p, u64 latency_us)
|
||||
{
|
||||
int do_warn, do_panic;
|
||||
|
@ -800,11 +856,19 @@ update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se,
|
|||
#ifdef CONFIG_SCHEDSTATS
|
||||
if (entity_is_task(se)) {
|
||||
u64 delta;
|
||||
struct sched_max_latency *max;
|
||||
|
||||
delta = rq_of(cfs_rq)->clock - se->statistics.wait_start;
|
||||
trace_sched_stat_wait(task_of(se), delta);
|
||||
|
||||
delta = delta >> 10;
|
||||
max = this_cpu_ptr(&sched_max_latency);
|
||||
if (max->latency_us < delta) {
|
||||
max->latency_us = delta;
|
||||
max->pid = task_of(se)->pid;
|
||||
memcpy(max->comm, task_of(se)->comm, TASK_COMM_LEN);
|
||||
}
|
||||
|
||||
check_for_high_latency(task_of(se), delta);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -618,6 +618,11 @@ static struct ctl_table kern_table[] = {
|
|||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec_minmax,
|
||||
},
|
||||
{
|
||||
.procname = "sched_max_latency_us",
|
||||
.mode = 0644,
|
||||
.proc_handler = sched_max_latency_sysctl,
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue