Currently boost policy is set to SCHED_BOOST_ON_BIG when min_possible_efficiency != max_possible_efficiency. This does not work for a SMP system on which some CPUs have slightly higher efficiency (for example higher cache size) but otherwise identical to other clusters. For such systems, spreading the tasks gives better performance under boost. Change-Id: Ie59388cb00e2ff9777c5b89903b38015cba23b23 Signed-off-by: Pavankumar Kondeti <pkondeti@codeaurora.org>
218 lines
4.9 KiB
C
218 lines
4.9 KiB
C
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "sched.h"
|
|
#include <linux/of.h>
|
|
#include <linux/sched/core_ctl.h>
|
|
#include <trace/events/sched.h>
|
|
|
|
/*
|
|
* Scheduler boost is a mechanism to temporarily place tasks on CPUs
|
|
* with higher capacity than those where a task would have normally
|
|
* ended up with their load characteristics. Any entity enabling
|
|
* boost is responsible for disabling it as well.
|
|
*/
|
|
|
|
unsigned int sysctl_sched_boost;
|
|
static enum sched_boost_policy boost_policy;
|
|
static enum sched_boost_policy boost_policy_dt = SCHED_BOOST_NONE;
|
|
static DEFINE_MUTEX(boost_mutex);
|
|
static unsigned int freq_aggr_threshold_backup;
|
|
|
|
static inline void boost_kick(int cpu)
|
|
{
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
if (!test_and_set_bit(BOOST_KICK, &rq->walt_flags))
|
|
smp_send_reschedule(cpu);
|
|
}
|
|
|
|
static void boost_kick_cpus(void)
|
|
{
|
|
int i;
|
|
struct cpumask kick_mask;
|
|
|
|
if (boost_policy != SCHED_BOOST_ON_BIG)
|
|
return;
|
|
|
|
cpumask_andnot(&kick_mask, cpu_online_mask, cpu_isolated_mask);
|
|
|
|
for_each_cpu(i, &kick_mask) {
|
|
if (cpu_capacity(i) != max_capacity)
|
|
boost_kick(i);
|
|
}
|
|
}
|
|
|
|
int got_boost_kick(void)
|
|
{
|
|
int cpu = smp_processor_id();
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
return test_bit(BOOST_KICK, &rq->walt_flags);
|
|
}
|
|
|
|
void clear_boost_kick(int cpu)
|
|
{
|
|
struct rq *rq = cpu_rq(cpu);
|
|
|
|
clear_bit(BOOST_KICK, &rq->walt_flags);
|
|
}
|
|
|
|
/*
|
|
* Scheduler boost type and boost policy might at first seem unrelated,
|
|
* however, there exists a connection between them that will allow us
|
|
* to use them interchangeably during placement decisions. We'll explain
|
|
* the connection here in one possible way so that the implications are
|
|
* clear when looking at placement policies.
|
|
*
|
|
* When policy = SCHED_BOOST_NONE, type is either none or RESTRAINED
|
|
* When policy = SCHED_BOOST_ON_ALL or SCHED_BOOST_ON_BIG, type can
|
|
* neither be none nor RESTRAINED.
|
|
*/
|
|
static void set_boost_policy(int type)
|
|
{
|
|
if (type == SCHED_BOOST_NONE || type == RESTRAINED_BOOST) {
|
|
boost_policy = SCHED_BOOST_NONE;
|
|
return;
|
|
}
|
|
|
|
if (boost_policy_dt) {
|
|
boost_policy = boost_policy_dt;
|
|
return;
|
|
}
|
|
|
|
if (sysctl_sched_is_big_little) {
|
|
boost_policy = SCHED_BOOST_ON_BIG;
|
|
return;
|
|
}
|
|
|
|
boost_policy = SCHED_BOOST_ON_ALL;
|
|
}
|
|
|
|
enum sched_boost_policy sched_boost_policy(void)
|
|
{
|
|
return boost_policy;
|
|
}
|
|
|
|
static bool verify_boost_params(int old_val, int new_val)
|
|
{
|
|
/*
|
|
* Boost can only be turned on or off. There is no possiblity of
|
|
* switching from one boost type to another or to set the same
|
|
* kind of boost several times.
|
|
*/
|
|
return !(!!old_val == !!new_val);
|
|
}
|
|
|
|
static void _sched_set_boost(int old_val, int type)
|
|
{
|
|
switch (type) {
|
|
case NO_BOOST:
|
|
if (old_val == FULL_THROTTLE_BOOST)
|
|
core_ctl_set_boost(false);
|
|
else if (old_val == CONSERVATIVE_BOOST)
|
|
restore_cgroup_boost_settings();
|
|
else
|
|
update_freq_aggregate_threshold(
|
|
freq_aggr_threshold_backup);
|
|
break;
|
|
|
|
case FULL_THROTTLE_BOOST:
|
|
core_ctl_set_boost(true);
|
|
boost_kick_cpus();
|
|
break;
|
|
|
|
case CONSERVATIVE_BOOST:
|
|
update_cgroup_boost_settings();
|
|
boost_kick_cpus();
|
|
break;
|
|
|
|
case RESTRAINED_BOOST:
|
|
freq_aggr_threshold_backup =
|
|
update_freq_aggregate_threshold(1);
|
|
break;
|
|
|
|
default:
|
|
WARN_ON(1);
|
|
return;
|
|
}
|
|
|
|
set_boost_policy(type);
|
|
sysctl_sched_boost = type;
|
|
trace_sched_set_boost(type);
|
|
}
|
|
|
|
void sched_boost_parse_dt(void)
|
|
{
|
|
struct device_node *sn;
|
|
const char *boost_policy;
|
|
|
|
sn = of_find_node_by_path("/sched-hmp");
|
|
if (!sn)
|
|
return;
|
|
|
|
if (!of_property_read_string(sn, "boost-policy", &boost_policy)) {
|
|
if (!strcmp(boost_policy, "boost-on-big"))
|
|
boost_policy_dt = SCHED_BOOST_ON_BIG;
|
|
else if (!strcmp(boost_policy, "boost-on-all"))
|
|
boost_policy_dt = SCHED_BOOST_ON_ALL;
|
|
}
|
|
}
|
|
|
|
int sched_set_boost(int type)
|
|
{
|
|
int ret = 0;
|
|
|
|
mutex_lock(&boost_mutex);
|
|
|
|
if (verify_boost_params(sysctl_sched_boost, type))
|
|
_sched_set_boost(sysctl_sched_boost, type);
|
|
else
|
|
ret = -EINVAL;
|
|
|
|
mutex_unlock(&boost_mutex);
|
|
return ret;
|
|
}
|
|
|
|
int sched_boost_handler(struct ctl_table *table, int write,
|
|
void __user *buffer, size_t *lenp,
|
|
loff_t *ppos)
|
|
{
|
|
int ret;
|
|
unsigned int *data = (unsigned int *)table->data;
|
|
unsigned int old_val;
|
|
|
|
mutex_lock(&boost_mutex);
|
|
|
|
old_val = *data;
|
|
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
|
|
|
|
if (ret || !write)
|
|
goto done;
|
|
|
|
if (verify_boost_params(old_val, *data)) {
|
|
_sched_set_boost(old_val, *data);
|
|
} else {
|
|
*data = old_val;
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
done:
|
|
mutex_unlock(&boost_mutex);
|
|
return ret;
|
|
}
|
|
|
|
int sched_boost(void)
|
|
{
|
|
return sysctl_sched_boost;
|
|
}
|