From: Daeyeong Lee Date: Fri, 23 Mar 2018 07:10:55 +0000 (+0900) Subject: [COMMON] sched: ems: Separate LBT feature into lbt.c X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=8e905c627850808a6a3af4ff2b94334738822554;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [COMMON] sched: ems: Separate LBT feature into lbt.c Change-Id: Id4b7b40f06418d4d1c46c3170999942ccb895f5b Signed-off-by: Daeyeong Lee --- diff --git a/kernel/sched/ems/Makefile b/kernel/sched/ems/Makefile index 6c5f5a421c5c..c3abbd9acdf0 100644 --- a/kernel/sched/ems/Makefile +++ b/kernel/sched/ems/Makefile @@ -1,4 +1,4 @@ -obj-y += core.o global_boost.o +obj-y += core.o global_boost.o lbt.o obj-$(CONFIG_SCHED_TUNE) += st_addon.o obj-$(CONFIG_SCHED_EMS) += ehmp.o obj-$(CONFIG_FREQVAR_TUNE) += freqvar_tune.o diff --git a/kernel/sched/ems/ehmp.c b/kernel/sched/ems/ehmp.c index 624f631fd1a7..c90a09d6b372 100644 --- a/kernel/sched/ems/ehmp.c +++ b/kernel/sched/ems/ehmp.c @@ -15,6 +15,7 @@ #include "../sched.h" #include "../tune.h" +#include "./ems.h" /********************************************************************** * extern functions * @@ -294,347 +295,6 @@ int exynos_need_active_balance(enum cpu_idle_type idle, struct sched_domain *sd, return unlikely(sd->nr_balance_failed > sd->cache_nice_tries + 2); } -/****************************************************************/ -/* Load Balance Trigger */ -/****************************************************************/ -#define DISABLE_OU -1 -#define DEFAULT_OU_RATIO 80 - -struct lbt_overutil { - bool top; - struct cpumask cpus; - unsigned long capacity; - int ratio; -}; -DEFINE_PER_CPU(struct lbt_overutil *, lbt_overutil); - -static inline int get_topology_depth(void) -{ - struct sched_domain *sd; - - for_each_domain(0, sd) { - if (sd->parent == NULL) - return sd->level; - } - - return -1; -} - -static inline int get_last_level(struct lbt_overutil *ou) -{ - int level; - - for (level = 0; &ou[level] != NULL; level++) { - if (ou[level].top == true) - return level; - } - - return -1; -} - -/****************************************************************/ -/* External APIs */ -/****************************************************************/ -bool lbt_overutilized(int cpu, int level) -{ - struct lbt_overutil *ou = per_cpu(lbt_overutil, cpu); - bool overutilized; - - if (!ou) - return false; - - overutilized = (cpu_util(cpu) > ou[level].capacity) ? true : false; - - if (overutilized) - trace_ehmp_lbt_overutilized(cpu, level, cpu_util(cpu), - ou[level].capacity, overutilized); - - return overutilized; -} - -void update_lbt_overutil(int cpu, unsigned long capacity) -{ - struct lbt_overutil *ou = per_cpu(lbt_overutil, cpu); - int level, last = get_last_level(ou); - - for (level = 0; level <= last; level++) { - if (ou[level].ratio == DISABLE_OU) - continue; - - ou[level].capacity = (capacity * ou[level].ratio) / 100; - } -} - -/****************************************************************/ -/* SYSFS */ -/****************************************************************/ -#define lbt_attr_init(_attr, _name, _mode, _show, _store) \ - sysfs_attr_init(&_attr.attr); \ - _attr.attr.name = _name; \ - _attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(_mode); \ - _attr.show = _show; \ - _attr.store = _store; - -static struct kobject *lbt_kobj; -static struct attribute **lbt_attrs; -static struct kobj_attribute *lbt_kattrs; -static struct attribute_group lbt_group; - -static ssize_t show_overutil_ratio(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct lbt_overutil *ou = per_cpu(lbt_overutil, 0); - int level = attr - lbt_kattrs; - int cpu, ret = 0; - - for_each_possible_cpu(cpu) { - ou = per_cpu(lbt_overutil, cpu); - - if (ou[level].ratio == DISABLE_OU) - continue; - - ret += sprintf(buf + ret, "cpu%d ratio:%3d capacity:%4lu\n", - cpu, ou[level].ratio, ou[level].capacity); - } - - return ret; -} - -static ssize_t store_overutil_ratio(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, - size_t count) -{ - struct lbt_overutil *ou; - unsigned long capacity; - int level = attr - lbt_kattrs; - int cpu, ratio; - - if (sscanf(buf, "%d %d", &cpu, &ratio) != 2) - return -EINVAL; - - /* Check cpu is possible */ - if (!cpumask_test_cpu(cpu, cpu_possible_mask)) - return -EINVAL; - ou = per_cpu(lbt_overutil, cpu); - - /* If ratio is outrage, disable overutil */ - if (ratio < 0 || ratio > 100) - ratio = DEFAULT_OU_RATIO; - - for_each_cpu(cpu, &ou[level].cpus) { - ou = per_cpu(lbt_overutil, cpu); - if (ou[level].ratio == DISABLE_OU) - continue; - - ou[level].ratio = ratio; - capacity = capacity_orig_of(cpu); - update_lbt_overutil(cpu, capacity); - } - - return count; -} - -static int alloc_lbt_sysfs(int size) -{ - if (size < 0) - return -EINVAL; - - lbt_attrs = kzalloc(sizeof(struct attribute *) * (size + 1), - GFP_KERNEL); - if (!lbt_attrs) - goto fail_alloc; - - lbt_kattrs = kzalloc(sizeof(struct kobj_attribute) * (size), - GFP_KERNEL); - if (!lbt_kattrs) - goto fail_alloc; - - return 0; - -fail_alloc: - kfree(lbt_attrs); - kfree(lbt_kattrs); - - pr_err("LBT(%s): failed to alloc sysfs attrs\n", __func__); - return -ENOMEM; -} - -static int __init lbt_sysfs_init(struct kobject *parent) -{ - int depth = get_topology_depth(); - int i; - - if (alloc_lbt_sysfs(depth + 1)) - goto out; - - for (i = 0; i <= depth; i++) { - char buf[20]; - char *name; - - sprintf(buf, "overutil_ratio_level%d", i); - name = kstrdup(buf, GFP_KERNEL); - if (!name) - goto out; - - lbt_attr_init(lbt_kattrs[i], name, 0644, - show_overutil_ratio, store_overutil_ratio); - lbt_attrs[i] = &lbt_kattrs[i].attr; - } - - lbt_group.attrs = lbt_attrs; - - lbt_kobj = kobject_create_and_add("lbt", parent); - if (!lbt_kobj) - goto out; - - if (sysfs_create_group(lbt_kobj, &lbt_group)) - goto out; - - return 0; - -out: - free_lbt_sysfs(); - - pr_err("LBT(%s): failed to create sysfs node\n", __func__); - return -EINVAL; -} - -/****************************************************************/ -/* Initialization */ -/****************************************************************/ -static void free_lbt_overutil(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { - if (per_cpu(lbt_overutil, cpu)) - kfree(per_cpu(lbt_overutil, cpu)); - } -} - -static int alloc_lbt_overutil(void) -{ - int cpu, depth = get_topology_depth(); - - for_each_possible_cpu(cpu) { - struct lbt_overutil *ou = kzalloc(sizeof(struct lbt_overutil) * - (depth + 1), GFP_KERNEL); - if (!ou) - goto fail_alloc; - - per_cpu(lbt_overutil, cpu) = ou; - } - return 0; - -fail_alloc: - free_lbt_overutil(); - return -ENOMEM; -} - -static int set_lbt_overutil(int level, const char *mask, int ratio) -{ - struct lbt_overutil *ou; - struct cpumask cpus; - bool top, overlap = false; - int cpu; - - cpulist_parse(mask, &cpus); - cpumask_and(&cpus, &cpus, cpu_possible_mask); - if (!cpumask_weight(&cpus)) - return -ENODEV; - - /* If sibling cpus is same with possible cpus, it is top level */ - top = cpumask_equal(&cpus, cpu_possible_mask); - - /* If this level is overlapped with prev level, disable this level */ - if (level > 0) { - ou = per_cpu(lbt_overutil, cpumask_first(&cpus)); - overlap = cpumask_equal(&cpus, &ou[level-1].cpus); - } - - for_each_cpu(cpu, &cpus) { - ou = per_cpu(lbt_overutil, cpu); - cpumask_copy(&ou[level].cpus, &cpus); - ou[level].ratio = overlap ? DISABLE_OU : ratio; - ou[level].top = top; - } - - return 0; -} - -static int parse_lbt_overutil(struct device_node *dn) -{ - struct device_node *lbt, *ou; - int level, depth = get_topology_depth(); - int ret = 0; - - lbt = of_get_child_by_name(dn, "lbt"); - if (!lbt) - return -ENODEV; - - for (level = 0; level <= depth; level++) { - char name[20]; - const char *mask[NR_CPUS]; - int ratio[NR_CPUS]; - int i, proplen; - - snprintf(name, sizeof(name), "overutil-level%d", level); - ou = of_get_child_by_name(lbt, name); - if (!ou) { - ret = -ENODEV; - goto out; - } - - proplen = of_property_count_strings(ou, "cpus"); - if ((proplen < 0) || (proplen != of_property_count_u32_elems(ou, "ratio"))) { - of_node_put(ou); - ret = -ENODEV; - goto out; - } - - of_property_read_string_array(ou, "cpus", mask, proplen); - of_property_read_u32_array(ou, "ratio", ratio, proplen); - of_node_put(ou); - - for (i = 0; i < proplen; i++) { - ret = set_lbt_overutil(level, mask[i], ratio[i]); - if (ret) - goto out; - } - } - -out: - of_node_put(lbt); - return ret; -} - -static int __init init_lbt(void) -{ - struct device_node *dn; - int ret; - - dn = of_find_node_by_path("/cpus/ehmp"); - if (!dn) - return 0; - - ret = alloc_lbt_overutil(); - if (ret) { - pr_err("Failed to allocate lbt_overutil\n"); - goto out; - } - - ret = parse_lbt_overutil(dn); - if (ret) { - pr_err("Failed to parse lbt_overutil\n"); - free_lbt_overutil(); - goto out; - } - -out: - of_node_put(dn); - return ret; -} -pure_initcall(init_lbt); /********************************************************************** * Global boost * **********************************************************************/ diff --git a/kernel/sched/ems/ems.h b/kernel/sched/ems/ems.h index e6a75a4bc1a6..7288c16d4f49 100644 --- a/kernel/sched/ems/ems.h +++ b/kernel/sched/ems/ems.h @@ -29,10 +29,15 @@ static inline int group_balancing(struct task_struct *p) { return -1; } #ifdef CONFIG_SCHED_EMS extern int exynos_wakeup_balance(struct task_struct *p, int sd_flag, int sync); +extern int __init lbt_sysfs_init(struct kobject *parent); #else static inline int exynos_wakeup_balance(struct task_struct *p, int sd_flag, int sync) { return -1; } +static inline int __init lbt_sysfs_init(struct kobject *parent) +{ + return 0; +} #endif diff --git a/kernel/sched/ems/lbt.c b/kernel/sched/ems/lbt.c new file mode 100644 index 000000000000..d9a11b080867 --- /dev/null +++ b/kernel/sched/ems/lbt.c @@ -0,0 +1,361 @@ +/* + * Load Balance Trigger (LBT) for Exynos Mobile Scheduler (EMS) + * + * Copyright (C) 2018 Samsung Electronics Co., Ltd + * LEE DAEYEONG + */ + +#include +#include +#include +#include +#include + +#include + +#include "../sched.h" +#include "../tune.h" +#include "./ems.h" + +/****************************************************************/ +/* Load Balance Trigger */ +/****************************************************************/ +#define DISABLE_OU -1 +#define DEFAULT_OU_RATIO 80 + +struct lbt_overutil { + bool top; + struct cpumask cpus; + unsigned long capacity; + int ratio; +}; +DEFINE_PER_CPU(struct lbt_overutil *, lbt_overutil); + +static inline int get_topology_depth(void) +{ + struct sched_domain *sd; + + for_each_domain(0, sd) { + if (sd->parent == NULL) + return sd->level; + } + + return -1; +} + +static inline int get_last_level(struct lbt_overutil *ou) +{ + int level; + + for (level = 0; &ou[level] != NULL; level++) { + if (ou[level].top == true) + return level; + } + + return -1; +} + +/****************************************************************/ +/* External APIs */ +/****************************************************************/ +bool lbt_overutilized(int cpu, int level) +{ + struct lbt_overutil *ou = per_cpu(lbt_overutil, cpu); + bool overutilized; + + if (!ou) + return false; + + overutilized = (cpu_util(cpu) > ou[level].capacity) ? true : false; + + if (overutilized) + trace_ehmp_lbt_overutilized(cpu, level, cpu_util(cpu), + ou[level].capacity, overutilized); + + return overutilized; +} + +void update_lbt_overutil(int cpu, unsigned long capacity) +{ + struct lbt_overutil *ou = per_cpu(lbt_overutil, cpu); + int level, last = get_last_level(ou); + + for (level = 0; level <= last; level++) { + if (ou[level].ratio == DISABLE_OU) + continue; + + ou[level].capacity = (capacity * ou[level].ratio) / 100; + } +} + +/****************************************************************/ +/* SYSFS */ +/****************************************************************/ +#define lbt_attr_init(_attr, _name, _mode, _show, _store) \ + sysfs_attr_init(&_attr.attr); \ + _attr.attr.name = _name; \ + _attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(_mode); \ + _attr.show = _show; \ + _attr.store = _store; + +static struct kobject *lbt_kobj; +static struct attribute **lbt_attrs; +static struct kobj_attribute *lbt_kattrs; +static struct attribute_group lbt_group; + +static ssize_t show_overutil_ratio(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct lbt_overutil *ou = per_cpu(lbt_overutil, 0); + int level = attr - lbt_kattrs; + int cpu, ret = 0; + + for_each_possible_cpu(cpu) { + ou = per_cpu(lbt_overutil, cpu); + + if (ou[level].ratio == DISABLE_OU) + continue; + + ret += sprintf(buf + ret, "cpu%d ratio:%3d capacity:%4lu\n", + cpu, ou[level].ratio, ou[level].capacity); + } + + return ret; +} + +static ssize_t store_overutil_ratio(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + struct lbt_overutil *ou; + unsigned long capacity; + int level = attr - lbt_kattrs; + int cpu, ratio; + + if (sscanf(buf, "%d %d", &cpu, &ratio) != 2) + return -EINVAL; + + /* Check cpu is possible */ + if (!cpumask_test_cpu(cpu, cpu_possible_mask)) + return -EINVAL; + ou = per_cpu(lbt_overutil, cpu); + + /* If ratio is outrage, disable overutil */ + if (ratio < 0 || ratio > 100) + ratio = DEFAULT_OU_RATIO; + + for_each_cpu(cpu, &ou[level].cpus) { + ou = per_cpu(lbt_overutil, cpu); + if (ou[level].ratio == DISABLE_OU) + continue; + + ou[level].ratio = ratio; + capacity = capacity_orig_of(cpu); + update_lbt_overutil(cpu, capacity); + } + + return count; +} + +static int alloc_lbt_sysfs(int size) +{ + if (size < 0) + return -EINVAL; + + lbt_attrs = kzalloc(sizeof(struct attribute *) * (size + 1), + GFP_KERNEL); + if (!lbt_attrs) + goto fail_alloc; + + lbt_kattrs = kzalloc(sizeof(struct kobj_attribute) * (size), + GFP_KERNEL); + if (!lbt_kattrs) + goto fail_alloc; + + return 0; + +fail_alloc: + kfree(lbt_attrs); + kfree(lbt_kattrs); + + pr_err("LBT(%s): failed to alloc sysfs attrs\n", __func__); + return -ENOMEM; +} + +int __init lbt_sysfs_init(struct kobject *parent) +{ + int depth = get_topology_depth(); + int i; + + if (alloc_lbt_sysfs(depth + 1)) + goto out; + + for (i = 0; i <= depth; i++) { + char buf[20]; + char *name; + + sprintf(buf, "overutil_ratio_level%d", i); + name = kstrdup(buf, GFP_KERNEL); + if (!name) + goto out; + + lbt_attr_init(lbt_kattrs[i], name, 0644, + show_overutil_ratio, store_overutil_ratio); + lbt_attrs[i] = &lbt_kattrs[i].attr; + } + + lbt_group.attrs = lbt_attrs; + + lbt_kobj = kobject_create_and_add("lbt", parent); + if (!lbt_kobj) + goto out; + + if (sysfs_create_group(lbt_kobj, &lbt_group)) + goto out; + + return 0; + +out: + kfree(lbt_attrs); + kfree(lbt_kattrs); + + pr_err("LBT(%s): failed to create sysfs node\n", __func__); + return -EINVAL; +} + +/****************************************************************/ +/* Initialization */ +/****************************************************************/ +static void free_lbt_overutil(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + if (per_cpu(lbt_overutil, cpu)) + kfree(per_cpu(lbt_overutil, cpu)); + } +} + +static int alloc_lbt_overutil(void) +{ + int cpu, depth = get_topology_depth(); + + for_each_possible_cpu(cpu) { + struct lbt_overutil *ou = kzalloc(sizeof(struct lbt_overutil) * + (depth + 1), GFP_KERNEL); + if (!ou) + goto fail_alloc; + + per_cpu(lbt_overutil, cpu) = ou; + } + return 0; + +fail_alloc: + free_lbt_overutil(); + return -ENOMEM; +} + +static int set_lbt_overutil(int level, const char *mask, int ratio) +{ + struct lbt_overutil *ou; + struct cpumask cpus; + bool top, overlap = false; + int cpu; + + cpulist_parse(mask, &cpus); + cpumask_and(&cpus, &cpus, cpu_possible_mask); + if (!cpumask_weight(&cpus)) + return -ENODEV; + + /* If sibling cpus is same with possible cpus, it is top level */ + top = cpumask_equal(&cpus, cpu_possible_mask); + + /* If this level is overlapped with prev level, disable this level */ + if (level > 0) { + ou = per_cpu(lbt_overutil, cpumask_first(&cpus)); + overlap = cpumask_equal(&cpus, &ou[level-1].cpus); + } + + for_each_cpu(cpu, &cpus) { + ou = per_cpu(lbt_overutil, cpu); + cpumask_copy(&ou[level].cpus, &cpus); + ou[level].ratio = overlap ? DISABLE_OU : ratio; + ou[level].top = top; + } + + return 0; +} + +static int parse_lbt_overutil(struct device_node *dn) +{ + struct device_node *lbt, *ou; + int level, depth = get_topology_depth(); + int ret = 0; + + lbt = of_get_child_by_name(dn, "lbt"); + if (!lbt) + return -ENODEV; + + for (level = 0; level <= depth; level++) { + char name[20]; + const char *mask[NR_CPUS]; + int ratio[NR_CPUS]; + int i, proplen; + + snprintf(name, sizeof(name), "overutil-level%d", level); + ou = of_get_child_by_name(lbt, name); + if (!ou) { + ret = -ENODEV; + goto out; + } + + proplen = of_property_count_strings(ou, "cpus"); + if ((proplen < 0) || (proplen != of_property_count_u32_elems(ou, "ratio"))) { + of_node_put(ou); + ret = -ENODEV; + goto out; + } + + of_property_read_string_array(ou, "cpus", mask, proplen); + of_property_read_u32_array(ou, "ratio", ratio, proplen); + of_node_put(ou); + + for (i = 0; i < proplen; i++) { + ret = set_lbt_overutil(level, mask[i], ratio[i]); + if (ret) + goto out; + } + } + +out: + of_node_put(lbt); + return ret; +} + +static int __init init_lbt(void) +{ + struct device_node *dn; + int ret; + + dn = of_find_node_by_path("/cpus/ems"); + if (!dn) + return 0; + + ret = alloc_lbt_overutil(); + if (ret) { + pr_err("Failed to allocate lbt_overutil\n"); + goto out; + } + + ret = parse_lbt_overutil(dn); + if (ret) { + pr_err("Failed to parse lbt_overutil\n"); + free_lbt_overutil(); + goto out; + } + +out: + of_node_put(dn); + return ret; +} +pure_initcall(init_lbt);