sched/walt: allow checking of last halt time against threshold

Support the ability to check whether the current time is within
a threshold since the last time the cpu was halted. If it's
within that threshold, pass the check.

Use that check to catch tasks being enqueued on halted cpus.

Change-Id: I1716aefc970fc3dea7474f6321971bf00c3b76f4
Signed-off-by: Stephen Dickey <quic_dickey@quicinc.com>
This commit is contained in:
Stephen Dickey 2022-01-11 10:37:51 -08:00 committed by Rishabh Bhatnagar
parent 2b8a21e9a4
commit 59b2ef40cb
3 changed files with 47 additions and 5 deletions

View File

@ -3942,6 +3942,11 @@ static void android_rvh_enqueue_task(void *unused, struct rq *rq, struct task_st
WALT_BUG(WALT_BUG_NONCRITICAL, p, "enqueueing on rq=%d comm=%s(%d) affinity=0x%x",
cpu_of(rq), p->comm, p->pid, (*(cpumask_bits(p->cpus_ptr))));
if (cpu_halted(cpu_of(rq)) && !(p->flags & PF_KTHREAD) && !walt_halt_check_last(cpu_of(rq)))
WALT_BUG(WALT_BUG_NONCRITICAL, p,
"Non Kthread Started on halted cpu_of(rq)=%d comm=%s(%d) affinity=0x%x\n",
cpu_of(rq), p->comm, p->pid, (*(cpumask_bits(p->cpus_ptr))));
wts->prev_on_rq = 1;
wts->prev_on_rq_cpu = cpu_of(rq);

View File

@ -905,6 +905,7 @@ struct compute_energy_output {
unsigned int cluster_first_cpu[MAX_CLUSTERS];
};
bool walt_halt_check_last(int cpu);
extern struct cpumask __cpu_halt_mask;
#define cpu_halt_mask ((struct cpumask *)&__cpu_halt_mask)
#define cpu_halted(cpu) cpumask_test_cpu((cpu), cpu_halt_mask)

View File

@ -15,11 +15,17 @@ struct cpumask __cpu_halt_mask;
static DEFINE_MUTEX(halt_lock);
struct halt_cpu_state {
u64 last_halt;
int ref_count;
};
static DEFINE_PER_CPU(struct halt_cpu_state, halt_state);
/* the amount of time allowed for enqueue operations that happen
* just after a halt operation.
*/
#define WALT_HALT_CHECK_THRESHOLD_NS 400000
/*
* Remove a task from the runqueue and pretend that it's migrating. This
* should prevent migrations for the detached task and disallow further
@ -176,6 +182,21 @@ static int cpu_drain_rq(unsigned int cpu)
return stop_one_cpu(cpu, drain_rq_cpu_stop, NULL);
}
/*
* returns true if last halt is within threshold
* note: do not take halt_lock, called from atomic context
*/
bool walt_halt_check_last(int cpu)
{
u64 last_halt = per_cpu_ptr(&halt_state, cpu)->last_halt;
/* last_halt is valid, check it against sched_clock */
if (last_halt != 0 && sched_clock() - last_halt > WALT_HALT_CHECK_THRESHOLD_NS)
return false;
return true;
}
/*
* 1) add the cpus to the halt mask
* 2) migrate tasks off the cpu
@ -186,14 +207,22 @@ static int halt_cpus(struct cpumask *cpus)
int cpu;
int ret = 0;
u64 start_time = sched_clock();
struct halt_cpu_state *halt_cpu_state;
trace_halt_cpus_start(cpus, 1);
for_each_cpu(cpu, cpus) {
halt_cpu_state = per_cpu_ptr(&halt_state, cpu);
/* set the cpu as halted */
cpumask_set_cpu(cpu, cpu_halt_mask);
/* guarantee mask written before updating last_halt */
wmb();
halt_cpu_state->last_halt = start_time;
/* only drain online cpus */
if (cpu_online(cpu)) {
/* drain the online CPU */
@ -219,12 +248,19 @@ static int halt_cpus(struct cpumask *cpus)
static int start_cpus(struct cpumask *cpus)
{
u64 start_time = sched_clock();
struct halt_cpu_state *halt_cpu_state;
int cpu;
trace_halt_cpus_start(cpus, 0);
if (!cpumask_empty(cpus)) {
/* remove the cpus from the halt mask */
cpumask_andnot(cpu_halt_mask, cpu_halt_mask, cpus);
for_each_cpu(cpu, cpus) {
halt_cpu_state = per_cpu_ptr(&halt_state, cpu);
halt_cpu_state->last_halt = 0;
/* guarantee zero'd last_halt before clearing from the mask */
wmb();
cpumask_clear_cpu(cpu, cpu_halt_mask);
}
trace_halt_cpus(cpus, start_time, 0, 0);
@ -240,9 +276,9 @@ static void update_ref_counts(struct cpumask *cpus, bool halt)
for_each_cpu(cpu, cpus) {
halt_cpu_state = per_cpu_ptr(&halt_state, cpu);
if (halt)
if (halt) {
halt_cpu_state->ref_count++;
else {
} else {
WARN_ON_ONCE(halt_cpu_state->ref_count == 0);
halt_cpu_state->ref_count--;
}