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

Commit bc941792 authored by Rohit Gupta's avatar Rohit Gupta Committed by Matt Wagantall
Browse files

cpufreq: interactive: Rearm governor timer at max freq



Currently interactive governor timer doesn't re-arm itself when it
selects policy->max as the new frequency to go to. On hitting idle
for the first time at max frequency timer is armed again. This
mechanism doesn't have any noticeable performance benefits since
CPUs running at max frequencies without going into idles show high
loads which prevents the governor from lowering their frequencies.
This change rearms the timer even at max frequency which removes
the need to handle idle starts. This simplifies the code and also
makes the governor timer windows more regular so that the
notifications going out from the governor are uniformly spaced
apart. Max freq hysteresis start timestamp is refreshed everytime
policy->max is selected as the new frequency to prevent stepping
down from max frequency earlier than intended.

Change-Id: I9c137113b703f2064f1e668628db91de94cc0887
Signed-off-by: default avatarRohit Gupta <rohgup@codeaurora.org>
parent 2fbeb27a
Loading
Loading
Loading
Loading
+8 −69
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ struct cpufreq_interactive_cpuinfo {
	u64 floor_validate_time;
	u64 hispeed_validate_time; /* cluster hispeed_validate_time */
	u64 local_hvtime; /* per-cpu hispeed_validate_time */
	u64 max_freq_idle_start_time;
	u64 max_freq_hyst_start_time;
	struct rw_semaphore enable_sem;
	bool reject_notification;
	int governor_enabled;
@@ -488,9 +488,8 @@ static void cpufreq_interactive_timer(unsigned long data)

	new_freq = pcpu->freq_table[index].frequency;

	if (pcpu->target_freq >= pcpu->policy->max
	    && new_freq < pcpu->target_freq
	    && now - pcpu->max_freq_idle_start_time <
	if (new_freq < pcpu->target_freq &&
	    now - pcpu->max_freq_hyst_start_time <
	    tunables->max_freq_hysteresis) {
		trace_cpufreq_interactive_notyet(data, cpu_load,
			pcpu->target_freq, pcpu->policy->cur, new_freq);
@@ -526,13 +525,16 @@ static void cpufreq_interactive_timer(unsigned long data)
		pcpu->floor_validate_time = now;
	}

	if (new_freq == pcpu->policy->max)
		pcpu->max_freq_hyst_start_time = now;

	if (pcpu->target_freq == new_freq &&
			pcpu->target_freq <= pcpu->policy->cur) {
		trace_cpufreq_interactive_already(
			data, cpu_load, pcpu->target_freq,
			pcpu->policy->cur, new_freq);
		spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
		goto rearm_if_notmax;
		goto rearm;
	}

	trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq,
@@ -545,14 +547,6 @@ static void cpufreq_interactive_timer(unsigned long data)
	spin_unlock_irqrestore(&speedchange_cpumask_lock, flags);
	wake_up_process(speedchange_task);

rearm_if_notmax:
	/*
	 * Already set max speed and don't see a need to change that,
	 * wait until next idle to re-evaluate, don't need timer.
	 */
	if (pcpu->target_freq == pcpu->policy->max)
		goto exit;

rearm:
	if (!timer_pending(&pcpu->cpu_timer))
		cpufreq_interactive_timer_resched(data);
@@ -562,55 +556,6 @@ exit:
	return;
}

static void cpufreq_interactive_idle_start(void)
{
	struct cpufreq_interactive_cpuinfo *pcpu =
		&per_cpu(cpuinfo, smp_processor_id());
	int pending;
	struct cpufreq_interactive_tunables *tunables;
	unsigned long flags;
	u64 now;

	if (!down_read_trylock(&pcpu->enable_sem))
		return;
	if (!pcpu->governor_enabled) {
		up_read(&pcpu->enable_sem);
		return;
	}

	pending = timer_pending(&pcpu->cpu_timer);

	if (pcpu->target_freq != pcpu->policy->min) {
		/*
		 * Entering idle while not at lowest speed.  On some
		 * platforms this can hold the other CPU(s) at that speed
		 * even though the CPU is idle. Set a timer to re-evaluate
		 * speed so this idle CPU doesn't hold the other CPUs above
		 * min indefinitely.  This should probably be a quirk of
		 * the CPUFreq driver.
		 */
		if (!pending) {
			pcpu->last_evaluated_jiffy = get_jiffies_64();
			cpufreq_interactive_timer_resched(smp_processor_id());

			/*
			 * If timer is cancelled because CPU is running at
			 * policy->max, record the time CPU first goes to
			 * idle.
			 */
			now = ktime_to_us(ktime_get());
			tunables = pcpu->policy->governor_data;
			if (tunables->max_freq_hysteresis) {
				spin_lock_irqsave(&pcpu->target_freq_lock,
						  flags);
				pcpu->max_freq_idle_start_time = now;
				spin_unlock_irqrestore(&pcpu->target_freq_lock,
						       flags);
			}
		}
	}
	up_read(&pcpu->enable_sem);
}

static void cpufreq_interactive_idle_end(void)
{
@@ -1475,14 +1420,8 @@ static int cpufreq_interactive_idle_notifier(struct notifier_block *nb,
					     unsigned long val,
					     void *data)
{
	switch (val) {
	case IDLE_START:
		cpufreq_interactive_idle_start();
		break;
	case IDLE_END:
	if (val == IDLE_END)
		cpufreq_interactive_idle_end();
		break;
	}

	return 0;
}