Received: by 10.213.65.68 with SMTP id h4csp258183imn; Tue, 20 Mar 2018 02:47:18 -0700 (PDT) X-Google-Smtp-Source: AG47ELspxBnkn+lgru0yLkAkpj5dy90r3ctTR6BKry1TUxdTZdRzy/sadcNoZ+/rkxDJ3E3va8iU X-Received: by 10.98.185.11 with SMTP id z11mr13014059pfe.153.1521539238415; Tue, 20 Mar 2018 02:47:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1521539238; cv=none; d=google.com; s=arc-20160816; b=ez5JJyy+w5n1fAXfXzHlxCI49CWFEzzHychCvbNWfd7p+G2n7IxYYmSk6GI1ezXVER 0r7Vs6IUUik3824DQ1i1nsP69nmKrdJ5f1EGhKONRf91vG3+TJaE1k04iJsIVagPyvfM 3pBAOB8EMcSHx4xfNElV7chAMFw+N77S+1x2hyv/OGIVtuweyfusWFtOnc92vp1c/icD vSHtP2aTHocAuHSzXOYgTs/5k/q/OobCKVVNxcjlJ1sbIh8Q+KxLSW01Xt3m+tHGzVfT JwDpt07FRNtMTpwI7+tyg3NAW5xVylyH03EtXedPXOKz5CAqikiBEhFGNPRaYYbO1KRu qXUQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=uj7rknqKwKUrD1kOC6gHLzochNh/QLdCbaVy3tK2BjM=; b=adJluKSuH5K6ZTu4NObrO7GVjWMDxObfB0cXjTFxCedJd3t75mjEefJtZGaniiMLuC uv2FUrOpyaL9RMD7yjc66s/OPghUu7OovBgznHSH30J+PhmdEa35DKTOsFQChi3FCjWp RR7rEz0xB/UK4PfvSfJ/CmWgQXn5MW15LbaNsN1QIvjDZ2MGxsn+vBly52UXwlCgL5KT Nduu5zd9ae0QHGfA91DwveJRcS6ed8E7g65CbykC6k+cLIipbXdZawiehhR1kIxQGOuS PIXXz2WmpOvobZkvJPjXijU+/7PrB5v82xN1kUyUSKXXnTskykAYo1hIXl9p35mkcPTY Uc8Q== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id y131si1075601pfg.44.2018.03.20.02.47.01; Tue, 20 Mar 2018 02:47:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752640AbeCTJpU (ORCPT + 99 others); Tue, 20 Mar 2018 05:45:20 -0400 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:37900 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752555AbeCTJoV (ORCPT ); Tue, 20 Mar 2018 05:44:21 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BB9A81435; Tue, 20 Mar 2018 02:44:20 -0700 (PDT) Received: from e107985-lin.cambridge.arm.com (e107985-lin.cambridge.arm.com [10.1.210.41]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 419283F487; Tue, 20 Mar 2018 02:44:18 -0700 (PDT) From: Dietmar Eggemann To: linux-kernel@vger.kernel.org, Peter Zijlstra , Quentin Perret , Thara Gopinath Cc: linux-pm@vger.kernel.org, Morten Rasmussen , Chris Redpath , Patrick Bellasi , Valentin Schneider , "Rafael J . Wysocki" , Greg Kroah-Hartman , Vincent Guittot , Viresh Kumar , Todd Kjos , Joel Fernandes Subject: [RFC PATCH 5/6] sched/fair: Select an energy-efficient CPU on task wake-up Date: Tue, 20 Mar 2018 09:43:11 +0000 Message-Id: <20180320094312.24081-6-dietmar.eggemann@arm.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180320094312.24081-1-dietmar.eggemann@arm.com> References: <20180320094312.24081-1-dietmar.eggemann@arm.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Quentin Perret In case an energy model is available, waking tasks are re-routed into a new energy-aware placement algorithm. The eligible CPUs to be used in the energy-aware wakeup path are restricted to the highest non-overutilized sched_domain containing prev_cpu and this_cpu. If no such domain is found, the tasks go through the usual wake-up path, hence energy-aware placement happens only in lightly utilized scenarios. The selection of the most energy-efficient CPU for a task is achieved by estimating the impact on system-level active energy resulting from the placement of the task on each candidate CPU. The best CPU energy-wise is then selected if it saves a large enough amount of energy with respect to prev_cpu. Although it has already shown significant benefits on some existing targets, this brute force approach clearly cannot scale to platforms with numerous CPUs. This patch is an attempt to do something useful as writing a fast heuristic that performs reasonably well on a broad spectrum of architectures isn't an easy task. As a consequence, the scope of usability of the energy-aware wake-up path is restricted to systems with the SD_ASYM_CPUCAPACITY flag set. These systems not only show the most promising opportunities for saving energy but also typically feature a limited number of logical CPUs. Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Quentin Perret Signed-off-by: Dietmar Eggemann --- kernel/sched/fair.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 76bd46502486..65a1bead0773 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6513,6 +6513,60 @@ static unsigned long compute_energy(struct task_struct *p, int dst_cpu) return energy; } +static bool task_fits(struct task_struct *p, int cpu) +{ + unsigned long next_util = cpu_util_next(cpu, p, cpu); + + return util_fits_capacity(next_util, capacity_orig_of(cpu)); +} + +static int find_energy_efficient_cpu(struct sched_domain *sd, + struct task_struct *p, int prev_cpu) +{ + unsigned long cur_energy, prev_energy, best_energy; + int cpu, best_cpu = prev_cpu; + + if (!task_util(p)) + return prev_cpu; + + /* Compute the energy impact of leaving the task on prev_cpu. */ + prev_energy = best_energy = compute_energy(p, prev_cpu); + + /* Look for the CPU that minimizes the energy. */ + for_each_cpu_and(cpu, &p->cpus_allowed, sched_domain_span(sd)) { + if (!task_fits(p, cpu) || cpu == prev_cpu) + continue; + cur_energy = compute_energy(p, cpu); + if (cur_energy < best_energy) { + best_energy = cur_energy; + best_cpu = cpu; + } + } + + /* + * We pick the best CPU only if it saves at least 1.5% of the + * energy used by prev_cpu. + */ + if ((prev_energy - best_energy) > (prev_energy >> 6)) + return best_cpu; + + return prev_cpu; +} + +static inline bool wake_energy(struct task_struct *p, int prev_cpu) +{ + struct sched_domain *sd; + + if (!static_branch_unlikely(&sched_energy_present)) + return false; + + sd = rcu_dereference_sched(cpu_rq(prev_cpu)->sd); + if (!sd || sd_overutilized(sd)) + return false; + + return true; +} + /* * select_task_rq_fair: Select target runqueue for the waking task in domains * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE, @@ -6529,18 +6583,22 @@ static int select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_flags) { struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL; + struct sched_domain *energy_sd = NULL; int cpu = smp_processor_id(); int new_cpu = prev_cpu; - int want_affine = 0; + int want_affine = 0, want_energy = 0; int sync = (wake_flags & WF_SYNC) && !(current->flags & PF_EXITING); + rcu_read_lock(); + if (sd_flag & SD_BALANCE_WAKE) { record_wakee(p); + want_energy = wake_energy(p, prev_cpu); want_affine = !wake_wide(p) && !wake_cap(p, cpu, prev_cpu) - && cpumask_test_cpu(cpu, &p->cpus_allowed); + && cpumask_test_cpu(cpu, &p->cpus_allowed) + && !want_energy; } - rcu_read_lock(); for_each_domain(cpu, tmp) { if (!(tmp->flags & SD_LOAD_BALANCE)) break; @@ -6555,6 +6613,14 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f break; } + /* + * Energy-aware task placement is performed on the highest + * non-overutilized domain spanning over cpu and prev_cpu. + */ + if (want_energy && !sd_overutilized(tmp) && + cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) + energy_sd = tmp; + if (tmp->flags & sd_flag) sd = tmp; else if (!want_affine) @@ -6586,6 +6652,8 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f if (want_affine) current->recent_used_cpu = cpu; } + } else if (energy_sd) { + new_cpu = find_energy_efficient_cpu(energy_sd, p, prev_cpu); } else { new_cpu = find_idlest_cpu(sd, p, cpu, prev_cpu, sd_flag); } -- 2.11.0