sched: ems: add wakeup balance
authorPark Bumgyu <bumgyu.park@samsung.com>
Fri, 23 Mar 2018 02:13:19 +0000 (11:13 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:33:25 +0000 (17:33 +0900)
Wakeup balance is a scheme that determines which cpu to assign waking
up task or new task to. In fact, it corresponds to the main stream of
EMS. The current patch is skeleton code, and each function will be
reflected.

Change-Id: Ib176e03c94af2d45476bb8b9747b53167e8ff2a9
Signed-off-by: Park Bumgyu <bumgyu.park@samsung.com>
include/trace/events/ems.h
kernel/sched/ems/Makefile
kernel/sched/ems/core.c [new file with mode: 0644]
kernel/sched/ems/ehmp.c
kernel/sched/ems/ems.h
kernel/sched/ems/global_boost.c [new file with mode: 0644]
kernel/sched/ems/st_addon.c [new file with mode: 0644]
kernel/sched/fair.c

index 49598ef756242aad002c0ad1c662d887784978f9..56ca386a25b05d4afc1fbadb8aae4aafd6ad3f7e 100644 (file)
 #include <linux/sched.h>
 #include <linux/tracepoint.h>
 
+/*
+ * Tracepoint for wakeup balance
+ */
+TRACE_EVENT(ems_wakeup_balance,
+
+       TP_PROTO(struct task_struct *p, int target_cpu, char *state),
+
+       TP_ARGS(p, target_cpu, state),
+
+       TP_STRUCT__entry(
+               __array(        char,           comm,   TASK_COMM_LEN   )
+               __field(        pid_t,          pid                     )
+               __field(        int,            target_cpu              )
+               __array(        char,           state,          30      )
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->comm, p->comm, TASK_COMM_LEN);
+               __entry->pid            = p->pid;
+               __entry->target_cpu     = target_cpu;
+               memcpy(__entry->state, state, 30);
+       ),
+
+       TP_printk("comm=%s pid=%d target_cpu=%d state=%s",
+                 __entry->comm, __entry->pid, __entry->target_cpu, __entry->state)
+);
+
 /*
  * Tracepoint for selection of boost cpu
  */
