From: Daeyeong Lee Date: Mon, 25 Jun 2018 11:07:30 +0000 (+0900) Subject: [COMMON] sched: ems: Modify select_eco_cpu algorithm X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=b38ce2ba328025ff264123a8c56d1abde5265c2b;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [COMMON] sched: ems: Modify select_eco_cpu algorithm - Previous select_eco_cpu function choose mininum capacity cpu as energy cpu as far as possible. But there is many case that bigger cpu is better at power efficiency. So modify select_eco_cpu function to search all active core. Change-Id: Ibe3d2a9729e794ac395780fe4d5875f31575c972 Signed-off-by: Daeyeong Lee --- diff --git a/include/trace/events/ems.h b/include/trace/events/ems.h index c17b9fcbc26b..d5f7529a8d08 100644 --- a/include/trace/events/ems.h +++ b/include/trace/events/ems.h @@ -20,11 +20,10 @@ */ TRACE_EVENT(ems_select_eco_cpu, - TP_PROTO(struct task_struct *p, int eco_cpu, int prev_cpu, int best_cpu, int backup_cpu, - unsigned int prev_energy, unsigned int best_energy, unsigned int backup_energy), + TP_PROTO(struct task_struct *p, int eco_cpu, int prev_cpu, int best_cpu, + unsigned int prev_energy, unsigned int best_energy), - TP_ARGS(p, eco_cpu, prev_cpu, best_cpu, backup_cpu, - prev_energy, best_energy, backup_energy), + TP_ARGS(p, eco_cpu, prev_cpu, best_cpu, prev_energy, best_energy), TP_STRUCT__entry( __array( char, comm, TASK_COMM_LEN ) @@ -32,10 +31,8 @@ TRACE_EVENT(ems_select_eco_cpu, __field( int, eco_cpu ) __field( int, prev_cpu ) __field( int, best_cpu ) - __field( int, backup_cpu ) __field( unsigned int, prev_energy ) __field( unsigned int, best_energy ) - __field( unsigned int, backup_energy ) ), TP_fast_assign( @@ -44,17 +41,14 @@ TRACE_EVENT(ems_select_eco_cpu, __entry->eco_cpu = eco_cpu; __entry->prev_cpu = prev_cpu; __entry->best_cpu = best_cpu; - __entry->backup_cpu = backup_cpu; __entry->prev_energy = prev_energy; __entry->best_energy = best_energy; - __entry->backup_energy = backup_energy; ), - TP_printk("comm=%s pid=%d eco_cpu=%d prev_cpu=%d best_cpu=%d backup_cpu=%d " - "prev_energy=%u best_energy=%u backup_energy=%u", - __entry->comm, __entry->pid, - __entry->eco_cpu, __entry->prev_cpu, __entry->best_cpu, __entry->backup_cpu, - __entry->prev_energy, __entry->best_energy, __entry->backup_energy) + TP_printk("comm=%s pid=%d eco_cpu=%d prev_cpu=%d best_cpu=%d " + "prev_energy=%u best_energy=%u", + __entry->comm, __entry->pid, __entry->eco_cpu, __entry->prev_cpu, + __entry->best_cpu, __entry->prev_energy, __entry->best_energy) ); /* diff --git a/kernel/sched/ems/energy.c b/kernel/sched/ems/energy.c index 03a22f424b2f..5b98131bc3db 100644 --- a/kernel/sched/ems/energy.c +++ b/kernel/sched/ems/energy.c @@ -55,97 +55,9 @@ unsigned int get_cpu_max_capacity(unsigned int cpu) */ struct eco_env { struct task_struct *p; - int prev_cpu; - int best_cpu; - int backup_cpu; }; -static void find_eco_target(struct eco_env *eenv) -{ - struct task_struct *p = eenv->p; - unsigned long best_min_cap_orig = ULONG_MAX; - unsigned long backup_min_cap_orig = ULONG_MAX; - unsigned long best_spare_cap = 0; - int backup_idle_cstate = INT_MAX; - int best_cpu = -1; - int backup_cpu = -1; - int cpu; - - /* - * It is meaningless to find an energy cpu when the energy table is - * not created or has not been created yet. - */ - if (!per_cpu(energy_table, eenv->prev_cpu).nr_states) - return; - - 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, new_util; - - wake_util = cpu_util_wake(cpu, p); - new_util = wake_util + task_util_est(p); - new_util = max(new_util, boosted_task_util(p)); - - /* checking prev cpu is meaningless */ - if (eenv->prev_cpu == cpu) - continue; - - /* skip over-capacity cpu */ - if (new_util > capacity_orig) - continue; - - /* - * Backup target) shallowest idle cpu among min-cap cpu - * - * In general, assigning a task to an idle cpu is - * disadvantagerous in energy. To minimize the energy increase - * associated with selecting idle cpu, choose a cpu that is - * in the lowest performance and shallowest idle state. - */ - if (idle_cpu(cpu)) { - int idle_idx; - - if (backup_min_cap_orig < capacity_orig) - continue; - - idle_idx = idle_get_state_idx(cpu_rq(cpu)); - if (backup_idle_cstate <= idle_idx) - continue; - - backup_min_cap_orig = capacity_orig; - backup_idle_cstate = idle_idx; - backup_cpu = cpu; - continue; - } - - /* - * Best target) biggest spare cpu among min-cap cpu - * - * Select the cpu with the biggest spare capacity to maintain - * frequency as possible without waking up idle cpu. Also, to - * maximize the use of energy-efficient cpu, we choose the - * lowest performance cpu. - */ - if (best_min_cap_orig < capacity_orig) - continue; - - if (best_spare_cap > (capacity_orig - new_util)) - continue; - - best_spare_cap = capacity_orig - new_util; - best_min_cap_orig = capacity_orig; - best_cpu = cpu; - } - - rcu_read_unlock(); - - eenv->best_cpu = best_cpu; - eenv->backup_cpu = backup_cpu; -} - static unsigned int calculate_energy(struct task_struct *p, int target_cpu) { unsigned long util[NR_CPUS] = {0, }; @@ -223,60 +135,98 @@ static unsigned int calculate_energy(struct task_struct *p, int target_cpu) return total_energy; } +static int find_min_util_cpu(struct cpumask *mask, unsigned long task_util) +{ + unsigned long min_util = ULONG_MAX; + int min_util_cpu = -1; + int cpu; + + /* Find energy efficient cpu in each coregroup. */ + for_each_cpu_and(cpu, mask, cpu_active_mask) { + unsigned long capacity_orig = capacity_orig_of(cpu); + unsigned long util = cpu_util(cpu); + + /* Skip over-capacity cpu */ + if (util + task_util > capacity_orig) + continue; + + /* + * Choose min util cpu within coregroup as candidates. + * Choosing a min util cpu is most likely to handle + * wake-up task without increasing the frequecncy. + */ + if (util < min_util) { + min_util = util; + min_util_cpu = cpu; + } + } + + return min_util_cpu; +} + static int select_eco_cpu(struct eco_env *eenv) { - unsigned int prev_energy, best_energy, backup_energy; - unsigned int temp_energy; - int temp_cpu; + unsigned long task_util = task_util_est(eenv->p); + unsigned int best_energy = UINT_MAX; + unsigned int prev_energy; int eco_cpu = eenv->prev_cpu; - int margin; - - prev_energy = calculate_energy(eenv->p, eenv->prev_cpu); + int cpu, best_cpu = -1; /* - * find_eco_target() may not find best or backup cup. Ignore unfound - * cpu, and if both are found, select a cpu that consumes less energy - * when assigning task. + * It is meaningless to find an energy cpu when the energy table is + * not created or has not been created yet. */ - best_energy = backup_energy = UINT_MAX; + if (!per_cpu(energy_table, eenv->prev_cpu).nr_states) + return eenv->prev_cpu; - if (cpu_selected(eenv->best_cpu)) - best_energy = calculate_energy(eenv->p, eenv->best_cpu); + for_each_cpu(cpu, cpu_active_mask) { + struct cpumask mask; + int energy_cpu; - if (cpu_selected(eenv->backup_cpu)) - backup_energy = calculate_energy(eenv->p, eenv->backup_cpu); + if (cpu != cpumask_first(cpu_coregroup_mask(cpu))) + continue; - if (best_energy < backup_energy) { - temp_energy = best_energy; - temp_cpu = eenv->best_cpu; - } else { - temp_energy = backup_energy; - temp_cpu = eenv->backup_cpu; - } + cpumask_and(&mask, cpu_coregroup_mask(cpu), tsk_cpus_allowed(eenv->p)); + /* + * Checking prev cpu is meaningless, because the energy of prev cpu + * will be compared to best cpu at last + */ + cpumask_clear_cpu(eenv->prev_cpu, &mask); + if (cpumask_empty(&mask)) + continue; - /* - * Compare prev cpu to target cpu among best and backup cpu to determine - * whether keeping the task on PREV CPU and sending the task to TARGET - * CPU is beneficial for energy. - */ - if (temp_energy < prev_energy) { /* - * Compute the dead-zone margin used to prevent too many task - * migrations with negligible energy savings. - * An energy saving is considered meaningful if it reduces the - * energy consumption of PREV CPU candidate by at least ~1.56%. + * Select the best target, which is expected to consume the + * lowest energy among the min util cpu for each coregroup. */ - margin = prev_energy >> 6; - if ((prev_energy - temp_energy) < margin) - goto out; + energy_cpu = find_min_util_cpu(&mask, task_util); + if (cpu_selected(energy_cpu)) { + unsigned int energy = calculate_energy(eenv->p, energy_cpu); - eco_cpu = temp_cpu; + if (energy < best_energy) { + best_energy = energy; + best_cpu = energy_cpu; + } + } } -out: - trace_ems_select_eco_cpu(eenv->p, eco_cpu, - eenv->prev_cpu, eenv->best_cpu, eenv->backup_cpu, - prev_energy, best_energy, backup_energy); + if (!cpu_selected(best_cpu)) + return -1; + + /* + * Compare prev cpu to best cpu to determine whether keeping the task + * on PREV CPU and sending the task to BEST CPU is beneficial for + * energy. + * An energy saving is considered meaningful if it reduces the energy + * consumption of PREV CPU candidate by at least ~1.56%. + */ + prev_energy = calculate_energy(eenv->p, eenv->prev_cpu); + if (prev_energy - (prev_energy >> 6) > best_energy) + eco_cpu = best_cpu; + + trace_ems_select_eco_cpu(eenv->p, eco_cpu, eenv->prev_cpu, best_cpu, + prev_energy, best_energy); + return eco_cpu; } @@ -287,8 +237,6 @@ int select_energy_cpu(struct task_struct *p, int prev_cpu, int sd_flag, int sync struct eco_env eenv = { .p = p, .prev_cpu = prev_cpu, - .best_cpu = -1, - .backup_cpu = -1, }; if (!sched_feat(ENERGY_AWARE)) @@ -320,13 +268,9 @@ int select_energy_cpu(struct task_struct *p, int prev_cpu, int sd_flag, int sync /* * Find eco-friendly target. - * After selecting the best and backup cpu according to strategy, we - * choose a cpu that is energy efficient compared to prev cpu. + * After selecting the best cpu according to strategy, + * we choose a cpu that is energy efficient compared to prev cpu. */ - find_eco_target(&eenv); - if (eenv.best_cpu < 0 && eenv.backup_cpu < 0) - return -1; - return select_eco_cpu(&eenv); }