cpufreq: Drop schedfreq governor
We all should be using (and improving) the schedutil governor now. Get rid of the non-upstream governor. Tested on Hikey. Change-Id: I2104558b03118b0a9c5f099c23c42cd9a6c2a963 Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
This commit is contained in:
@@ -102,14 +102,6 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
|
||||
governor. If unsure have a look at the help section of the
|
||||
driver. Fallback governor will be the performance governor.
|
||||
|
||||
config CPU_FREQ_DEFAULT_GOV_SCHED
|
||||
bool "sched"
|
||||
select CPU_FREQ_GOV_SCHED
|
||||
help
|
||||
Use the CPUfreq governor 'sched' as default. This scales
|
||||
cpu frequency using CPU utilization estimates from the
|
||||
scheduler.
|
||||
|
||||
config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
|
||||
bool "interactive"
|
||||
select CPU_FREQ_GOV_INTERACTIVE
|
||||
@@ -211,19 +203,6 @@ config CPU_FREQ_GOV_CONSERVATIVE
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config CPU_FREQ_GOV_SCHED
|
||||
bool "'sched' cpufreq governor"
|
||||
depends on CPU_FREQ
|
||||
depends on SMP
|
||||
select CPU_FREQ_GOV_COMMON
|
||||
help
|
||||
'sched' - this governor scales cpu frequency from the
|
||||
scheduler as a function of cpu capacity utilization. It does
|
||||
not evaluate utilization on a periodic basis (as ondemand
|
||||
does) but instead is event-driven by the scheduler.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config CPU_FREQ_GOV_INTERACTIVE
|
||||
tristate "'interactive' cpufreq policy governor"
|
||||
depends on CPU_FREQ
|
||||
|
||||
@@ -19,7 +19,6 @@ extern unsigned int sysctl_sched_min_granularity;
|
||||
extern unsigned int sysctl_sched_wakeup_granularity;
|
||||
extern unsigned int sysctl_sched_child_runs_first;
|
||||
extern unsigned int sysctl_sched_sync_hint_enable;
|
||||
extern unsigned int sysctl_sched_initial_task_util;
|
||||
extern unsigned int sysctl_sched_cstate_aware;
|
||||
#ifdef CONFIG_SCHED_WALT
|
||||
extern unsigned int sysctl_sched_use_walt_cpu_util;
|
||||
|
||||
@@ -26,5 +26,4 @@ obj-$(CONFIG_SCHED_DEBUG) += debug.o
|
||||
obj-$(CONFIG_SCHED_TUNE) += tune.o
|
||||
obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o
|
||||
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_SCHED) += cpufreq_sched.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o
|
||||
|
||||
@@ -3142,98 +3142,6 @@ unsigned long long task_sched_runtime(struct task_struct *p)
|
||||
return ns;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_GOV_SCHED
|
||||
|
||||
static inline
|
||||
unsigned long add_capacity_margin(unsigned long cpu_capacity)
|
||||
{
|
||||
cpu_capacity = cpu_capacity * capacity_margin;
|
||||
cpu_capacity /= SCHED_CAPACITY_SCALE;
|
||||
return cpu_capacity;
|
||||
}
|
||||
|
||||
static inline
|
||||
unsigned long sum_capacity_reqs(unsigned long cfs_cap,
|
||||
struct sched_capacity_reqs *scr)
|
||||
{
|
||||
unsigned long total = add_capacity_margin(cfs_cap + scr->rt);
|
||||
return total += scr->dl;
|
||||
}
|
||||
|
||||
unsigned long boosted_cpu_util(int cpu);
|
||||
static void sched_freq_tick_pelt(int cpu)
|
||||
{
|
||||
unsigned long cpu_utilization = boosted_cpu_util(cpu);
|
||||
unsigned long capacity_curr = capacity_curr_of(cpu);
|
||||
struct sched_capacity_reqs *scr;
|
||||
|
||||
scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
|
||||
if (sum_capacity_reqs(cpu_utilization, scr) < capacity_curr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* To make free room for a task that is building up its "real"
|
||||
* utilization and to harm its performance the least, request
|
||||
* a jump to a higher OPP as soon as the margin of free capacity
|
||||
* is impacted (specified by capacity_margin).
|
||||
* Remember CPU utilization in sched_capacity_reqs should be normalised.
|
||||
*/
|
||||
cpu_utilization = cpu_utilization * SCHED_CAPACITY_SCALE / capacity_orig_of(cpu);
|
||||
set_cfs_cpu_capacity(cpu, true, cpu_utilization);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_WALT
|
||||
static void sched_freq_tick_walt(int cpu)
|
||||
{
|
||||
unsigned long cpu_utilization = cpu_util(cpu);
|
||||
unsigned long capacity_curr = capacity_curr_of(cpu);
|
||||
|
||||
if (walt_disabled || !sysctl_sched_use_walt_cpu_util)
|
||||
return sched_freq_tick_pelt(cpu);
|
||||
|
||||
/*
|
||||
* Add a margin to the WALT utilization.
|
||||
* NOTE: WALT tracks a single CPU signal for all the scheduling
|
||||
* classes, thus this margin is going to be added to the DL class as
|
||||
* well, which is something we do not do in sched_freq_tick_pelt case.
|
||||
*/
|
||||
cpu_utilization = add_capacity_margin(cpu_utilization);
|
||||
if (cpu_utilization <= capacity_curr)
|
||||
return;
|
||||
|
||||
/*
|
||||
* It is likely that the load is growing so we
|
||||
* keep the added margin in our request as an
|
||||
* extra boost.
|
||||
* Remember CPU utilization in sched_capacity_reqs should be normalised.
|
||||
*/
|
||||
cpu_utilization = cpu_utilization * SCHED_CAPACITY_SCALE / capacity_orig_of(cpu);
|
||||
set_cfs_cpu_capacity(cpu, true, cpu_utilization);
|
||||
|
||||
}
|
||||
#define _sched_freq_tick(cpu) sched_freq_tick_walt(cpu)
|
||||
#else
|
||||
#define _sched_freq_tick(cpu) sched_freq_tick_pelt(cpu)
|
||||
#endif /* CONFIG_SCHED_WALT */
|
||||
|
||||
static void sched_freq_tick(int cpu)
|
||||
{
|
||||
unsigned long capacity_orig, capacity_curr;
|
||||
|
||||
if (!sched_freq())
|
||||
return;
|
||||
|
||||
capacity_orig = capacity_orig_of(cpu);
|
||||
capacity_curr = capacity_curr_of(cpu);
|
||||
if (capacity_curr == capacity_orig)
|
||||
return;
|
||||
|
||||
_sched_freq_tick(cpu);
|
||||
}
|
||||
#else
|
||||
static inline void sched_freq_tick(int cpu) { }
|
||||
#endif /* CONFIG_CPU_FREQ_GOV_SCHED */
|
||||
|
||||
/*
|
||||
* This function gets called by the timer code, with HZ frequency.
|
||||
* We call it with interrupts disabled.
|
||||
@@ -3254,7 +3162,6 @@ void scheduler_tick(void)
|
||||
walt_update_task_ravg(rq->curr, rq, TASK_UPDATE,
|
||||
walt_ktime_clock(), 0);
|
||||
calc_global_load_tick(rq);
|
||||
sched_freq_tick(cpu);
|
||||
raw_spin_unlock(&rq->lock);
|
||||
|
||||
perf_event_task_tick();
|
||||
|
||||
@@ -1,499 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Michael Turquette <mturquette@linaro.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/cpufreq_sched.h>
|
||||
|
||||
#include "sched.h"
|
||||
|
||||
#define THROTTLE_DOWN_NSEC 50000000 /* 50ms default */
|
||||
#define THROTTLE_UP_NSEC 500000 /* 500us default */
|
||||
|
||||
struct static_key __read_mostly __sched_freq = STATIC_KEY_INIT_FALSE;
|
||||
static bool __read_mostly cpufreq_driver_slow;
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
|
||||
static struct cpufreq_governor cpufreq_gov_sched;
|
||||
#endif
|
||||
|
||||
static DEFINE_PER_CPU(unsigned long, enabled);
|
||||
DEFINE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
|
||||
|
||||
struct gov_tunables {
|
||||
struct gov_attr_set attr_set;
|
||||
unsigned int up_throttle_nsec;
|
||||
unsigned int down_throttle_nsec;
|
||||
};
|
||||
|
||||
/**
|
||||
* gov_data - per-policy data internal to the governor
|
||||
* @up_throttle: next throttling period expiry if increasing OPP
|
||||
* @down_throttle: next throttling period expiry if decreasing OPP
|
||||
* @up_throttle_nsec: throttle period length in nanoseconds if increasing OPP
|
||||
* @down_throttle_nsec: throttle period length in nanoseconds if decreasing OPP
|
||||
* @task: worker thread for dvfs transition that may block/sleep
|
||||
* @irq_work: callback used to wake up worker thread
|
||||
* @requested_freq: last frequency requested by the sched governor
|
||||
*
|
||||
* struct gov_data is the per-policy cpufreq_sched-specific data structure. A
|
||||
* per-policy instance of it is created when the cpufreq_sched governor receives
|
||||
* the CPUFREQ_GOV_START condition and a pointer to it exists in the gov_data
|
||||
* member of struct cpufreq_policy.
|
||||
*
|
||||
* Readers of this data must call down_read(policy->rwsem). Writers must
|
||||
* call down_write(policy->rwsem).
|
||||
*/
|
||||
struct gov_data {
|
||||
ktime_t up_throttle;
|
||||
ktime_t down_throttle;
|
||||
struct gov_tunables *tunables;
|
||||
struct list_head tunables_hook;
|
||||
struct task_struct *task;
|
||||
struct irq_work irq_work;
|
||||
unsigned int requested_freq;
|
||||
};
|
||||
|
||||
static void cpufreq_sched_try_driver_target(struct cpufreq_policy *policy,
|
||||
unsigned int freq)
|
||||
{
|
||||
struct gov_data *gd = policy->governor_data;
|
||||
|
||||
/* avoid race with cpufreq_sched_stop */
|
||||
if (!down_write_trylock(&policy->rwsem))
|
||||
return;
|
||||
|
||||
__cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
|
||||
|
||||
gd->up_throttle = ktime_add_ns(ktime_get(),
|
||||
gd->tunables->up_throttle_nsec);
|
||||
gd->down_throttle = ktime_add_ns(ktime_get(),
|
||||
gd->tunables->down_throttle_nsec);
|
||||
up_write(&policy->rwsem);
|
||||
}
|
||||
|
||||
static bool finish_last_request(struct gov_data *gd, unsigned int cur_freq)
|
||||
{
|
||||
ktime_t now = ktime_get();
|
||||
|
||||
ktime_t throttle = gd->requested_freq < cur_freq ?
|
||||
gd->down_throttle : gd->up_throttle;
|
||||
|
||||
if (ktime_after(now, throttle))
|
||||
return false;
|
||||
|
||||
while (1) {
|
||||
int usec_left = ktime_to_ns(ktime_sub(throttle, now));
|
||||
|
||||
usec_left /= NSEC_PER_USEC;
|
||||
trace_cpufreq_sched_throttled(usec_left);
|
||||
usleep_range(usec_left, usec_left + 100);
|
||||
now = ktime_get();
|
||||
if (ktime_after(now, throttle))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* we pass in struct cpufreq_policy. This is safe because changing out the
|
||||
* policy requires a call to __cpufreq_governor(policy, CPUFREQ_GOV_STOP),
|
||||
* which tears down all of the data structures and __cpufreq_governor(policy,
|
||||
* CPUFREQ_GOV_START) will do a full rebuild, including this kthread with the
|
||||
* new policy pointer
|
||||
*/
|
||||
static int cpufreq_sched_thread(void *data)
|
||||
{
|
||||
struct sched_param param;
|
||||
struct cpufreq_policy *policy;
|
||||
struct gov_data *gd;
|
||||
unsigned int new_request = 0;
|
||||
unsigned int last_request = 0;
|
||||
int ret;
|
||||
|
||||
policy = (struct cpufreq_policy *) data;
|
||||
gd = policy->governor_data;
|
||||
|
||||
param.sched_priority = 50;
|
||||
ret = sched_setscheduler_nocheck(gd->task, SCHED_FIFO, ¶m);
|
||||
if (ret) {
|
||||
pr_warn("%s: failed to set SCHED_FIFO\n", __func__);
|
||||
do_exit(-EINVAL);
|
||||
} else {
|
||||
pr_debug("%s: kthread (%d) set to SCHED_FIFO\n",
|
||||
__func__, gd->task->pid);
|
||||
}
|
||||
|
||||
do {
|
||||
new_request = gd->requested_freq;
|
||||
if (new_request == last_request) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
schedule();
|
||||
} else {
|
||||
/*
|
||||
* if the frequency thread sleeps while waiting to be
|
||||
* unthrottled, start over to check for a newer request
|
||||
*/
|
||||
if (finish_last_request(gd, policy->cur))
|
||||
continue;
|
||||
last_request = new_request;
|
||||
cpufreq_sched_try_driver_target(policy, new_request);
|
||||
}
|
||||
} while (!kthread_should_stop());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpufreq_sched_irq_work(struct irq_work *irq_work)
|
||||
{
|
||||
struct gov_data *gd;
|
||||
|
||||
gd = container_of(irq_work, struct gov_data, irq_work);
|
||||
if (!gd)
|
||||
return;
|
||||
|
||||
wake_up_process(gd->task);
|
||||
}
|
||||
|
||||
static void update_fdomain_capacity_request(int cpu)
|
||||
{
|
||||
unsigned int freq_new, index_new, cpu_tmp;
|
||||
struct cpufreq_policy *policy;
|
||||
struct gov_data *gd;
|
||||
unsigned long capacity = 0;
|
||||
|
||||
/*
|
||||
* Avoid grabbing the policy if possible. A test is still
|
||||
* required after locking the CPU's policy to avoid racing
|
||||
* with the governor changing.
|
||||
*/
|
||||
if (!per_cpu(enabled, cpu))
|
||||
return;
|
||||
|
||||
policy = cpufreq_cpu_get(cpu);
|
||||
if (IS_ERR_OR_NULL(policy))
|
||||
return;
|
||||
|
||||
if (policy->governor != &cpufreq_gov_sched ||
|
||||
!policy->governor_data)
|
||||
goto out;
|
||||
|
||||
gd = policy->governor_data;
|
||||
|
||||
/* find max capacity requested by cpus in this policy */
|
||||
for_each_cpu(cpu_tmp, policy->cpus) {
|
||||
struct sched_capacity_reqs *scr;
|
||||
|
||||
scr = &per_cpu(cpu_sched_capacity_reqs, cpu_tmp);
|
||||
capacity = max(capacity, scr->total);
|
||||
}
|
||||
|
||||
/* Convert the new maximum capacity request into a cpu frequency */
|
||||
freq_new = capacity * policy->cpuinfo.max_freq >> SCHED_CAPACITY_SHIFT;
|
||||
index_new = cpufreq_frequency_table_target(policy, freq_new, CPUFREQ_RELATION_L);
|
||||
freq_new = policy->freq_table[index_new].frequency;
|
||||
|
||||
if (freq_new > policy->max)
|
||||
freq_new = policy->max;
|
||||
|
||||
if (freq_new < policy->min)
|
||||
freq_new = policy->min;
|
||||
|
||||
trace_cpufreq_sched_request_opp(cpu, capacity, freq_new,
|
||||
gd->requested_freq);
|
||||
if (freq_new == gd->requested_freq)
|
||||
goto out;
|
||||
|
||||
gd->requested_freq = freq_new;
|
||||
|
||||
/*
|
||||
* Throttling is not yet supported on platforms with fast cpufreq
|
||||
* drivers.
|
||||
*/
|
||||
if (cpufreq_driver_slow)
|
||||
irq_work_queue_on(&gd->irq_work, cpu);
|
||||
else
|
||||
cpufreq_sched_try_driver_target(policy, freq_new);
|
||||
|
||||
out:
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
void update_cpu_capacity_request(int cpu, bool request)
|
||||
{
|
||||
unsigned long new_capacity;
|
||||
struct sched_capacity_reqs *scr;
|
||||
|
||||
/* The rq lock serializes access to the CPU's sched_capacity_reqs. */
|
||||
lockdep_assert_held(&cpu_rq(cpu)->lock);
|
||||
|
||||
scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
|
||||
|
||||
new_capacity = scr->cfs + scr->rt;
|
||||
new_capacity = new_capacity * capacity_margin
|
||||
/ SCHED_CAPACITY_SCALE;
|
||||
new_capacity += scr->dl;
|
||||
|
||||
if (new_capacity == scr->total)
|
||||
return;
|
||||
|
||||
trace_cpufreq_sched_update_capacity(cpu, request, scr, new_capacity);
|
||||
|
||||
scr->total = new_capacity;
|
||||
if (request)
|
||||
update_fdomain_capacity_request(cpu);
|
||||
}
|
||||
|
||||
static inline void set_sched_freq(void)
|
||||
{
|
||||
static_key_slow_inc(&__sched_freq);
|
||||
}
|
||||
|
||||
static inline void clear_sched_freq(void)
|
||||
{
|
||||
static_key_slow_dec(&__sched_freq);
|
||||
}
|
||||
|
||||
/* Tunables */
|
||||
static struct gov_tunables *global_tunables;
|
||||
|
||||
static inline struct gov_tunables *to_tunables(struct gov_attr_set *attr_set)
|
||||
{
|
||||
return container_of(attr_set, struct gov_tunables, attr_set);
|
||||
}
|
||||
|
||||
static ssize_t up_throttle_nsec_show(struct gov_attr_set *attr_set, char *buf)
|
||||
{
|
||||
struct gov_tunables *tunables = to_tunables(attr_set);
|
||||
|
||||
return sprintf(buf, "%u\n", tunables->up_throttle_nsec);
|
||||
}
|
||||
|
||||
static ssize_t up_throttle_nsec_store(struct gov_attr_set *attr_set,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct gov_tunables *tunables = to_tunables(attr_set);
|
||||
int ret;
|
||||
long unsigned int val;
|
||||
|
||||
ret = kstrtoul(buf, 0, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tunables->up_throttle_nsec = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t down_throttle_nsec_show(struct gov_attr_set *attr_set, char *buf)
|
||||
{
|
||||
struct gov_tunables *tunables = to_tunables(attr_set);
|
||||
|
||||
return sprintf(buf, "%u\n", tunables->down_throttle_nsec);
|
||||
}
|
||||
|
||||
static ssize_t down_throttle_nsec_store(struct gov_attr_set *attr_set,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct gov_tunables *tunables = to_tunables(attr_set);
|
||||
int ret;
|
||||
long unsigned int val;
|
||||
|
||||
ret = kstrtoul(buf, 0, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
tunables->down_throttle_nsec = val;
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct governor_attr up_throttle_nsec = __ATTR_RW(up_throttle_nsec);
|
||||
static struct governor_attr down_throttle_nsec = __ATTR_RW(down_throttle_nsec);
|
||||
|
||||
static struct attribute *schedfreq_attributes[] = {
|
||||
&up_throttle_nsec.attr,
|
||||
&down_throttle_nsec.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct kobj_type tunables_ktype = {
|
||||
.default_attrs = schedfreq_attributes,
|
||||
.sysfs_ops = &governor_sysfs_ops,
|
||||
};
|
||||
|
||||
static int cpufreq_sched_policy_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct gov_data *gd;
|
||||
int cpu;
|
||||
int rc;
|
||||
|
||||
for_each_cpu(cpu, policy->cpus)
|
||||
memset(&per_cpu(cpu_sched_capacity_reqs, cpu), 0,
|
||||
sizeof(struct sched_capacity_reqs));
|
||||
|
||||
gd = kzalloc(sizeof(*gd), GFP_KERNEL);
|
||||
if (!gd)
|
||||
return -ENOMEM;
|
||||
|
||||
policy->governor_data = gd;
|
||||
|
||||
if (!global_tunables) {
|
||||
gd->tunables = kzalloc(sizeof(*gd->tunables), GFP_KERNEL);
|
||||
if (!gd->tunables)
|
||||
goto free_gd;
|
||||
|
||||
gd->tunables->up_throttle_nsec =
|
||||
policy->cpuinfo.transition_latency ?
|
||||
policy->cpuinfo.transition_latency :
|
||||
THROTTLE_UP_NSEC;
|
||||
gd->tunables->down_throttle_nsec =
|
||||
THROTTLE_DOWN_NSEC;
|
||||
|
||||
rc = kobject_init_and_add(&gd->tunables->attr_set.kobj,
|
||||
&tunables_ktype,
|
||||
get_governor_parent_kobj(policy),
|
||||
"%s", cpufreq_gov_sched.name);
|
||||
if (rc)
|
||||
goto free_tunables;
|
||||
|
||||
gov_attr_set_init(&gd->tunables->attr_set,
|
||||
&gd->tunables_hook);
|
||||
|
||||
pr_debug("%s: throttle_threshold = %u [ns]\n",
|
||||
__func__, gd->tunables->up_throttle_nsec);
|
||||
|
||||
if (!have_governor_per_policy())
|
||||
global_tunables = gd->tunables;
|
||||
} else {
|
||||
gd->tunables = global_tunables;
|
||||
gov_attr_set_get(&global_tunables->attr_set,
|
||||
&gd->tunables_hook);
|
||||
}
|
||||
|
||||
policy->governor_data = gd;
|
||||
if (cpufreq_driver_is_slow()) {
|
||||
cpufreq_driver_slow = true;
|
||||
gd->task = kthread_create(cpufreq_sched_thread, policy,
|
||||
"kschedfreq:%d",
|
||||
cpumask_first(policy->related_cpus));
|
||||
if (IS_ERR_OR_NULL(gd->task)) {
|
||||
pr_err("%s: failed to create kschedfreq thread\n",
|
||||
__func__);
|
||||
goto free_tunables;
|
||||
}
|
||||
get_task_struct(gd->task);
|
||||
kthread_bind_mask(gd->task, policy->related_cpus);
|
||||
wake_up_process(gd->task);
|
||||
init_irq_work(&gd->irq_work, cpufreq_sched_irq_work);
|
||||
}
|
||||
|
||||
set_sched_freq();
|
||||
|
||||
return 0;
|
||||
|
||||
free_tunables:
|
||||
kfree(gd->tunables);
|
||||
free_gd:
|
||||
policy->governor_data = NULL;
|
||||
kfree(gd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void cpufreq_sched_policy_exit(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int count;
|
||||
struct gov_data *gd = policy->governor_data;
|
||||
|
||||
clear_sched_freq();
|
||||
if (cpufreq_driver_slow) {
|
||||
kthread_stop(gd->task);
|
||||
put_task_struct(gd->task);
|
||||
}
|
||||
|
||||
count = gov_attr_set_put(&gd->tunables->attr_set, &gd->tunables_hook);
|
||||
if (!count) {
|
||||
if (!have_governor_per_policy())
|
||||
global_tunables = NULL;
|
||||
kfree(gd->tunables);
|
||||
}
|
||||
|
||||
policy->governor_data = NULL;
|
||||
|
||||
kfree(gd);
|
||||
}
|
||||
|
||||
static int cpufreq_sched_start(struct cpufreq_policy *policy)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu(cpu, policy->cpus)
|
||||
per_cpu(enabled, cpu) = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpufreq_sched_limits(struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int clamp_freq;
|
||||
struct gov_data *gd = policy->governor_data;;
|
||||
|
||||
pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz\n",
|
||||
policy->cpu, policy->min, policy->max,
|
||||
policy->cur);
|
||||
|
||||
clamp_freq = clamp(gd->requested_freq, policy->min, policy->max);
|
||||
|
||||
if (policy->cur != clamp_freq)
|
||||
__cpufreq_driver_target(policy, clamp_freq, CPUFREQ_RELATION_L);
|
||||
}
|
||||
|
||||
static void cpufreq_sched_stop(struct cpufreq_policy *policy)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu(cpu, policy->cpus)
|
||||
per_cpu(enabled, cpu) = 0;
|
||||
}
|
||||
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
|
||||
static
|
||||
#endif
|
||||
struct cpufreq_governor cpufreq_gov_sched = {
|
||||
.name = "sched",
|
||||
.init = cpufreq_sched_policy_init,
|
||||
.exit = cpufreq_sched_policy_exit,
|
||||
.start = cpufreq_sched_start,
|
||||
.stop = cpufreq_sched_stop,
|
||||
.limits = cpufreq_sched_limits,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init cpufreq_sched_init(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu(cpu, cpu_possible_mask)
|
||||
per_cpu(enabled, cpu) = 0;
|
||||
return cpufreq_register_governor(&cpufreq_gov_sched);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SCHED
|
||||
struct cpufreq_governor *cpufreq_default_governor(void)
|
||||
{
|
||||
return &cpufreq_gov_sched;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Try to make this the default governor */
|
||||
fs_initcall(cpufreq_sched_init);
|
||||
+2
-85
@@ -54,7 +54,6 @@ unsigned int sysctl_sched_latency = 6000000ULL;
|
||||
unsigned int normalized_sysctl_sched_latency = 6000000ULL;
|
||||
|
||||
unsigned int sysctl_sched_sync_hint_enable = 1;
|
||||
unsigned int sysctl_sched_initial_task_util = 0;
|
||||
unsigned int sysctl_sched_cstate_aware = 1;
|
||||
|
||||
#ifdef CONFIG_SCHED_WALT
|
||||
@@ -756,9 +755,7 @@ void init_entity_runnable_average(struct sched_entity *se)
|
||||
/*
|
||||
* At this point, util_avg won't be used in select_task_rq_fair anyway
|
||||
*/
|
||||
sa->util_avg = sched_freq() ?
|
||||
sysctl_sched_initial_task_util :
|
||||
0;
|
||||
sa->util_avg = 0;
|
||||
sa->util_sum = 0;
|
||||
/* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */
|
||||
}
|
||||
@@ -4795,21 +4792,6 @@ unsigned long boosted_cpu_util(int cpu);
|
||||
#define boosted_cpu_util(cpu) cpu_util(cpu)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static void update_capacity_of(int cpu)
|
||||
{
|
||||
unsigned long req_cap;
|
||||
|
||||
if (!sched_freq())
|
||||
return;
|
||||
|
||||
/* Normalize scale-invariant capacity to cpu. */
|
||||
req_cap = boosted_cpu_util(cpu);
|
||||
req_cap = req_cap * SCHED_CAPACITY_SCALE / capacity_orig_of(cpu);
|
||||
set_cfs_cpu_capacity(cpu, true, req_cap);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The enqueue_task method is called before nr_running is
|
||||
* increased. Here we update the fair scheduling stats and
|
||||
@@ -4822,7 +4804,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
|
||||
struct sched_entity *se = &p->se;
|
||||
#ifdef CONFIG_SMP
|
||||
int task_new = flags & ENQUEUE_WAKEUP_NEW;
|
||||
int task_wakeup = flags & ENQUEUE_WAKEUP;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -4896,16 +4877,6 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
|
||||
rq->rd->overutilized = true;
|
||||
trace_sched_overutilized(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to potentially trigger a freq switch
|
||||
* request only for tasks that are waking up; this is
|
||||
* because we get here also during load balancing, but
|
||||
* in these cases it seems wise to trigger as single
|
||||
* request after load balancing is done.
|
||||
*/
|
||||
if (task_new || task_wakeup)
|
||||
update_capacity_of(cpu_of(rq));
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
@@ -4981,25 +4952,8 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
|
||||
*/
|
||||
schedtune_dequeue_task(p, cpu_of(rq));
|
||||
|
||||
if (!se) {
|
||||
if (!se)
|
||||
walt_dec_cumulative_runnable_avg(rq, p);
|
||||
|
||||
/*
|
||||
* We want to potentially trigger a freq switch
|
||||
* request only for tasks that are going to sleep;
|
||||
* this is because we get here also during load
|
||||
* balancing, but in these cases it seems wise to
|
||||
* trigger as single request after load balancing is
|
||||
* done.
|
||||
*/
|
||||
if (task_sleep) {
|
||||
if (rq->cfs.nr_running)
|
||||
update_capacity_of(cpu_of(rq));
|
||||
else if (sched_freq())
|
||||
set_cfs_cpu_capacity(cpu_of(rq), false, 0); /* no normalization required for 0 */
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
hrtick_update(rq);
|
||||
@@ -8107,10 +8061,6 @@ static void attach_one_task(struct rq *rq, struct task_struct *p)
|
||||
{
|
||||
raw_spin_lock(&rq->lock);
|
||||
attach_task(rq, p);
|
||||
/*
|
||||
* We want to potentially raise target_cpu's OPP.
|
||||
*/
|
||||
update_capacity_of(cpu_of(rq));
|
||||
raw_spin_unlock(&rq->lock);
|
||||
}
|
||||
|
||||
@@ -8132,11 +8082,6 @@ static void attach_tasks(struct lb_env *env)
|
||||
attach_task(env->dst_rq, p);
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to potentially raise env.dst_cpu's OPP.
|
||||
*/
|
||||
update_capacity_of(env->dst_cpu);
|
||||
|
||||
raw_spin_unlock(&env->dst_rq->lock);
|
||||
}
|
||||
|
||||
@@ -9468,11 +9413,6 @@ more_balance:
|
||||
* ld_moved - cumulative load moved across iterations
|
||||
*/
|
||||
cur_ld_moved = detach_tasks(&env);
|
||||
/*
|
||||
* We want to potentially lower env.src_cpu's OPP.
|
||||
*/
|
||||
if (cur_ld_moved)
|
||||
update_capacity_of(env.src_cpu);
|
||||
|
||||
/*
|
||||
* We've detached some tasks from busiest_rq. Every
|
||||
@@ -9695,7 +9635,6 @@ static int idle_balance(struct rq *this_rq)
|
||||
struct sched_domain *sd;
|
||||
int pulled_task = 0;
|
||||
u64 curr_cost = 0;
|
||||
long removed_util=0;
|
||||
|
||||
/*
|
||||
* We must set idle_stamp _before_ calling idle_balance(), such that we
|
||||
@@ -9717,17 +9656,6 @@ static int idle_balance(struct rq *this_rq)
|
||||
|
||||
raw_spin_unlock(&this_rq->lock);
|
||||
|
||||
/*
|
||||
* If removed_util_avg is !0 we most probably migrated some task away
|
||||
* from this_cpu. In this case we might be willing to trigger an OPP
|
||||
* update, but we want to do so if we don't find anybody else to pull
|
||||
* here (we will trigger an OPP update with the pulled task's enqueue
|
||||
* anyway).
|
||||
*
|
||||
* Record removed_util before calling update_blocked_averages, and use
|
||||
* it below (before returning) to see if an OPP update is required.
|
||||
*/
|
||||
removed_util = atomic_long_read(&(this_rq->cfs).removed_util_avg);
|
||||
update_blocked_averages(this_cpu);
|
||||
rcu_read_lock();
|
||||
for_each_domain(this_cpu, sd) {
|
||||
@@ -9791,13 +9719,6 @@ out:
|
||||
|
||||
if (pulled_task)
|
||||
this_rq->idle_stamp = 0;
|
||||
else if (removed_util) {
|
||||
/*
|
||||
* No task pulled and someone has been migrated away.
|
||||
* Good case to trigger an OPP update.
|
||||
*/
|
||||
update_capacity_of(this_cpu);
|
||||
}
|
||||
|
||||
return pulled_task;
|
||||
}
|
||||
@@ -9859,10 +9780,6 @@ static int active_load_balance_cpu_stop(void *data)
|
||||
p = detach_one_task(&env);
|
||||
if (p) {
|
||||
schedstat_inc(sd->alb_pushed);
|
||||
/*
|
||||
* We want to potentially lower env.src_cpu's OPP.
|
||||
*/
|
||||
update_capacity_of(env.src_cpu);
|
||||
/* Active balancing done, reset the failure counter. */
|
||||
sd->nr_balance_failed = 0;
|
||||
} else {
|
||||
|
||||
@@ -1657,81 +1657,6 @@ static inline unsigned long cpu_util(int cpu)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_GOV_SCHED
|
||||
#define capacity_max SCHED_CAPACITY_SCALE
|
||||
extern unsigned int capacity_margin;
|
||||
extern struct static_key __sched_freq;
|
||||
|
||||
static inline bool sched_freq(void)
|
||||
{
|
||||
return static_key_false(&__sched_freq);
|
||||
}
|
||||
|
||||
/*
|
||||
* sched_capacity_reqs expects capacity requests to be normalised.
|
||||
* All capacities should sum to the range of 0-1024.
|
||||
*/
|
||||
DECLARE_PER_CPU(struct sched_capacity_reqs, cpu_sched_capacity_reqs);
|
||||
void update_cpu_capacity_request(int cpu, bool request);
|
||||
|
||||
static inline void set_cfs_cpu_capacity(int cpu, bool request,
|
||||
unsigned long capacity)
|
||||
{
|
||||
struct sched_capacity_reqs *scr = &per_cpu(cpu_sched_capacity_reqs, cpu);
|
||||
|
||||
#ifdef CONFIG_SCHED_WALT
|
||||
if (!walt_disabled && sysctl_sched_use_walt_cpu_util) {
|
||||
int rtdl = scr->rt + scr->dl;
|
||||
/*
|
||||
* WALT tracks the utilization of a CPU considering the load
|
||||
* generated by all the scheduling classes.
|
||||
* Since the following call to:
|
||||
* update_cpu_capacity
|
||||
* is already adding the RT and DL utilizations let's remove
|
||||
* these contributions from the WALT signal.
|
||||
*/
|
||||
if (capacity > rtdl)
|
||||
capacity -= rtdl;
|
||||
else
|
||||
capacity = 0;
|
||||
}
|
||||
#endif
|
||||
if (scr->cfs != capacity) {
|
||||
scr->cfs = capacity;
|
||||
update_cpu_capacity_request(cpu, request);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_rt_cpu_capacity(int cpu, bool request,
|
||||
unsigned long capacity)
|
||||
{
|
||||
if (per_cpu(cpu_sched_capacity_reqs, cpu).rt != capacity) {
|
||||
per_cpu(cpu_sched_capacity_reqs, cpu).rt = capacity;
|
||||
update_cpu_capacity_request(cpu, request);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void set_dl_cpu_capacity(int cpu, bool request,
|
||||
unsigned long capacity)
|
||||
{
|
||||
if (per_cpu(cpu_sched_capacity_reqs, cpu).dl != capacity) {
|
||||
per_cpu(cpu_sched_capacity_reqs, cpu).dl = capacity;
|
||||
update_cpu_capacity_request(cpu, request);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static inline bool sched_freq(void) { return false; }
|
||||
static inline void set_cfs_cpu_capacity(int cpu, bool request,
|
||||
unsigned long capacity)
|
||||
{ }
|
||||
static inline void set_rt_cpu_capacity(int cpu, bool request,
|
||||
unsigned long capacity)
|
||||
{ }
|
||||
static inline void set_dl_cpu_capacity(int cpu, bool request,
|
||||
unsigned long capacity)
|
||||
{ }
|
||||
#endif
|
||||
|
||||
static inline void sched_rt_avg_update(struct rq *rq, u64 rt_delta)
|
||||
{
|
||||
rq->rt_avg += rt_delta * arch_scale_freq_capacity(NULL, cpu_of(rq));
|
||||
|
||||
@@ -344,13 +344,6 @@ static struct ctl_table kern_table[] = {
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.procname = "sched_initial_task_util",
|
||||
.data = &sysctl_sched_initial_task_util,
|
||||
.maxlen = sizeof(unsigned int),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
{
|
||||
.procname = "sched_cstate_aware",
|
||||
.data = &sysctl_sched_cstate_aware,
|
||||
|
||||
Reference in New Issue
Block a user