index 5a981b8e53c494c3c2cb35ed77dcd326f84d755d..6c5f5a421c5c5a393f7ff3f69e19fe48f4e4024c 100644 (file)
@@ -1,2 +1,4 @@
+obj-y += core.o global_boost.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/core.c b/kernel/sched/ems/core.c
new file mode 100644 (file)
index 0000000..8ab7905
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Core Exynos Mobile Scheduler
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd
+ * Park Bumgyu <bumgyu.park@samsung.com>
+ */
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/ems.h>
+
+#include "ems.h"
+#include "../sched.h"
+
+static int select_energy_cpu(struct task_struct *p)
+{
+       return -1;
+}
+
+static int select_proper_cpu(struct task_struct *p)
+{
+       return -1;
+}
+
+#define cpu_selected(cpu)      (cpu >= 0)
+
+extern void sync_entity_load_avg(struct sched_entity *se);
+
+int exynos_wakeup_balance(struct task_struct *p, int sd_flag, int sync)
+{
+       int target_cpu = -1;
+       char state[30] = "fail";
+
+       /*
+        * Since the utilization of a task is accumulated before sleep, it updates
+        * the utilization to determine which cpu the task will be assigned to.
+        * Exclude new task.
+        */
+       if (!(sd_flag & SD_BALANCE_FORK))
+               sync_entity_load_avg(&p->se);
+
+       /*
+        * Priority 1 : ontime task
+        *
+        * If task which has more utilization than threshold wakes up, the task is
+        * classified as "ontime task" and assigned to performance cpu. Conversely,
+        * if heavy task that has been classified as ontime task sleeps for a long
+        * time and utilization becomes small, it is excluded from ontime task and
+        * is no longer guaranteed to operate on performance cpu.
+        *
+        * Ontime task is very sensitive to performance because it is usually the
+        * main task of application. Therefore, it has the highest priority.
+        */
+       target_cpu = ontime_task_wakeup(p);
+       if (cpu_selected(target_cpu)) {
+               strcpy(state, "ontime migration");
+               goto out;
+       }
+
+       /*
+        * Priority 2 : prefer-perf
+        *
+        * Prefer-perf is a function that operates on cgroup basis managed by
+        * schedtune. When perfer-perf is set to 1, the tasks in the group are
+        * preferentially assigned to the performance cpu.
+        *
+        * It has a high priority because it is a function that is turned on
+        * temporarily in scenario requiring reactivity(touch, app laucning).
+        */
+       target_cpu = prefer_perf_cpu(p);
+       if (cpu_selected(target_cpu)) {
+               strcpy(state, "prefer-perf");
+               goto out;
+       }
+
+       /*
+        * Priority 3 : global boosting
+        *
+        * Global boost is a function that preferentially assigns all tasks in the
+        * system to the performance cpu. Unlike prefer-perf, which targets only
+        * group tasks, global boost targets all tasks. So, it maximizes performance
+        * cpu utilization.
+        *
+        * Typically, prefer-perf operates on groups that contains UX related tasks,
+        * such as "top-app" or "foreground", so that major tasks are likely to be
+        * assigned to performance cpu. On the other hand, global boost assigns
+        * all tasks to performance cpu, which is not as effective as perfer-perf.
+        * For this reason, global boost has a lower priority than prefer-perf.
+        */
+       target_cpu = global_boosting(p);
+       if (cpu_selected(target_cpu)) {
+               strcpy(state, "global boosting");
+               goto out;
+       }
+
+       /*
+        * Priority 4 : group balancing
+        */
+       target_cpu = group_balancing(p);
+       if (cpu_selected(target_cpu)) {
+               strcpy(state, "group balancing");
+               goto out;
+       }
+
+       /*
+        * Priority 5 : prefer-idle
+        *
+        * Prefer-idle is a function that operates on cgroup basis managed by
+        * schedtune. When perfer-idle is set to 1, the tasks in the group are
+        * preferentially assigned to the idle cpu.
+        *
+        * Prefer-idle has a smaller performance impact than the above. Therefore
+        * it has a relatively low priority.
+        */
+       target_cpu = prefer_idle_cpu(p);
+       if (cpu_selected(target_cpu)) {
+               strcpy(state, "prefer-idle");
+               goto out;
+       }
+
+       /*
+        * Priority 6 : energy cpu
+        *
+        * A scheduling scheme based on cpu energy, find the least power consumption
+        * cpu referring energy table when assigning task.
+        */
+       target_cpu = select_energy_cpu(p);
+       if (cpu_selected(target_cpu)) {
+               strcpy(state, "energy cpu");
+               goto out;
+       }
+
+       /*
+        * Priority 7 : proper cpu
+        */
+       target_cpu = select_proper_cpu(p);
+       if (cpu_selected(target_cpu))
+               strcpy(state, "proper cpu");
+
+out:
+       trace_ems_wakeup_balance(p, target_cpu, state);
+       return target_cpu;
+}
+
+struct kobject *ems_kobj;
+
+static int __init init_sysfs(void)
+{
+       ems_kobj = kobject_create_and_add("ems", kernel_kobj);
+
+       return 0;
+}
+core_initcall(init_sysfs);
index 7368f61a28f6bebd7c7bef9c6c44058a5b9b0c28..d0eb259fc1c70963e7ef40229c7a5af00c50cf67 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/ems.h>
 #include <linux/sched_energy.h>
 
-#define CREATE_TRACE_POINTS
 #include <trace/events/ems.h>
 
 #include "../sched.h"
@@ -1431,7 +1430,7 @@ success_unlock:
        return 0;
 }
 
