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

Commit e81a1d6e authored by Srivatsa Vaddagiri's avatar Srivatsa Vaddagiri Committed by Syed Rameez Mustafa
Browse files

sched: window-stats: Fix exit race



Exiting tasks are removed from tasklist and hence at some point will
become invisible to do_each_thread/for_each_thread task iterators.
This breaks the functionality of reset_all_windows_stats() which *has*
to reset stats for *all* tasks.

This patch causes exiting tasks stats to be reset *before* they are
removed from tasklist. DONT_ACCOUNT bit in exiting task's ravg.flags
is also marked so that their remaining execution time is not accounted
in cpu busy time counters (rq->curr/prev_runnable_sum).
reset_all_windows_stats() is thus guaranteed to return with all task's
stats reset to 0.

Change-Id: I5f101156a4f958c1b3f31eb0db8cd06e621b75e9
Signed-off-by: default avatarSrivatsa Vaddagiri <vatsa@codeaurora.org>
parent f90ea88f
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -2131,6 +2131,11 @@ extern void wake_up_new_task(struct task_struct *tsk);
#endif
#endif
extern void sched_fork(struct task_struct *p);
extern void sched_fork(struct task_struct *p);
extern void sched_dead(struct task_struct *p);
extern void sched_dead(struct task_struct *p);
#if defined(CONFIG_SCHED_HMP) || defined(CONFIG_SCHED_FREQ_INPUT)
extern void sched_exit(struct task_struct *p);
#else
static inline void sched_exit(struct task_struct *p) { }
#endif


extern void proc_caches_init(void);
extern void proc_caches_init(void);
extern void flush_signals(struct task_struct *);
extern void flush_signals(struct task_struct *);
+3 −0
Original line number Original line Diff line number Diff line
@@ -769,6 +769,9 @@ void do_exit(long code)
	}
	}


	exit_signals(tsk);  /* sets PF_EXITING */
	exit_signals(tsk);  /* sets PF_EXITING */

	sched_exit(tsk);

	/*
	/*
	 * tsk->flags are checked in the futex code to protect against
	 * tsk->flags are checked in the futex code to protect against
	 * an exiting task cleaning up the robust pi futexes.
	 * an exiting task cleaning up the robust pi futexes.
+51 −4
Original line number Original line Diff line number Diff line
@@ -1188,6 +1188,7 @@ static u64 sched_clock_at_init_jiffy;


#define CURR_WINDOW_CONTRIB	1
#define CURR_WINDOW_CONTRIB	1
#define PREV_WINDOW_CONTRIB	2
#define PREV_WINDOW_CONTRIB	2
#define DONT_ACCOUNT		4


/* Returns how undercommitted a CPU is given its current frequency and
/* Returns how undercommitted a CPU is given its current frequency and
 * task load (as measured in the previous window).  Returns this value
 * task load (as measured in the previous window).  Returns this value
@@ -1232,7 +1233,7 @@ update_history(struct rq *rq, struct task_struct *p, u32 runtime, int samples,
	u64 sum = 0;
	u64 sum = 0;


	if (new_window) {
	if (new_window) {
		p->ravg.flags = 0;
		p->ravg.flags &= ~(CURR_WINDOW_CONTRIB | PREV_WINDOW_CONTRIB);
		if (runtime)
		if (runtime)
			p->ravg.flags |= PREV_WINDOW_CONTRIB;
			p->ravg.flags |= PREV_WINDOW_CONTRIB;
	}
	}
@@ -1447,7 +1448,14 @@ static void update_task_ravg(struct task_struct *p, struct rq *rq,
			new_window = 1;
			new_window = 1;
		}
		}


		if (update_sum) {
		/*
		 * Tasks marked as DONT_ACCOUNT will not be accounted in
		 * rq->prev/curr_runnable_sum. We however want to perform
		 * maintenance duties on other counters such as window_start
		 * and roll over of curr_runnable_sum into prev_runnable_sum
		 * when update_task_ravg() is called on such tasks.
		 */
		if (update_sum && !(p->ravg.flags & DONT_ACCOUNT)) {
			delta = now - mark_start;
			delta = now - mark_start;
			delta = scale_exec_time(delta, rq);
			delta = scale_exec_time(delta, rq);
			BUG_ON(delta < 0);
			BUG_ON(delta < 0);
@@ -1467,7 +1475,7 @@ static void update_task_ravg(struct task_struct *p, struct rq *rq,


		if (nr_full_windows) {
		if (nr_full_windows) {
			window_start += nr_full_windows * window_size;
			window_start += nr_full_windows * window_size;
			if (update_sum)
			if (update_sum && !(p->ravg.flags & DONT_ACCOUNT))
				sum = window_size;
				sum = window_size;
			sum = scale_exec_time(sum, rq);
			sum = scale_exec_time(sum, rq);
			update_history(rq, p, sum, nr_full_windows,
			update_history(rq, p, sum, nr_full_windows,
@@ -1660,11 +1668,50 @@ static void reset_task_stats(struct task_struct *p)
	p->ravg.sum = 0;
	p->ravg.sum = 0;
	p->ravg.demand = 0;
	p->ravg.demand = 0;
	p->ravg.partial_demand = 0;
	p->ravg.partial_demand = 0;
	p->ravg.flags = 0;
	p->ravg.flags &= ~(CURR_WINDOW_CONTRIB | PREV_WINDOW_CONTRIB);
	for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i)
	for (i = 0; i < RAVG_HIST_SIZE_MAX; ++i)
		p->ravg.sum_history[i] = 0;
		p->ravg.sum_history[i] = 0;
}
}


/*
 * sched_exit() - Set DONT_ACCOUNT bit in task's ravg.flags
 *
 * This will remove an exiting task's stats from cpu busy counters
 * (rq->curr/prev_runnable_sum) and also reset its stats. DONT_ACCOUNT bit is
 * also set in exiting tasks ravg.flags so that its future usage of cpu is
 * discounted from cpu busy time.
 *
 * We need this so that reset_all_windows_stats() can function correctly.
 * reset_all_window_stats() depends on do_each_thread/for_each_thread task
 * iterators to reset *all* task's statistics. Exiting tasks however become
 * invisible to those iterators. sched_exit() is called on a exiting task prior
 * to being removed from task_list, which will let reset_all_window_stats()
 * function correctly.
 */
void sched_exit(struct task_struct *p)
{
	unsigned long flags;
	int cpu = get_cpu();
	struct rq *rq = cpu_rq(cpu);

	raw_spin_lock_irqsave(&rq->lock, flags);
	/* rq->curr == p */
	update_task_ravg(rq->curr, rq, TASK_UPDATE, sched_clock(), 0);
	dequeue_task(rq, p, 0);
	if (p->ravg.flags & CURR_WINDOW_CONTRIB)
		rq->curr_runnable_sum -= p->ravg.partial_demand;
	if (p->ravg.flags & PREV_WINDOW_CONTRIB)
		rq->prev_runnable_sum -= p->ravg.demand;
	BUG_ON((s64)rq->curr_runnable_sum < 0);
	BUG_ON((s64)rq->prev_runnable_sum < 0);
	reset_task_stats(p);
	p->ravg.flags |= DONT_ACCOUNT;
	enqueue_task(rq, p, 0);
	raw_spin_unlock_irqrestore(&rq->lock, flags);

	put_cpu();
}

/* Called with IRQs disabled */
/* Called with IRQs disabled */
void reset_all_window_stats(u64 window_start, unsigned int window_size)
void reset_all_window_stats(u64 window_start, unsigned int window_size)
{
{