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 accommodate 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
[junjiew@codeaurora.org: Resolved conflicts. Dropped changes to code
that no longer exists. Trivial checkpatch fix. Renamed
max_freq_idle_start_time to max_freq_hyst_start_time.]
Signed-off-by: Junjie Wu <junjiew@codeaurora.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 530a9fb..638fef4 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -52,6 +52,7 @@
u64 loc_floor_val_time; /* per-cpu floor_validate_time */
u64 pol_hispeed_val_time; /* policy hispeed_validate_time */
u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
+ u64 max_freq_hyst_start_time;
struct rw_semaphore enable_sem;
int governor_enabled;
struct cpufreq_interactive_tunables *cached_tunables;
@@ -125,6 +126,12 @@
/* 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;
};
/*
@@ -501,6 +508,16 @@
new_freq = pcpu->freq_table[index].frequency;
+ if (pcpu->target_freq >= pcpu->policy->max
+ && 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);
+ 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.
@@ -909,6 +926,27 @@
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; \
+ unsigned long 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)
{
@@ -1289,6 +1327,7 @@
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 = \
@@ -1314,6 +1353,7 @@
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);
@@ -1336,6 +1376,7 @@
&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,
};
@@ -1359,6 +1400,7 @@
&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,
};