From: Park Bumgyu Date: Fri, 23 Mar 2018 05:08:55 +0000 (+0900) Subject: sched: ems: support PCF(Performance CPU Finder) X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=afbc62de6e74e748f0774e5579e9750f6ea37bac;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git sched: ems: support PCF(Performance CPU Finder) PCF(Performance CPU Finder) provides the ability to find the highest performance cpu at any given moment. Currently, it is composed of a selection algorithm based on distributed processing. Change-Id: Iaaaedd12fee9fe0829db9dd1f7cb72993581a51e Signed-off-by: Park Bumgyu --- diff --git a/include/trace/events/ems.h b/include/trace/events/ems.h index 6b98fcf45624..e1831114520c 100644 --- a/include/trace/events/ems.h +++ b/include/trace/events/ems.h @@ -42,6 +42,34 @@ TRACE_EVENT(ems_wakeup_balance, __entry->comm, __entry->pid, __entry->target_cpu, __entry->state) ); +/* + * Tracepoint for performance cpu finder + */ +TRACE_EVENT(ems_select_perf_cpu, + + TP_PROTO(struct task_struct *p, int best_cpu, int backup_cpu), + + TP_ARGS(p, best_cpu, backup_cpu), + + TP_STRUCT__entry( + __array( char, comm, TASK_COMM_LEN ) + __field( pid_t, pid ) + __field( int, best_cpu ) + __field( int, backup_cpu ) + ), + + TP_fast_assign( + memcpy(__entry->comm, p->comm, TASK_COMM_LEN); + __entry->pid = p->pid; + __entry->best_cpu = best_cpu; + __entry->backup_cpu = backup_cpu; + ), + + TP_printk("comm=%s pid=%d best_cpu=%d backup_cpu=%d", + __entry->comm, __entry->pid, __entry->best_cpu, __entry->backup_cpu) +); + + /* * Tracepoint for selection of boost cpu */ diff --git a/kernel/sched/ems/Makefile b/kernel/sched/ems/Makefile index 0771a344916c..bbfe44f9efbe 100644 --- a/kernel/sched/ems/Makefile +++ b/kernel/sched/ems/Makefile @@ -1,4 +1,5 @@ -obj-y += core.o global_boost.o lbt.o ontime.o +obj-y += core.o pcf.o global_boost.o lbt.o ontime.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/ems.h b/kernel/sched/ems/ems.h index 9cf27e760746..227e97067a59 100644 --- a/kernel/sched/ems/ems.h +++ b/kernel/sched/ems/ems.h @@ -18,6 +18,7 @@ extern struct kobject *ems_kobj; extern int ontime_task_wakeup(struct task_struct *p); +extern int select_perf_cpu(struct task_struct *p); extern int global_boosting(struct task_struct *p); extern bool lbt_bring_overutilize(int cpu, struct task_struct *p); diff --git a/kernel/sched/ems/pcf.c b/kernel/sched/ems/pcf.c new file mode 100644 index 000000000000..119c5b51e62a --- /dev/null +++ b/kernel/sched/ems/pcf.c @@ -0,0 +1,107 @@ +/* + * Performance CPU Finder + * + * Copyright (C) 2018 Samsung Electronics Co., Ltd + * Park Bumgyu + */ + +#include + +#include "../sched.h" + +static int cpu_util_wake(int cpu, struct task_struct *p) +{ + unsigned long util, capacity; + + /* Task has no contribution or is new */ + if (cpu != task_cpu(p) || !p->se.avg.last_update_time) + return cpu_util(cpu); + + capacity = capacity_orig_of(cpu); + util = max_t(long, cpu_rq(cpu)->cfs.avg.util_avg - p->se.avg.util_avg, 0); + + return (util >= capacity) ? capacity : util; +} + +/* + * Currently, PCF is composed of a selection algorithm based on distributed + * processing, for example, selecting idle cpu or cpu with biggest spare + * capacity. Although the current algorithm may suffice, it is necessary to + * examine a selection algorithm considering cache hot and migration cost. + */ +int select_perf_cpu(struct task_struct *p) +{ + int cpu; + unsigned long best_perf_cap_orig = 0; + unsigned long max_spare_cap = 0; + int best_perf_cstate = INT_MAX; + int best_perf_cpu = -1; + int backup_cpu = -1; + + rcu_read_lock(); + + for_each_cpu_and(cpu, &p->cpus_allowed, cpu_active_mask) { + unsigned long capacity_orig = capacity_orig_of(cpu); + unsigned long wake_util; + + /* + * A) Find best performance cpu. + * + * If the impact of cache hot and migration cost are excluded, + * distributed processing is the best way to achieve performance. + * To maximize performance, the idle cpu with the highest + * performance is selected first. If there are more than two idle + * cpus with the highest performance, choose the cpu with the + * shallowest idle state for fast reactivity. + */ + if (idle_cpu(cpu)) { + int idle_idx = idle_get_state_idx(cpu_rq(cpu)); + + /* find biggest capacity cpu */ + if (capacity_orig < best_perf_cap_orig) + continue; + + /* + * if we find a better-performing cpu, re-initialize + * best_perf_cstate + */ + if (capacity_orig > best_perf_cap_orig) { + best_perf_cap_orig = capacity_orig; + best_perf_cstate = INT_MAX; + } + + /* find shallowest idle state cpu */ + if (idle_idx >= best_perf_cstate) + continue; + + /* Keep track of best idle CPU */ + best_perf_cstate = idle_idx; + best_perf_cpu = cpu; + continue; + } + + /* + * B) Find backup performance cpu. + * + * Backup cpu also adopts distributed processing. In the absence + * of idle cpu, it is difficult to expect reactivity, so select + * the cpu with the biggest spare capacity to handle the most + * computations. Since a high performance cpu has a large capacity, + * cpu having a high performance is likely to be selected. + */ + wake_util = cpu_util_wake(cpu, p); + if ((capacity_orig - wake_util) < max_spare_cap) + continue; + + max_spare_cap = capacity_orig - wake_util; + backup_cpu = cpu; + } + + rcu_read_unlock(); + + trace_ems_select_perf_cpu(p, best_perf_cpu, backup_cpu); + if (best_perf_cpu == -1) + return backup_cpu; + + return best_perf_cpu; +}