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

Commit 9c8a5a48 authored by Junjie Wu's avatar Junjie Wu
Browse files

cpufreq: interactive: Handle notification even if timer fires first



Scheduler provides different load number based on whether a
notification is pending. Under normal situation, it won't provide a
load that exceeds 100% busy time of current frequency. For migration,
the busy time can be huge if a heavy task just moved to the CPU.

This creates a race condition due to how governor handles
notification:
1) Scheduler sends notification for a big task
2) Governor timer runs, and gets a huge load, but fails to skip
hispeed_freq logic and all delays because it's not a notification
3) After receiving sched_get_cpus_busy(), scheduler thinks governor has
finished handling the notification and changes to provide normal load
that is capped to 100% of the CPU at current frequency.
4) Governor now starts handling notification, but gets a small load
that doesn't reflect real demand of the heavy task.

The migration notification is thus effectively lost. Fixing this by
making notification pending a per-cpu flag. If timer gets ahead of
notification handling, it will be run as if it's a notification.

Change-Id: Ie3d68edf85b822232a646c2694bec6928a2d7cd1
Signed-off-by: default avatarJunjie Wu <junjiew@codeaurora.org>
parent 64182585
Loading
Loading
Loading
Loading
+14 −10
Original line number Original line Diff line number Diff line
@@ -51,6 +51,7 @@ struct cpufreq_interactive_policyinfo {
	u64 max_freq_hyst_start_time;
	u64 max_freq_hyst_start_time;
	struct rw_semaphore enable_sem;
	struct rw_semaphore enable_sem;
	bool reject_notification;
	bool reject_notification;
	bool notif_pending;
	int governor_enabled;
	int governor_enabled;
	struct cpufreq_interactive_tunables *cached_tunables;
	struct cpufreq_interactive_tunables *cached_tunables;
	struct sched_load *sl;
	struct sched_load *sl;
@@ -433,7 +434,7 @@ static u64 update_load(int cpu)
}
}


#define NEW_TASK_RATIO 75
#define NEW_TASK_RATIO 75
static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
static void cpufreq_interactive_timer(unsigned long data)
{
{
	u64 now;
	u64 now;
	unsigned int delta_time;
	unsigned int delta_time;
@@ -462,12 +463,15 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
		goto exit;
		goto exit;


	fcpu = cpumask_first(ppol->policy->related_cpus);
	fcpu = cpumask_first(ppol->policy->related_cpus);
	skip_hispeed_logic = tunables->ignore_hispeed_on_notif && is_notif;
	skip_min_sample_time = tunables->fast_ramp_down && is_notif;

	now = ktime_to_us(ktime_get());
	now = ktime_to_us(ktime_get());

	spin_lock_irqsave(&ppol->target_freq_lock, flags);
	spin_lock_irqsave(&ppol->target_freq_lock, flags);
	spin_lock(&ppol->load_lock);
	spin_lock(&ppol->load_lock);

	skip_hispeed_logic = tunables->ignore_hispeed_on_notif &&
						ppol->notif_pending;
	skip_min_sample_time = tunables->fast_ramp_down && ppol->notif_pending;
	ppol->notif_pending = false;
	ppol->last_evaluated_jiffy = get_jiffies_64();
	ppol->last_evaluated_jiffy = get_jiffies_64();


	if (tunables->use_sched_load)
	if (tunables->use_sched_load)
@@ -649,11 +653,6 @@ exit:
	return;
	return;
}
}


static void cpufreq_interactive_timer(unsigned long data)
{
	__cpufreq_interactive_timer(data, false);
}

static int cpufreq_interactive_speedchange_task(void *data)
static int cpufreq_interactive_speedchange_task(void *data)
{
{
	unsigned int cpu;
	unsigned int cpu;
@@ -752,6 +751,7 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val,
	unsigned long cpu = (unsigned long) data;
	unsigned long cpu = (unsigned long) data;
	struct cpufreq_interactive_policyinfo *ppol = per_cpu(polinfo, cpu);
	struct cpufreq_interactive_policyinfo *ppol = per_cpu(polinfo, cpu);
	struct cpufreq_interactive_tunables *tunables;
	struct cpufreq_interactive_tunables *tunables;
	unsigned long flags;


	if (speedchange_task == current)
	if (speedchange_task == current)
		return 0;
		return 0;
@@ -771,9 +771,12 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val,
	}
	}


	trace_cpufreq_interactive_load_change(cpu);
	trace_cpufreq_interactive_load_change(cpu);
	spin_lock_irqsave(&ppol->target_freq_lock, flags);
	ppol->notif_pending = true;
	spin_unlock_irqrestore(&ppol->target_freq_lock, flags);
	del_timer(&ppol->policy_timer);
	del_timer(&ppol->policy_timer);
	del_timer(&ppol->policy_slack_timer);
	del_timer(&ppol->policy_slack_timer);
	__cpufreq_interactive_timer(cpu, true);
	cpufreq_interactive_timer(cpu);


	up_read(&ppol->enable_sem);
	up_read(&ppol->enable_sem);
	return 0;
	return 0;
@@ -1695,6 +1698,7 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
		ppol->hispeed_validate_time = ppol->floor_validate_time;
		ppol->hispeed_validate_time = ppol->floor_validate_time;
		ppol->min_freq = policy->min;
		ppol->min_freq = policy->min;
		ppol->reject_notification = true;
		ppol->reject_notification = true;
		ppol->notif_pending = false;
		down_write(&ppol->enable_sem);
		down_write(&ppol->enable_sem);
		del_timer_sync(&ppol->policy_timer);
		del_timer_sync(&ppol->policy_timer);
		del_timer_sync(&ppol->policy_slack_timer);
		del_timer_sync(&ppol->policy_slack_timer);