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

Commit f2002d22 authored by Junjie Wu's avatar Junjie Wu
Browse files

cpufreq: interactive: Re-evaluate immediately in load change callback



Previously, there was a limitation in load change callback that it
can't attempt to wake up a task. Therefore the best we can do is to
schedule timer at current jiffy. The timer function will only be
executed at next timer tick. This could take up to 10ms.

Now that this limitation is removed, re-evaluate load immediately upon
receiving this callback.

Change-Id: Iab3de4705b9aae96054655b1541e32fb040f7e60
Signed-off-by: default avatarJunjie Wu <junjiew@codeaurora.org>
parent 19b3f3f8
Loading
Loading
Loading
Loading
+22 −33
Original line number Diff line number Diff line
@@ -149,25 +149,6 @@ static inline int set_window_helper(
			 usecs_to_jiffies(tunables->timer_rate));
}

/*
 * Scheduler holds various locks when sending load change notification.
 * Attempting to wake up a thread or schedule a work could result in a
 * deadlock. Therefore we schedule the timer to fire immediately.
 * Since we are just re-evaluating previous window's load, we
 * should not push back slack timer.
 */
static void cpufreq_interactive_timer_resched_now(unsigned long cpu)
{
	unsigned long flags;
	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);

	spin_lock_irqsave(&pcpu->load_lock, flags);
	del_timer(&pcpu->cpu_timer);
	pcpu->cpu_timer.expires = jiffies;
	add_timer_on(&pcpu->cpu_timer, cpu);
	spin_unlock_irqrestore(&pcpu->load_lock, flags);
}

static void cpufreq_interactive_timer_resched(unsigned long cpu)
{
	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
@@ -410,10 +391,9 @@ static void cpufreq_interactive_timer(unsigned long data)
		/*
		 * Unlock early to avoid deadlock.
		 *
		 * cpufreq_interactive_timer_resched_now() is called
		 * in thread migration notification which already holds
		 * rq lock. Then it locks load_lock to avoid racing with
		 * cpufreq_interactive_timer_resched/start().
		 * load_change_callback() for thread migration already
		 * holds rq lock. Then it locks load_lock to avoid racing
		 * with cpufreq_interactive_timer_resched/start().
		 * sched_get_busy() will also acquire rq lock. Thus we
		 * can't hold load_lock when calling sched_get_busy().
		 *
@@ -704,18 +684,27 @@ static int load_change_callback(struct notifier_block *nb, unsigned long val,
	struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
	struct cpufreq_interactive_tunables *tunables;

	/*
	 * We can't acquire enable_sem here. However, this doesn't matter
	 * because timer function will grab it and check if governor is
	 * enabled before doing anything. Therefore the execution is
	 * still correct.
	 */
	if (pcpu->governor_enabled) {
		tunables = per_cpu(cpuinfo, pcpu->first_cpu).cached_tunables;
		if (tunables->use_sched_load && tunables->use_migration_notif)
			cpufreq_interactive_timer_resched_now(cpu);
	if (speedchange_task == current)
		return 0;

	if (!down_read_trylock(&pcpu->enable_sem))
		return 0;
	if (!pcpu->governor_enabled) {
		up_read(&pcpu->enable_sem);
		return 0;
	}
	tunables = pcpu->policy->governor_data;
	if (!tunables->use_sched_load || !tunables->use_migration_notif) {
		up_read(&pcpu->enable_sem);
		return 0;
	}

	trace_cpufreq_interactive_load_change(cpu);
	del_timer(&pcpu->cpu_timer);
	del_timer(&pcpu->cpu_slack_timer);
	cpufreq_interactive_timer(cpu);

	up_read(&pcpu->enable_sem);
	return 0;
}

+12 −0
Original line number Diff line number Diff line
@@ -106,6 +106,18 @@ TRACE_EVENT(cpufreq_interactive_unboost,
	    TP_printk("%s", __get_str(s))
);

TRACE_EVENT(cpufreq_interactive_load_change,
	    TP_PROTO(unsigned long cpu_id),
	    TP_ARGS(cpu_id),
	    TP_STRUCT__entry(
		__field(unsigned long, cpu_id)
	    ),
	    TP_fast_assign(
		__entry->cpu_id = cpu_id;
	    ),
	    TP_printk("re-evaluate for cpu=%lu", __entry->cpu_id)
);

#endif /* _TRACE_CPUFREQ_INTERACTIVE_H */

/* This part must be outside protection */