__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
*/
--- /dev/null
+/*
+ * Performance CPU Finder
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd
+ * Park Bumgyu <bumgyu.park@samsung.com>
+ */
+
+#include <trace/events/ems.h>
+
+#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;
+}