-static int ontime_task_wakeup(struct task_struct *p)
+int ontime_task_wakeup(struct task_struct *p)
 {
        struct ontime_cond *cond;
        struct cpumask target_mask;
index 1ad0eb098216401f54e34b0fae2b0b7671125bbe..e6a75a4bc1a6658811b36e7660d55a73f8feeab0 100644 (file)
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
+extern struct kobject *ems_kobj;
+
+extern int ontime_task_wakeup(struct task_struct *p);
+extern int global_boosting(struct task_struct *p);
+
+#ifdef CONFIG_SCHED_TUNE
+extern int prefer_perf_cpu(struct task_struct *p);
+extern int prefer_idle_cpu(struct task_struct *p);
+extern int group_balancing(struct task_struct *p);
+#else
+static inline int prefer_perf_cpu(struct task_struct *p) { return -1; }
+static inline int prefer_idle_cpu(struct task_struct *p) { return -1; }
+static inline int group_balancing(struct task_struct *p) { return -1; }
+#endif
+
+#ifdef CONFIG_SCHED_EMS
+extern int
+exynos_wakeup_balance(struct task_struct *p, int sd_flag, int sync);
+#else
+static inline int
+exynos_wakeup_balance(struct task_struct *p, int sd_flag, int sync)
+{
+       return -1;
+}
+#endif
diff --git a/kernel/sched/ems/global_boost.c b/kernel/sched/ems/global_boost.c
new file mode 100644 (file)
index 0000000..e6eb4ce
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Global task boosting
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd
+ * Park Bumgyu <bumgyu.park@samsung.com>
+ */
+
+#include <linux/sched.h>
+
+int global_boosting(struct task_struct *p)
+{
+       return -1;
+}
diff --git a/kernel/sched/ems/st_addon.c b/kernel/sched/ems/st_addon.c
new file mode 100644 (file)
index 0000000..20c7d11
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SchedTune add-on features
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd
+ * Park Bumgyu <bumgyu.park@samsung.com>
+ */
+
+#include <linux/sched.h>
+
+/**********************************************************************
+ *                            Prefer Perf                             *
+ **********************************************************************/
+int prefer_perf_cpu(struct task_struct *p)
+{
+       return -1;
+}
+
+/**********************************************************************
+ *                            Prefer Idle                             *
+ **********************************************************************/
+int prefer_idle_cpu(struct task_struct *p)
+{
+       return -1;
+}
+
+/**********************************************************************
+ *                           Group balancer                           *
+ **********************************************************************/
+int group_balancing(struct task_struct *p)
+{
+       return -1;
+}
index 98681cdc98787eaee82f496123d617f6b5b4a4a5..8f74a808eadfa0115b195448fd37bda69e54b4c6 100644 (file)
@@ -40,6 +40,7 @@
 #include "sched.h"
 #include "tune.h"
 #include "walt.h"
+#include "ems/ems.h"
 
 /*
  * Targeted preemption latency for CPU-bound tasks:
@@ -7337,17 +7338,9 @@ static int find_energy_efficient_cpu(struct sched_domain *sd,
                eenv->max_cpu_count = EAS_CPU_BKP + 1;
 
                /* Find a cpu with sufficient capacity */
-               if (sched_feat(EXYNOS_MS)) {
-                       eenv->cpu[EAS_CPU_NXT].cpu_id = exynos_select_cpu(p,
-                                       &eenv->cpu[EAS_CPU_BKP].cpu_id,
-                                       boosted, prefer_idle);
-                       if (ontime_of(p)->flags == ONTIME)
-                               return eenv->cpu[EAS_CPU_NXT].cpu_id;
-               }
-               else
-                       eenv->cpu[EAS_CPU_NXT].cpu_id = find_best_target(p,
-                                       &eenv->cpu[EAS_CPU_BKP].cpu_id,
-                                       boosted, prefer_idle);
+               eenv->cpu[EAS_CPU_NXT].cpu_id = find_best_target(p,
+                               &eenv->cpu[EAS_CPU_BKP].cpu_id,
+                               boosted, prefer_idle);
 
                /* take note if no backup was found */
                if (eenv->cpu[EAS_CPU_BKP].cpu_id < 0)
@@ -7452,6 +7445,13 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
        int want_affine = 0;
        int want_energy = 0;
        int sync = wake_flags & WF_SYNC;
+       int target_cpu;
+
+       if (sched_feat(EXYNOS_MS)) {
+               target_cpu = exynos_wakeup_balance(p, sd_flag, sync);
+               if (target_cpu >= 0)
+                       return target_cpu;
+       }
 
        rcu_read_lock();