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

Commit f99927a7 authored by Srivatsa Vaddagiri's avatar Srivatsa Vaddagiri Committed by Steve Muckle
Browse files

sched: window-stats: Retain idle thread's mark_start



init_idle() is called on a cpu's idle-thread once at bootup and
subsequently everytime the cpu is hot-added. Since init_idle() calls
__sched_fork(), we end up blowing idle thread's ravg.mark_start value.
As a result we will fail to accurately maintain cpu's
curr/prev_runnable_sum counters. Below example illustrates such a
failure:

CS = curr_runnable_sum, PS = prev_runnable_sum

t0 -> New window starts for CPU2
<after some_task_activity> CS = X, PS = Y
t1 -> <cpu2 is hot-removed. idle_task start's running on cpu2>
      At this time, cpu2_idle_thread.ravg.mark_start = t1

t1 -> t0 + W. One window elapses. CPU2 still hot-removed. We
	defer swapping CS and PS until some future task event occurs

t2 -> CPU2 hot-added.  _cpu_up()->idle_thread_get()->init_idle()
	->__sched_fork() results in cpu2_idle_thread.ravg.mark_start = 0

t3 -> Some task wakes on cpu2. Since mark_start = 0, we don't swap CS
	and PS => which is a BUG!

Fix this by retaining idle task's original mark_start value during
init_idle() call.

Change-Id: I4ac9bfe3a58fb5da8a6c7bc378c79d9930d17942
Signed-off-by: default avatarSrivatsa Vaddagiri <vatsa@codeaurora.org>
parent d2a8c71b
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -2523,6 +2523,16 @@ static int register_sched_callback(void)
 */
core_initcall(register_sched_callback);

static u64 orig_mark_start(struct task_struct *p)
{
	return p->ravg.mark_start;
}

static void restore_orig_mark_start(struct task_struct *p, u64 mark_start)
{
	p->ravg.mark_start = mark_start;
}

#else	/* CONFIG_SCHED_HMP */

static inline void fixup_busy_time(struct task_struct *p, int new_cpu) { }
@@ -2547,6 +2557,13 @@ static inline void set_window_start(struct rq *rq) {}

static inline void migrate_sync_cpu(int cpu) {}

static inline u64 orig_mark_start(struct task_struct *p) { return 0; }

static inline void
restore_orig_mark_start(struct task_struct *p, u64 mark_start)
{
}

#endif	/* CONFIG_SCHED_HMP */

#ifdef CONFIG_SMP
@@ -6615,10 +6632,16 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
{
	struct rq *rq = cpu_rq(cpu);
	unsigned long flags;
	u64 mark_start = orig_mark_start(idle);

	raw_spin_lock_irqsave(&rq->lock, flags);

	__sched_fork(idle);
	/*
	 * Restore idle thread's original mark_start as we rely on it being
	 * correct for maintaining per-cpu counters, curr/prev_runnable_sum.
	 */
	restore_orig_mark_start(idle, mark_start);
	idle->state = TASK_RUNNING;
	idle->se.exec_start = sched_clock();