Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9075331c authored by Pavankumar Kondeti's avatar Pavankumar Kondeti
Browse files

trace: fix preemption disable tracking during context switch to idle



schedule() calls __schedule() with preemption disabled. The preemption
latency tracking code make a note of this. If the CPU enters idle there
is no up date to the latency tracking code. When the CPU exits idle,
preemption is enabled by the task that is scheduled in. The latency
tracking code thinks that preemption is disabled the whole time. To fix
this, reset the preemption latency tracking time upon context switching
from the idle task. This is only done for the idle task because we still
want to catch the long preemption disable time during the context switch
which may also involves running time of new idle load balance.

Change-Id: Ic6ec526e244911d6dac9851d32a25263abf56639
Signed-off-by: default avatarPavankumar Kondeti <pkondeti@codeaurora.org>
parent adc5c327
Loading
Loading
Loading
Loading
+19 −6
Original line number Diff line number Diff line
@@ -3322,10 +3322,24 @@ struct preempt_store {
	u64 ts;
	unsigned long caddr[4];
	bool irqs_disabled;
	bool is_idle_task;
};

DEFINE_PER_CPU(struct preempt_store, the_ps);

/*
 * This is only called from __schedule() upon context switch.
 *
 * schedule() calls __schedule() with preemption disabled.
 * if we had entered idle and exiting idle now, reset the preemption
 * tracking otherwise we may think preemption is disabled the whole time
 * when the non idle task re-enables the preemption in schedule().
 */
static inline void preempt_latency_reset(void)
{
	if (is_idle_task(this_rq()->curr))
		this_cpu_ptr(&the_ps)->ts = 0;
}

/*
 * If the value passed in is equal to the current preempt count
 * then we just disabled preemption. Start timing the latency.
@@ -3333,7 +3347,6 @@ DEFINE_PER_CPU(struct preempt_store, the_ps);
static inline void preempt_latency_start(int val)
{
	int cpu = raw_smp_processor_id();
	struct rq *rq = cpu_rq(cpu);
	struct preempt_store *ps = &per_cpu(the_ps, cpu);

	if (preempt_count() == val) {
@@ -3347,7 +3360,6 @@ static inline void preempt_latency_start(int val)
		ps->caddr[2] = CALLER_ADDR2;
		ps->caddr[3] = CALLER_ADDR3;
		ps->irqs_disabled = irqs_disabled();
		ps->is_idle_task = (rq->curr == rq->idle);

		trace_preempt_off(CALLER_ADDR0, ip);
	}
@@ -3384,14 +3396,13 @@ static inline void preempt_latency_stop(int val)
	if (preempt_count() == val) {
		struct preempt_store *ps = &per_cpu(the_ps,
				raw_smp_processor_id());
		u64 delta = sched_clock() - ps->ts;
		u64 delta = ps->ts ? (sched_clock() - ps->ts) : 0;

		/*
		 * Trace preempt disable stack if preemption
		 * is disabled for more than the threshold.
		 */
		if (!ps->is_idle_task &&
				delta > sysctl_preemptoff_tracing_threshold_ns)
		if (delta > sysctl_preemptoff_tracing_threshold_ns)
			trace_sched_preempt_disable(delta, ps->irqs_disabled,
						ps->caddr[0], ps->caddr[1],
						ps->caddr[2], ps->caddr[3]);
@@ -3424,6 +3435,7 @@ NOKPROBE_SYMBOL(preempt_count_sub);
#else
static inline void preempt_latency_start(int val) { }
static inline void preempt_latency_stop(int val) { }
static inline void preempt_latency_reset(void) { }
#endif

static inline unsigned long get_preempt_disable_ip(struct task_struct *p)
@@ -3647,6 +3659,7 @@ static void __sched notrace __schedule(bool preempt)
		if (!prev->on_rq)
			prev->last_sleep_ts = wallclock;

		preempt_latency_reset();
		update_task_ravg(prev, rq, PUT_PREV_TASK, wallclock, 0);
		update_task_ravg(next, rq, PICK_NEXT_TASK, wallclock, 0);
		rq->nr_switches++;