mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
Merge branches 'master-arm-multi_pmu_v2', 'master-config-fragments', 'master-hw-bkpt-fix', 'master-misc-patches' and 'master-task-placement-v2-updates' into big-LITTLE-MP-master-v19
Updates:
-------
- Rebased over 3.10 final
- Differences from big-LITTLE-MP-master-v18
- New Patches:
- master-config-fragments: 1 new patch
- "config: Disable priority filtering for HMP Scheduler"
- master-misc-patches: 1 new patch
- "mm: make vmstat_update periodic run conditional"
- New Branches:
- master-task-placement-v2-updates: 7 patches
New patches from ARM added in a new topic branch stacked on top
of master-task-placement-v2-sysfs...
- Revert "sched: Enable HMP priority filter by default"
- "HMP: Use unweighted load for hmp migration decisions"
- "HMP: Select least-loaded CPU when performing HMP Migrations"
- "HMP: Avoid multiple calls to hmp_domain_min_load in fast path"
- "HMP: Force new non-kernel tasks onto big CPUs until load stabilises"
- "sched: Restrict nohz balance kicks to stay in the HMP domain"
- "HMP: experimental: Force all rt tasks to start on little domain."
Commands used for merge:
-----------------------
$ git checkout -b big-LITTLE-MP-master-v19 v3.10
$ git merge master-arm-multi_pmu_v2 master-config-fragments \
master-hw-bkpt-fix master-misc-patches master-task-placement-v2 \
master-task-placement-v2-sysfs master-task-placement-v2-updates
This commit is contained in:
@@ -1240,6 +1240,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
See comment before ip2_setup() in
|
||||
drivers/char/ip2/ip2base.c.
|
||||
|
||||
irqaffinity= [SMP] Set the default irq affinity mask
|
||||
Format:
|
||||
<cpu number>,...,<cpu number>
|
||||
or
|
||||
<cpu number>-<cpu number>
|
||||
(must be a positive range in ascending order)
|
||||
or a mixture
|
||||
<cpu number>,...,<cpu number>-<cpu number>
|
||||
|
||||
irqfixup [HW]
|
||||
When an interrupt is not handled search all handlers
|
||||
for it. Intended to get systems with badly broken
|
||||
|
||||
@@ -1494,6 +1494,90 @@ config SCHED_SMT
|
||||
MultiThreading at a cost of slightly increased overhead in some
|
||||
places. If unsure say N here.
|
||||
|
||||
config DISABLE_CPU_SCHED_DOMAIN_BALANCE
|
||||
bool "(EXPERIMENTAL) Disable CPU level scheduler load-balancing"
|
||||
help
|
||||
Disables scheduler load-balancing at CPU sched domain level.
|
||||
|
||||
config SCHED_HMP
|
||||
bool "(EXPERIMENTAL) Heterogenous multiprocessor scheduling"
|
||||
depends on DISABLE_CPU_SCHED_DOMAIN_BALANCE && SCHED_MC && FAIR_GROUP_SCHED && !SCHED_AUTOGROUP
|
||||
help
|
||||
Experimental scheduler optimizations for heterogeneous platforms.
|
||||
Attempts to introspectively select task affinity to optimize power
|
||||
and performance. Basic support for multiple (>2) cpu types is in place,
|
||||
but it has only been tested with two types of cpus.
|
||||
There is currently no support for migration of task groups, hence
|
||||
!SCHED_AUTOGROUP. Furthermore, normal load-balancing must be disabled
|
||||
between cpus of different type (DISABLE_CPU_SCHED_DOMAIN_BALANCE).
|
||||
|
||||
config SCHED_HMP_PRIO_FILTER
|
||||
bool "(EXPERIMENTAL) Filter HMP migrations by task priority"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
Enables task priority based HMP migration filter. Any task with
|
||||
a NICE value above the threshold will always be on low-power cpus
|
||||
with less compute capacity.
|
||||
|
||||
config SCHED_HMP_PRIO_FILTER_VAL
|
||||
int "NICE priority threshold"
|
||||
default 5
|
||||
depends on SCHED_HMP_PRIO_FILTER
|
||||
|
||||
config HMP_FAST_CPU_MASK
|
||||
string "HMP scheduler fast CPU mask"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
Leave empty to use device tree information.
|
||||
Specify the cpuids of the fast CPUs in the system as a list string,
|
||||
e.g. cpuid 0+1 should be specified as 0-1.
|
||||
|
||||
config HMP_SLOW_CPU_MASK
|
||||
string "HMP scheduler slow CPU mask"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
Leave empty to use device tree information.
|
||||
Specify the cpuids of the slow CPUs in the system as a list string,
|
||||
e.g. cpuid 0+1 should be specified as 0-1.
|
||||
|
||||
config HMP_VARIABLE_SCALE
|
||||
bool "Allows changing the load tracking scale through sysfs"
|
||||
depends on SCHED_HMP
|
||||
help
|
||||
When turned on, this option exports the thresholds and load average
|
||||
period value for the load tracking patches through sysfs.
|
||||
The values can be modified to change the rate of load accumulation
|
||||
and the thresholds used for HMP migration.
|
||||
The load_avg_period_ms is the time in ms to reach a load average of
|
||||
0.5 for an idle task of 0 load average ratio that start a busy loop.
|
||||
The up_threshold and down_threshold is the value to go to a faster
|
||||
CPU or to go back to a slower cpu.
|
||||
The {up,down}_threshold are devided by 1024 before being compared
|
||||
to the load average.
|
||||
For examples, with load_avg_period_ms = 128 and up_threshold = 512,
|
||||
a running task with a load of 0 will be migrated to a bigger CPU after
|
||||
128ms, because after 128ms its load_avg_ratio is 0.5 and the real
|
||||
up_threshold is 0.5.
|
||||
This patch has the same behavior as changing the Y of the load
|
||||
average computation to
|
||||
(1002/1024)^(LOAD_AVG_PERIOD/load_avg_period_ms)
|
||||
but it remove intermadiate overflows in computation.
|
||||
|
||||
config HMP_FREQUENCY_INVARIANT_SCALE
|
||||
bool "(EXPERIMENTAL) Frequency-Invariant Tracked Load for HMP"
|
||||
depends on HMP_VARIABLE_SCALE && CPU_FREQ
|
||||
help
|
||||
Scales the current load contribution in line with the frequency
|
||||
of the CPU that the task was executed on.
|
||||
In this version, we use a simple linear scale derived from the
|
||||
maximum frequency reported by CPUFreq.
|
||||
Restricting tracked load to be scaled by the CPU's frequency
|
||||
represents the consumption of possible compute capacity
|
||||
(rather than consumption of actual instantaneous capacity as
|
||||
normal) and allows the HMP migration's simple threshold
|
||||
migration strategy to interact more predictably with CPUFreq's
|
||||
asynchronous compute capacity changes.
|
||||
|
||||
config HAVE_ARM_SCU
|
||||
bool
|
||||
help
|
||||
|
||||
@@ -28,6 +28,37 @@ void store_cpu_topology(unsigned int cpuid);
|
||||
const struct cpumask *cpu_coregroup_mask(int cpu);
|
||||
int cluster_to_logical_mask(unsigned int socket_id, cpumask_t *cluster_mask);
|
||||
|
||||
#ifdef CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE
|
||||
/* Common values for CPUs */
|
||||
#ifndef SD_CPU_INIT
|
||||
#define SD_CPU_INIT (struct sched_domain) { \
|
||||
.min_interval = 1, \
|
||||
.max_interval = 4, \
|
||||
.busy_factor = 64, \
|
||||
.imbalance_pct = 125, \
|
||||
.cache_nice_tries = 1, \
|
||||
.busy_idx = 2, \
|
||||
.idle_idx = 1, \
|
||||
.newidle_idx = 0, \
|
||||
.wake_idx = 0, \
|
||||
.forkexec_idx = 0, \
|
||||
\
|
||||
.flags = 0*SD_LOAD_BALANCE \
|
||||
| 1*SD_BALANCE_NEWIDLE \
|
||||
| 1*SD_BALANCE_EXEC \
|
||||
| 1*SD_BALANCE_FORK \
|
||||
| 0*SD_BALANCE_WAKE \
|
||||
| 1*SD_WAKE_AFFINE \
|
||||
| 0*SD_SHARE_CPUPOWER \
|
||||
| 0*SD_SHARE_PKG_RESOURCES \
|
||||
| 0*SD_SERIALIZE \
|
||||
, \
|
||||
.last_balance = jiffies, \
|
||||
.balance_interval = 1, \
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE */
|
||||
|
||||
#else
|
||||
|
||||
static inline void init_cpu_topology(void) { }
|
||||
|
||||
@@ -1049,7 +1049,8 @@ static struct notifier_block dbg_cpu_pm_nb = {
|
||||
|
||||
static void __init pm_init(void)
|
||||
{
|
||||
cpu_pm_register_notifier(&dbg_cpu_pm_nb);
|
||||
if (has_ossr)
|
||||
cpu_pm_register_notifier(&dbg_cpu_pm_nb);
|
||||
}
|
||||
#else
|
||||
static inline void pm_init(void)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/cputype.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <asm/topology.h>
|
||||
|
||||
/*
|
||||
@@ -289,6 +290,113 @@ void store_cpu_topology(unsigned int cpuid)
|
||||
cpu_topology[cpuid].socket_id, mpidr);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
|
||||
static const char * const little_cores[] = {
|
||||
"arm,cortex-a7",
|
||||
NULL,
|
||||
};
|
||||
|
||||
static bool is_little_cpu(struct device_node *cn)
|
||||
{
|
||||
const char * const *lc;
|
||||
for (lc = little_cores; *lc; lc++)
|
||||
if (of_device_is_compatible(cn, *lc))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void __init arch_get_fast_and_slow_cpus(struct cpumask *fast,
|
||||
struct cpumask *slow)
|
||||
{
|
||||
struct device_node *cn = NULL;
|
||||
int cpu;
|
||||
|
||||
cpumask_clear(fast);
|
||||
cpumask_clear(slow);
|
||||
|
||||
/*
|
||||
* Use the config options if they are given. This helps testing
|
||||
* HMP scheduling on systems without a big.LITTLE architecture.
|
||||
*/
|
||||
if (strlen(CONFIG_HMP_FAST_CPU_MASK) && strlen(CONFIG_HMP_SLOW_CPU_MASK)) {
|
||||
if (cpulist_parse(CONFIG_HMP_FAST_CPU_MASK, fast))
|
||||
WARN(1, "Failed to parse HMP fast cpu mask!\n");
|
||||
if (cpulist_parse(CONFIG_HMP_SLOW_CPU_MASK, slow))
|
||||
WARN(1, "Failed to parse HMP slow cpu mask!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Else, parse device tree for little cores.
|
||||
*/
|
||||
while ((cn = of_find_node_by_type(cn, "cpu"))) {
|
||||
|
||||
const u32 *mpidr;
|
||||
int len;
|
||||
|
||||
mpidr = of_get_property(cn, "reg", &len);
|
||||
if (!mpidr || len != 4) {
|
||||
pr_err("* %s missing reg property\n", cn->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
cpu = get_logical_index(be32_to_cpup(mpidr));
|
||||
if (cpu == -EINVAL) {
|
||||
pr_err("couldn't get logical index for mpidr %x\n",
|
||||
be32_to_cpup(mpidr));
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_little_cpu(cn))
|
||||
cpumask_set_cpu(cpu, slow);
|
||||
else
|
||||
cpumask_set_cpu(cpu, fast);
|
||||
}
|
||||
|
||||
if (!cpumask_empty(fast) && !cpumask_empty(slow))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We didn't find both big and little cores so let's call all cores
|
||||
* fast as this will keep the system running, with all cores being
|
||||
* treated equal.
|
||||
*/
|
||||
cpumask_setall(fast);
|
||||
cpumask_clear(slow);
|
||||
}
|
||||
|
||||
struct cpumask hmp_slow_cpu_mask;
|
||||
|
||||
void __init arch_get_hmp_domains(struct list_head *hmp_domains_list)
|
||||
{
|
||||
struct cpumask hmp_fast_cpu_mask;
|
||||
struct hmp_domain *domain;
|
||||
|
||||
arch_get_fast_and_slow_cpus(&hmp_fast_cpu_mask, &hmp_slow_cpu_mask);
|
||||
|
||||
/*
|
||||
* Initialize hmp_domains
|
||||
* Must be ordered with respect to compute capacity.
|
||||
* Fastest domain at head of list.
|
||||
*/
|
||||
if(!cpumask_empty(&hmp_slow_cpu_mask)) {
|
||||
domain = (struct hmp_domain *)
|
||||
kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
|
||||
cpumask_copy(&domain->possible_cpus, &hmp_slow_cpu_mask);
|
||||
cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
|
||||
list_add(&domain->hmp_domains, hmp_domains_list);
|
||||
}
|
||||
domain = (struct hmp_domain *)
|
||||
kmalloc(sizeof(struct hmp_domain), GFP_KERNEL);
|
||||
cpumask_copy(&domain->possible_cpus, &hmp_fast_cpu_mask);
|
||||
cpumask_and(&domain->cpus, cpu_online_mask, &domain->possible_cpus);
|
||||
list_add(&domain->hmp_domains, hmp_domains_list);
|
||||
}
|
||||
#endif /* CONFIG_SCHED_HMP */
|
||||
|
||||
|
||||
/*
|
||||
* cluster_to_logical_mask - return cpu logical mask of CPUs in a cluster
|
||||
* @socket_id: cluster HW identifier
|
||||
|
||||
@@ -885,6 +885,13 @@ void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms);
|
||||
|
||||
bool cpus_share_cache(int this_cpu, int that_cpu);
|
||||
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
struct hmp_domain {
|
||||
struct cpumask cpus;
|
||||
struct cpumask possible_cpus;
|
||||
struct list_head hmp_domains;
|
||||
};
|
||||
#endif /* CONFIG_SCHED_HMP */
|
||||
#else /* CONFIG_SMP */
|
||||
|
||||
struct sched_domain_attr;
|
||||
@@ -931,6 +938,12 @@ struct sched_avg {
|
||||
u64 last_runnable_update;
|
||||
s64 decay_count;
|
||||
unsigned long load_avg_contrib;
|
||||
unsigned long load_avg_ratio;
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
u64 hmp_last_up_migration;
|
||||
u64 hmp_last_down_migration;
|
||||
#endif
|
||||
u32 usage_avg_sum;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SCHEDSTATS
|
||||
|
||||
@@ -198,7 +198,7 @@ extern void __inc_zone_state(struct zone *, enum zone_stat_item);
|
||||
extern void dec_zone_state(struct zone *, enum zone_stat_item);
|
||||
extern void __dec_zone_state(struct zone *, enum zone_stat_item);
|
||||
|
||||
void refresh_cpu_vm_stats(int);
|
||||
bool refresh_cpu_vm_stats(int);
|
||||
void refresh_zone_stat_thresholds(void);
|
||||
|
||||
void drain_zonestat(struct zone *zone, struct per_cpu_pageset *);
|
||||
|
||||
@@ -430,6 +430,159 @@ TRACE_EVENT(sched_pi_setprio,
|
||||
__entry->oldprio, __entry->newprio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for showing tracked load contribution.
|
||||
*/
|
||||
TRACE_EVENT(sched_task_load_contrib,
|
||||
|
||||
TP_PROTO(struct task_struct *tsk, unsigned long load_contrib),
|
||||
|
||||
TP_ARGS(tsk, load_contrib),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, comm, TASK_COMM_LEN)
|
||||
__field(pid_t, pid)
|
||||
__field(unsigned long, load_contrib)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
|
||||
__entry->pid = tsk->pid;
|
||||
__entry->load_contrib = load_contrib;
|
||||
),
|
||||
|
||||
TP_printk("comm=%s pid=%d load_contrib=%lu",
|
||||
__entry->comm, __entry->pid,
|
||||
__entry->load_contrib)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for showing tracked task runnable ratio [0..1023].
|
||||
*/
|
||||
TRACE_EVENT(sched_task_runnable_ratio,
|
||||
|
||||
TP_PROTO(struct task_struct *tsk, unsigned long ratio),
|
||||
|
||||
TP_ARGS(tsk, ratio),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, comm, TASK_COMM_LEN)
|
||||
__field(pid_t, pid)
|
||||
__field(unsigned long, ratio)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
|
||||
__entry->pid = tsk->pid;
|
||||
__entry->ratio = ratio;
|
||||
),
|
||||
|
||||
TP_printk("comm=%s pid=%d ratio=%lu",
|
||||
__entry->comm, __entry->pid,
|
||||
__entry->ratio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for showing tracked rq runnable ratio [0..1023].
|
||||
*/
|
||||
TRACE_EVENT(sched_rq_runnable_ratio,
|
||||
|
||||
TP_PROTO(int cpu, unsigned long ratio),
|
||||
|
||||
TP_ARGS(cpu, ratio),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, cpu)
|
||||
__field(unsigned long, ratio)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->cpu = cpu;
|
||||
__entry->ratio = ratio;
|
||||
),
|
||||
|
||||
TP_printk("cpu=%d ratio=%lu",
|
||||
__entry->cpu,
|
||||
__entry->ratio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for showing tracked rq runnable load.
|
||||
*/
|
||||
TRACE_EVENT(sched_rq_runnable_load,
|
||||
|
||||
TP_PROTO(int cpu, u64 load),
|
||||
|
||||
TP_ARGS(cpu, load),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field(int, cpu)
|
||||
__field(u64, load)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->cpu = cpu;
|
||||
__entry->load = load;
|
||||
),
|
||||
|
||||
TP_printk("cpu=%d load=%llu",
|
||||
__entry->cpu,
|
||||
__entry->load)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for showing tracked task cpu usage ratio [0..1023].
|
||||
*/
|
||||
TRACE_EVENT(sched_task_usage_ratio,
|
||||
|
||||
TP_PROTO(struct task_struct *tsk, unsigned long ratio),
|
||||
|
||||
TP_ARGS(tsk, ratio),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, comm, TASK_COMM_LEN)
|
||||
__field(pid_t, pid)
|
||||
__field(unsigned long, ratio)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
|
||||
__entry->pid = tsk->pid;
|
||||
__entry->ratio = ratio;
|
||||
),
|
||||
|
||||
TP_printk("comm=%s pid=%d ratio=%lu",
|
||||
__entry->comm, __entry->pid,
|
||||
__entry->ratio)
|
||||
);
|
||||
|
||||
/*
|
||||
* Tracepoint for HMP (CONFIG_SCHED_HMP) task migrations.
|
||||
*/
|
||||
TRACE_EVENT(sched_hmp_migrate,
|
||||
|
||||
TP_PROTO(struct task_struct *tsk, int dest, int force),
|
||||
|
||||
TP_ARGS(tsk, dest, force),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__array(char, comm, TASK_COMM_LEN)
|
||||
__field(pid_t, pid)
|
||||
__field(int, dest)
|
||||
__field(int, force)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
|
||||
__entry->pid = tsk->pid;
|
||||
__entry->dest = dest;
|
||||
__entry->force = force;
|
||||
),
|
||||
|
||||
TP_printk("comm=%s pid=%d dest=%d force=%d",
|
||||
__entry->comm, __entry->pid,
|
||||
__entry->dest, __entry->force)
|
||||
);
|
||||
#endif /* _TRACE_SCHED_H */
|
||||
|
||||
/* This part must be outside protection */
|
||||
|
||||
@@ -23,10 +23,27 @@
|
||||
static struct lock_class_key irq_desc_lock_class;
|
||||
|
||||
#if defined(CONFIG_SMP)
|
||||
static int __init irq_affinity_setup(char *str)
|
||||
{
|
||||
zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
|
||||
cpulist_parse(str, irq_default_affinity);
|
||||
/*
|
||||
* Set at least the boot cpu. We don't want to end up with
|
||||
* bugreports caused by random comandline masks
|
||||
*/
|
||||
cpumask_set_cpu(smp_processor_id(), irq_default_affinity);
|
||||
return 1;
|
||||
}
|
||||
__setup("irqaffinity=", irq_affinity_setup);
|
||||
|
||||
static void __init init_irq_default_affinity(void)
|
||||
{
|
||||
alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
|
||||
cpumask_setall(irq_default_affinity);
|
||||
#ifdef CONFIG_CPUMASK_OFFSTACK
|
||||
if (!irq_default_affinity)
|
||||
zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
|
||||
#endif
|
||||
if (cpumask_empty(irq_default_affinity))
|
||||
cpumask_setall(irq_default_affinity);
|
||||
}
|
||||
#else
|
||||
static void __init init_irq_default_affinity(void)
|
||||
|
||||
@@ -1617,6 +1617,20 @@ static void __sched_fork(struct task_struct *p)
|
||||
#if defined(CONFIG_SMP) && defined(CONFIG_FAIR_GROUP_SCHED)
|
||||
p->se.avg.runnable_avg_period = 0;
|
||||
p->se.avg.runnable_avg_sum = 0;
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
/* keep LOAD_AVG_MAX in sync with fair.c if load avg series is changed */
|
||||
#define LOAD_AVG_MAX 47742
|
||||
if (p->mm) {
|
||||
p->se.avg.hmp_last_up_migration = 0;
|
||||
p->se.avg.hmp_last_down_migration = 0;
|
||||
p->se.avg.load_avg_ratio = 1023;
|
||||
p->se.avg.load_avg_contrib =
|
||||
(1023 * scale_load_down(p->se.load.weight));
|
||||
p->se.avg.runnable_avg_period = LOAD_AVG_MAX;
|
||||
p->se.avg.runnable_avg_sum = LOAD_AVG_MAX;
|
||||
p->se.avg.usage_avg_sum = LOAD_AVG_MAX;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#ifdef CONFIG_SCHEDSTATS
|
||||
memset(&p->se.statistics, 0, sizeof(p->se.statistics));
|
||||
@@ -3813,6 +3827,8 @@ static struct task_struct *find_process_by_pid(pid_t pid)
|
||||
return pid ? find_task_by_vpid(pid) : current;
|
||||
}
|
||||
|
||||
extern struct cpumask hmp_slow_cpu_mask;
|
||||
|
||||
/* Actually do priority change: must hold rq lock. */
|
||||
static void
|
||||
__setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
|
||||
@@ -3822,8 +3838,13 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio)
|
||||
p->normal_prio = normal_prio(p);
|
||||
/* we are holding p->pi_lock already */
|
||||
p->prio = rt_mutex_getprio(p);
|
||||
if (rt_prio(p->prio))
|
||||
if (rt_prio(p->prio)) {
|
||||
p->sched_class = &rt_sched_class;
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
if (cpumask_equal(&p->cpus_allowed, cpu_all_mask))
|
||||
do_set_cpus_allowed(p, &hmp_slow_cpu_mask);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
p->sched_class = &fair_sched_class;
|
||||
set_load_weight(p);
|
||||
|
||||
@@ -94,6 +94,7 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
|
||||
#ifdef CONFIG_SMP
|
||||
P(se->avg.runnable_avg_sum);
|
||||
P(se->avg.runnable_avg_period);
|
||||
P(se->avg.usage_avg_sum);
|
||||
P(se->avg.load_avg_contrib);
|
||||
P(se->avg.decay_count);
|
||||
#endif
|
||||
@@ -223,6 +224,8 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
|
||||
cfs_rq->tg_runnable_contrib);
|
||||
SEQ_printf(m, " .%-30s: %d\n", "tg->runnable_avg",
|
||||
atomic_read(&cfs_rq->tg->runnable_avg));
|
||||
SEQ_printf(m, " .%-30s: %d\n", "tg->usage_avg",
|
||||
atomic_read(&cfs_rq->tg->usage_avg));
|
||||
#endif
|
||||
|
||||
print_cfs_group_stats(m, cpu, cfs_rq->tg);
|
||||
|
||||
1130
kernel/sched/fair.c
1130
kernel/sched/fair.c
File diff suppressed because it is too large
Load Diff
@@ -142,7 +142,7 @@ struct task_group {
|
||||
|
||||
atomic_t load_weight;
|
||||
atomic64_t load_avg;
|
||||
atomic_t runnable_avg;
|
||||
atomic_t runnable_avg, usage_avg;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RT_GROUP_SCHED
|
||||
@@ -279,7 +279,7 @@ struct cfs_rq {
|
||||
#endif /* CONFIG_FAIR_GROUP_SCHED */
|
||||
/* These always depend on CONFIG_FAIR_GROUP_SCHED */
|
||||
#ifdef CONFIG_FAIR_GROUP_SCHED
|
||||
u32 tg_runnable_contrib;
|
||||
u32 tg_runnable_contrib, tg_usage_contrib;
|
||||
u64 tg_load_contrib;
|
||||
#endif /* CONFIG_FAIR_GROUP_SCHED */
|
||||
|
||||
@@ -464,6 +464,9 @@ struct rq {
|
||||
int active_balance;
|
||||
int push_cpu;
|
||||
struct cpu_stop_work active_balance_work;
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
struct task_struct *migrate_task;
|
||||
#endif
|
||||
/* cpu of this runqueue: */
|
||||
int cpu;
|
||||
int online;
|
||||
@@ -642,6 +645,12 @@ static inline unsigned int group_first_cpu(struct sched_group *group)
|
||||
|
||||
extern int group_balance_cpu(struct sched_group *sg);
|
||||
|
||||
#ifdef CONFIG_SCHED_HMP
|
||||
static LIST_HEAD(hmp_domains);
|
||||
DECLARE_PER_CPU(struct hmp_domain *, hmp_cpu_domain);
|
||||
#define hmp_cpu_domain(cpu) (per_cpu(hmp_cpu_domain, (cpu)))
|
||||
#endif /* CONFIG_SCHED_HMP */
|
||||
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
#include "stats.h"
|
||||
|
||||
11
linaro/configs/big-LITTLE-MP.conf
Normal file
11
linaro/configs/big-LITTLE-MP.conf
Normal file
@@ -0,0 +1,11 @@
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_FAIR_GROUP_SCHED=y
|
||||
CONFIG_NO_HZ=y
|
||||
CONFIG_SCHED_MC=y
|
||||
CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y
|
||||
CONFIG_SCHED_HMP=y
|
||||
CONFIG_HMP_FAST_CPU_MASK=""
|
||||
CONFIG_HMP_SLOW_CPU_MASK=""
|
||||
CONFIG_HMP_VARIABLE_SCALE=y
|
||||
CONFIG_HMP_FREQUENCY_INVARIANT_SCALE=y
|
||||
95
mm/vmstat.c
95
mm/vmstat.c
@@ -14,6 +14,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/vmstat.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/math64.h>
|
||||
@@ -432,11 +433,12 @@ EXPORT_SYMBOL(dec_zone_page_state);
|
||||
* with the global counters. These could cause remote node cache line
|
||||
* bouncing and will have to be only done when necessary.
|
||||
*/
|
||||
void refresh_cpu_vm_stats(int cpu)
|
||||
bool refresh_cpu_vm_stats(int cpu)
|
||||
{
|
||||
struct zone *zone;
|
||||
int i;
|
||||
int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
|
||||
bool vm_activity = false;
|
||||
|
||||
for_each_populated_zone(zone) {
|
||||
struct per_cpu_pageset *p;
|
||||
@@ -483,14 +485,21 @@ void refresh_cpu_vm_stats(int cpu)
|
||||
if (p->expire)
|
||||
continue;
|
||||
|
||||
if (p->pcp.count)
|
||||
if (p->pcp.count) {
|
||||
vm_activity = true;
|
||||
drain_zone_pages(zone, &p->pcp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
|
||||
if (global_diff[i])
|
||||
if (global_diff[i]) {
|
||||
atomic_long_add(global_diff[i], &vm_stat[i]);
|
||||
vm_activity = true;
|
||||
}
|
||||
|
||||
return vm_activity;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1174,20 +1183,70 @@ static const struct file_operations proc_vmstat_file_operations = {
|
||||
#ifdef CONFIG_SMP
|
||||
static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
|
||||
int sysctl_stat_interval __read_mostly = HZ;
|
||||
static struct cpumask vmstat_off_cpus;
|
||||
struct delayed_work vmstat_monitor_work;
|
||||
|
||||
static void vmstat_update(struct work_struct *w)
|
||||
static inline bool need_vmstat(int cpu)
|
||||
{
|
||||
refresh_cpu_vm_stats(smp_processor_id());
|
||||
schedule_delayed_work(&__get_cpu_var(vmstat_work),
|
||||
round_jiffies_relative(sysctl_stat_interval));
|
||||
struct zone *zone;
|
||||
int i;
|
||||
|
||||
for_each_populated_zone(zone) {
|
||||
struct per_cpu_pageset *p;
|
||||
|
||||
p = per_cpu_ptr(zone->pageset, cpu);
|
||||
|
||||
for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
|
||||
if (p->vm_stat_diff[i])
|
||||
return true;
|
||||
|
||||
if (zone_to_nid(zone) != numa_node_id() && p->pcp.count)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __cpuinit start_cpu_timer(int cpu)
|
||||
static void vmstat_update(struct work_struct *w);
|
||||
|
||||
static void start_cpu_timer(int cpu)
|
||||
{
|
||||
struct delayed_work *work = &per_cpu(vmstat_work, cpu);
|
||||
|
||||
cpumask_clear_cpu(cpu, &vmstat_off_cpus);
|
||||
schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu));
|
||||
}
|
||||
|
||||
static void __cpuinit setup_cpu_timer(int cpu)
|
||||
{
|
||||
struct delayed_work *work = &per_cpu(vmstat_work, cpu);
|
||||
|
||||
INIT_DEFERRABLE_WORK(work, vmstat_update);
|
||||
schedule_delayed_work_on(cpu, work, __round_jiffies_relative(HZ, cpu));
|
||||
start_cpu_timer(cpu);
|
||||
}
|
||||
|
||||
static void vmstat_update_monitor(struct work_struct *w)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_cpu_and(cpu, &vmstat_off_cpus, cpu_online_mask)
|
||||
if (need_vmstat(cpu))
|
||||
start_cpu_timer(cpu);
|
||||
|
||||
queue_delayed_work(system_unbound_wq, &vmstat_monitor_work,
|
||||
round_jiffies_relative(sysctl_stat_interval));
|
||||
}
|
||||
|
||||
|
||||
static void vmstat_update(struct work_struct *w)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (likely(refresh_cpu_vm_stats(cpu)))
|
||||
schedule_delayed_work(&__get_cpu_var(vmstat_work),
|
||||
round_jiffies_relative(sysctl_stat_interval));
|
||||
else
|
||||
cpumask_set_cpu(cpu, &vmstat_off_cpus);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1204,17 +1263,19 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,
|
||||
case CPU_ONLINE:
|
||||
case CPU_ONLINE_FROZEN:
|
||||
refresh_zone_stat_thresholds();
|
||||
start_cpu_timer(cpu);
|
||||
setup_cpu_timer(cpu);
|
||||
node_set_state(cpu_to_node(cpu), N_CPU);
|
||||
break;
|
||||
case CPU_DOWN_PREPARE:
|
||||
case CPU_DOWN_PREPARE_FROZEN:
|
||||
cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
|
||||
per_cpu(vmstat_work, cpu).work.func = NULL;
|
||||
if (!cpumask_test_cpu(cpu, &vmstat_off_cpus)) {
|
||||
cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));
|
||||
per_cpu(vmstat_work, cpu).work.func = NULL;
|
||||
}
|
||||
break;
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_DOWN_FAILED_FROZEN:
|
||||
start_cpu_timer(cpu);
|
||||
setup_cpu_timer(cpu);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
case CPU_DEAD_FROZEN:
|
||||
@@ -1237,8 +1298,14 @@ static int __init setup_vmstat(void)
|
||||
|
||||
register_cpu_notifier(&vmstat_notifier);
|
||||
|
||||
INIT_DEFERRABLE_WORK(&vmstat_monitor_work,
|
||||
vmstat_update_monitor);
|
||||
queue_delayed_work(system_unbound_wq,
|
||||
&vmstat_monitor_work,
|
||||
round_jiffies_relative(HZ));
|
||||
|
||||
for_each_online_cpu(cpu)
|
||||
start_cpu_timer(cpu);
|
||||
setup_cpu_timer(cpu);
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
|
||||
|
||||
Reference in New Issue
Block a user