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

Commit b2328868 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cpufreq: interactive: Compute target freq independent of policy min/max"

parents c0534bae dba8cf26
Loading
Loading
Loading
Loading
+47 −41
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ struct cpufreq_interactive_policyinfo {
	spinlock_t load_lock; /* protects load tracking stat */
	u64 last_evaluated_jiffy;
	struct cpufreq_policy *policy;
	struct cpufreq_policy p_nolim; /* policy copy with no limits */
	struct cpufreq_frequency_table *freq_table;
	spinlock_t target_freq_lock; /*protects target freq */
	unsigned int target_freq;
@@ -339,7 +340,7 @@ static unsigned int choose_freq(struct cpufreq_interactive_policyinfo *pcpu,
		 */

		if (cpufreq_frequency_table_target(
			    pcpu->policy, pcpu->freq_table, loadadjfreq / tl,
			    &pcpu->p_nolim, pcpu->freq_table, loadadjfreq / tl,
			    CPUFREQ_RELATION_L, &index))
			break;
		freq = pcpu->freq_table[index].frequency;
@@ -354,7 +355,7 @@ static unsigned int choose_freq(struct cpufreq_interactive_policyinfo *pcpu,
				 * than freqmax.
				 */
				if (cpufreq_frequency_table_target(
					    pcpu->policy, pcpu->freq_table,
					    &pcpu->p_nolim, pcpu->freq_table,
					    freqmax - 1, CPUFREQ_RELATION_H,
					    &index))
					break;
@@ -381,7 +382,7 @@ static unsigned int choose_freq(struct cpufreq_interactive_policyinfo *pcpu,
				 * than freqmin.
				 */
				if (cpufreq_frequency_table_target(
					    pcpu->policy, pcpu->freq_table,
					    &pcpu->p_nolim, pcpu->freq_table,
					    freqmin + 1, CPUFREQ_RELATION_L,
					    &index))
					break;
@@ -431,6 +432,7 @@ static u64 update_load(int cpu)
	return now;
}

#define NEW_TASK_RATIO 75
static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
{
	u64 now;
@@ -448,9 +450,11 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
	unsigned long max_cpu;
	int i, fcpu;
	struct sched_load *sl;
	int new_load_pct = 0;
	struct cpufreq_govinfo govinfo;
	bool skip_hispeed_logic, skip_min_sample_time;
	bool policy_max_fast_restore = false;
	bool jump_to_max = false;

	if (!down_read_trylock(&ppol->enable_sem))
		return;
@@ -458,8 +462,12 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
		goto exit;

	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());
	spin_lock_irqsave(&ppol->load_lock, flags);
	spin_lock_irqsave(&ppol->target_freq_lock, flags);
	spin_lock(&ppol->load_lock);
	ppol->last_evaluated_jiffy = get_jiffies_64();

	if (tunables->use_sched_load)
@@ -472,6 +480,7 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
			cputime_speedadj = (u64)sl->prev_load *
					   ppol->policy->cpuinfo.max_freq;
			do_div(cputime_speedadj, tunables->timer_rate);
			new_load_pct = sl->new_task_load * 100 / sl->prev_load;
		} else {
			now = update_load(i);
			delta_time = (unsigned int)
@@ -483,38 +492,25 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
		}
		tmploadadjfreq = (unsigned int)cputime_speedadj * 100;
		pcpu->loadadjfreq = tmploadadjfreq;
		trace_cpufreq_interactive_cpuload(i, tmploadadjfreq /
						  ppol->target_freq);

		if (tmploadadjfreq > loadadjfreq) {
			loadadjfreq = tmploadadjfreq;
			max_cpu = i;
		}
	}
	spin_unlock_irqrestore(&ppol->load_lock, flags);
		cpu_load = tmploadadjfreq / ppol->target_freq;
		trace_cpufreq_interactive_cpuload(i, cpu_load, new_load_pct);

	/*
	 * Send govinfo notification.
	 * Govinfo notification could potentially wake up another thread
	 * managed by its clients. Thread wakeups might trigger a load
	 * change callback that executes this function again. Therefore
	 * no spinlock could be held when sending the notification.
	 */
	for_each_cpu(i, ppol->policy->cpus) {
		pcpu = &per_cpu(cpuinfo, i);
		govinfo.cpu = i;
		govinfo.load = pcpu->loadadjfreq / ppol->policy->max;
		govinfo.sampling_rate_us = tunables->timer_rate;
		atomic_notifier_call_chain(&cpufreq_govinfo_notifier_list,
					   CPUFREQ_LOAD_CHANGE, &govinfo);
		if (cpu_load >= tunables->go_hispeed_load &&
		    new_load_pct >= NEW_TASK_RATIO) {
			skip_hispeed_logic = true;
			jump_to_max = true;
		}
	}
	spin_unlock(&ppol->load_lock);

	spin_lock_irqsave(&ppol->target_freq_lock, flags);
	cpu_load = loadadjfreq / ppol->target_freq;
	tunables->boosted = tunables->boost_val || now < tunables->boostpulse_endtime;

	skip_hispeed_logic = tunables->ignore_hispeed_on_notif && is_notif;
	skip_min_sample_time = tunables->fast_ramp_down && is_notif;
	if (now - ppol->max_freq_hyst_start_time <
	    tunables->max_freq_hysteresis &&
	    cpu_load >= tunables->go_hispeed_load &&
@@ -524,8 +520,8 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
		policy_max_fast_restore = true;
	}

	if (policy_max_fast_restore) {
		new_freq = ppol->policy->max;
	if (policy_max_fast_restore || jump_to_max) {
		new_freq = ppol->policy->cpuinfo.max_freq;
	} else if (skip_hispeed_logic) {
		new_freq = choose_freq(ppol, loadadjfreq);
	} else if (cpu_load >= tunables->go_hispeed_load || tunables->boosted) {
@@ -562,7 +558,7 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)

	ppol->hispeed_validate_time = now;

	if (cpufreq_frequency_table_target(ppol->policy, ppol->freq_table,
	if (cpufreq_frequency_table_target(&ppol->p_nolim, ppol->freq_table,
					   new_freq, CPUFREQ_RELATION_L,
					   &index)) {
		spin_unlock_irqrestore(&ppol->target_freq_lock, flags);
@@ -603,7 +599,7 @@ static void __cpufreq_interactive_timer(unsigned long data, bool is_notif)
		ppol->floor_validate_time = now;
	}

	if (new_freq == ppol->policy->max && !policy_max_fast_restore)
	if (new_freq >= ppol->policy->max && !policy_max_fast_restore)
		ppol->max_freq_hyst_start_time = now;

	if (ppol->target_freq == new_freq &&
@@ -629,6 +625,22 @@ rearm:
	if (!timer_pending(&ppol->policy_timer))
		cpufreq_interactive_timer_resched(data, false);

	/*
	 * Send govinfo notification.
	 * Govinfo notification could potentially wake up another thread
	 * managed by its clients. Thread wakeups might trigger a load
	 * change callback that executes this function again. Therefore
	 * no spinlock could be held when sending the notification.
	 */
	for_each_cpu(i, ppol->policy->cpus) {
		pcpu = &per_cpu(cpuinfo, i);
		govinfo.cpu = i;
		govinfo.load = pcpu->loadadjfreq / ppol->policy->max;
		govinfo.sampling_rate_us = tunables->timer_rate;
		atomic_notifier_call_chain(&cpufreq_govinfo_notifier_list,
					   CPUFREQ_LOAD_CHANGE, &govinfo);
	}

exit:
	up_read(&ppol->enable_sem);
	return;
@@ -1568,7 +1580,6 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
	struct cpufreq_interactive_policyinfo *ppol;
	struct cpufreq_frequency_table *freq_table;
	struct cpufreq_interactive_tunables *tunables;
	unsigned long flags;

	if (have_governor_per_policy())
		tunables = policy->governor_data;
@@ -1673,6 +1684,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
		ppol->policy = policy;
		ppol->target_freq = policy->cur;
		ppol->freq_table = freq_table;
		ppol->p_nolim = *policy;
		ppol->p_nolim.min = policy->cpuinfo.min_freq;
		ppol->p_nolim.max = policy->cpuinfo.max_freq;
		ppol->floor_freq = ppol->target_freq;
		ppol->floor_validate_time = ktime_to_us(ktime_get());
		ppol->hispeed_validate_time = ppol->floor_validate_time;
@@ -1708,26 +1722,18 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
		break;

	case CPUFREQ_GOV_LIMITS:
		__cpufreq_driver_target(policy,
				policy->cur, CPUFREQ_RELATION_L);

		ppol = per_cpu(polinfo, policy->cpu);

		__cpufreq_driver_target(policy,
				ppol->target_freq, CPUFREQ_RELATION_L);

		down_read(&ppol->enable_sem);
		if (ppol->governor_enabled) {
			spin_lock_irqsave(&ppol->target_freq_lock, flags);
			if (policy->max < ppol->target_freq)
				ppol->target_freq = policy->max;
			else if (policy->min > ppol->target_freq)
				ppol->target_freq = policy->min;
			spin_unlock_irqrestore(&ppol->target_freq_lock, flags);

			if (policy->min < ppol->min_freq)
				cpufreq_interactive_timer_resched(policy->cpu,
								  true);
			ppol->min_freq = policy->min;
		}

		up_read(&ppol->enable_sem);

		break;
+7 −3
Original line number Diff line number Diff line
@@ -119,17 +119,21 @@ TRACE_EVENT(cpufreq_interactive_load_change,
);

TRACE_EVENT(cpufreq_interactive_cpuload,
	    TP_PROTO(unsigned long cpu_id, unsigned long load),
	    TP_ARGS(cpu_id, load),
	    TP_PROTO(unsigned long cpu_id, unsigned long load,
		     unsigned int new_task_pct),
	    TP_ARGS(cpu_id, load, new_task_pct),
	    TP_STRUCT__entry(
		__field(unsigned long, cpu_id)
		__field(unsigned long, load)
		__field(unsigned long, new_task_pct)
	    ),
	    TP_fast_assign(
		__entry->cpu_id = cpu_id;
		__entry->load = load;
		__entry->new_task_pct = new_task_pct;
	    ),
	    TP_printk("cpu=%lu load=%lu", __entry->cpu_id, __entry->load)
	    TP_printk("cpu=%lu load=%lu new_task_pct=%lu", __entry->cpu_id,
		      __entry->load, __entry->new_task_pct)
);

#endif /* _TRACE_CPUFREQ_INTERACTIVE_H */