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

Commit 345ef1c3 authored by Junjie Wu's avatar Junjie Wu
Browse files

cpufreq: interactive: Add max_freq_hysteresis feature



Previously known as sampling down factor, max_freq_hysteresis
extends the period that interactive governor will stay at policy->max.
This feature is to accomodate short idle periods in an otherwise very
intensive workload.

When the feature is enabled, it ensures that once a CPU goes to max
frequency, it doesn't reduce the frequency for max_freq_hysteresis
microseconds from the time it first goes to idle.

Change-Id: Ia54985cb554f63f8c22d0b554a0a0f2ed2be038f
Signed-off-by: default avatarJunjie Wu <junjiew@codeaurora.org>
parent 3511ae2a
Loading
Loading
Loading
Loading
+60 −1
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ struct cpufreq_interactive_cpuinfo {
	unsigned int max_freq;
	u64 floor_validate_time;
	u64 hispeed_validate_time;
	u64 max_freq_idle_start_time;
	struct rw_semaphore enable_sem;
	int governor_enabled;
	struct cpufreq_interactive_tunables *cached_tunables;
@@ -125,6 +126,12 @@ struct cpufreq_interactive_tunables {
	/* scheduler input related flags */
	bool use_sched_load;
	bool use_migration_notif;

	/*
	 * Stay at max freq for at least max_freq_hysteresis before dropping
	 * frequency.
	 */
	unsigned int max_freq_hysteresis;
};

/* For cases where we have single governor instance for system */
@@ -476,6 +483,16 @@ 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 <
	    tunables->max_freq_hysteresis) {
		trace_cpufreq_interactive_notyet(data, cpu_load,
			pcpu->target_freq, pcpu->policy->cur, new_freq);
		spin_unlock_irqrestore(&pcpu->target_freq_lock, flags);
		goto rearm;
	}

	/*
	 * Do not scale below floor_freq unless we have been at or above the
	 * floor frequency for the minimum sample time since last validated.
@@ -544,6 +561,9 @@ 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;
@@ -566,9 +586,23 @@ static void cpufreq_interactive_idle_start(void)
		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);
}

@@ -912,6 +946,27 @@ static ssize_t store_hispeed_freq(struct cpufreq_interactive_tunables *tunables,
	return count;
}

#define show_store_one(file_name)					\
static ssize_t show_##file_name(					\
	struct cpufreq_interactive_tunables *tunables, char *buf)	\
{									\
	return snprintf(buf, PAGE_SIZE, "%u\n", tunables->file_name);	\
}									\
static ssize_t store_##file_name(					\
		struct cpufreq_interactive_tunables *tunables,		\
		const char *buf, size_t count)				\
{									\
	int ret;							\
	long unsigned int val;						\
									\
	ret = kstrtoul(buf, 0, &val);				\
	if (ret < 0)							\
		return ret;						\
	tunables->file_name = val;					\
	return count;							\
}
show_store_one(max_freq_hysteresis);

static ssize_t show_go_hispeed_load(struct cpufreq_interactive_tunables
		*tunables, char *buf)
{
@@ -1290,6 +1345,7 @@ show_store_gov_pol_sys(boostpulse_duration);
show_store_gov_pol_sys(io_is_busy);
show_store_gov_pol_sys(use_sched_load);
show_store_gov_pol_sys(use_migration_notif);
show_store_gov_pol_sys(max_freq_hysteresis);

#define gov_sys_attr_rw(_name)						\
static struct global_attr _name##_gov_sys =				\
@@ -1315,6 +1371,7 @@ gov_sys_pol_attr_rw(boostpulse_duration);
gov_sys_pol_attr_rw(io_is_busy);
gov_sys_pol_attr_rw(use_sched_load);
gov_sys_pol_attr_rw(use_migration_notif);
gov_sys_pol_attr_rw(max_freq_hysteresis);

static struct global_attr boostpulse_gov_sys =
	__ATTR(boostpulse, 0200, NULL, store_boostpulse_gov_sys);
@@ -1337,6 +1394,7 @@ static struct attribute *interactive_attributes_gov_sys[] = {
	&io_is_busy_gov_sys.attr,
	&use_sched_load_gov_sys.attr,
	&use_migration_notif_gov_sys.attr,
	&max_freq_hysteresis_gov_sys.attr,
	NULL,
};

@@ -1360,6 +1418,7 @@ static struct attribute *interactive_attributes_gov_pol[] = {
	&io_is_busy_gov_pol.attr,
	&use_sched_load_gov_pol.attr,
	&use_migration_notif_gov_pol.attr,
	&max_freq_hysteresis_gov_pol.attr,
	NULL,
};