From patchwork Tue Mar 28 15:35:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vincent Guittot X-Patchwork-Id: 96170 Delivered-To: patch@linaro.org Received: by 10.140.89.233 with SMTP id v96csp1769230qgd; Tue, 28 Mar 2017 08:36:29 -0700 (PDT) X-Received: by 10.202.197.204 with SMTP id v195mr13264376oif.4.1490715389639; Tue, 28 Mar 2017 08:36:29 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m198si2207440oig.76.2017.03.28.08.36.29; Tue, 28 Mar 2017 08:36:29 -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; dkim=pass header.i=@linaro.org; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752653AbdC1Pf4 (ORCPT + 17 others); Tue, 28 Mar 2017 11:35:56 -0400 Received: from mail-wr0-f173.google.com ([209.85.128.173]:32828 "EHLO mail-wr0-f173.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751091AbdC1Pfy (ORCPT ); Tue, 28 Mar 2017 11:35:54 -0400 Received: by mail-wr0-f173.google.com with SMTP id w43so94682801wrb.0 for ; Tue, 28 Mar 2017 08:35:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=ptsq/Q5PLb21sjGU+JF9jIv76mJjtHuj5BokE0+xQ6I=; b=CO6Hwm9vjYS4svxK+uow3g8GRJf2Med8tB1wKp3VeCVNwNTuo9unP6rhPEo6sW6g7O lIczLISdDkynoBKUNgTrsIL8hjYo5OXu502qFV8PVV/ga5MdzFryqoxtPKeu+Q4rrLCN eqfl81fxKvL3Di6OiYt8TOlR1AwgePO3TbqPA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=ptsq/Q5PLb21sjGU+JF9jIv76mJjtHuj5BokE0+xQ6I=; b=MCXzLmykuhxb2E75odVggae05sBehFEjsLLLi7Z4uqUS/Xbvzt5xo8h05sCE7Rk8vB BMKdUDrRO4mctoJc6sz5tcZW45RFX56P8m/6G+82+dSgh0lQ357WavmZtTaznHSUuM4s uUXmU2uMa4AU1+079Wy1GrG80N/qqBByHp3WR2pkk1Y4pgQkYyFQltthgPGgvm/IaOCM tmCyz//F6rWI4bN+hH2t9t4NvyfWk56c7fxJFLFMyDAXeQ/HcIc2l3EyzjPU/wGQpihk pGqwAcBmkwepolCwlxfYfuknfca8aymX47CuDhzQINvuz67v08ZS+YC8I6C/UiNdhGdN xfyA== X-Gm-Message-State: AFeK/H0IGf/lZnAbl10ZN7Cip/rIherlgxCJzXsth+VGN63/kY78soW6DzfI2/Y5HnlB/0Bp X-Received: by 10.223.161.132 with SMTP id u4mr17996648wru.203.1490715352542; Tue, 28 Mar 2017 08:35:52 -0700 (PDT) Received: from localhost.localdomain ([2a01:e0a:f:6020:293c:e2bc:95fa:b35e]) by smtp.gmail.com with ESMTPSA id p185sm4093622wme.20.2017.03.28.08.35.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 28 Mar 2017 08:35:51 -0700 (PDT) From: Vincent Guittot To: peterz@infradead.org, mingo@kernel.org, linux-kernel@vger.kernel.org Cc: dietmar.eggemann@arm.com, Morten.Rasmussen@arm.com, yuyang.du@intel.com, pjt@google.com, bsegall@google.com, Vincent Guittot Subject: [PATCH] sched/fair: update scale invariance of PELT Date: Tue, 28 Mar 2017 17:35:45 +0200 Message-Id: <1490715345-13803-1-git-send-email-vincent.guittot@linaro.org> X-Mailer: git-send-email 2.7.4 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The current implementation of load tracking invariance scales the contribution with current frequency and uarch performance (only for utilization) of the CPU. One main result of this formula is that the figures are capped by current capacity of CPU. Another one is that the load_avg is not invariant because not scaled with uarch. The util_avg of a periodic task that runs r time slots every p time slots varies in the range : U * (1-y^r)/(1-y^p) * y^i < Utilization < U * (1-y^r)/(1-y^p) with U is the max util_avg value = SCHED_CAPACITY_SCALE At a lower capacity, the range becomes: U * C * (1-y^r')/(1-y^p) * y^i' < Utilization < U * C * (1-y^r')/(1-y^p) with C reflecting the compute capacity ratio between current capacity and max capacity. so C tries to compensate changes in (1-y^r') but it can't be accurate. Instead of scaling the contribution value of PELT algo, we should scale the running time. The PELT signal aims to track the amount of computation of tasks and/or rq so it seems more correct to scale the running time to reflect the effective amount of computation done since the last update. In order to be fully invariant, we need to apply the same amount of running time and idle time whatever the current capacity. Because running at lower capacity implies that the task will run longer, we have to track the amount of "stolen" idle time and to apply it when task becomes idle. But once we have reached the maximum utilization value (SCHED_CAPACITY_SCALE), it means that the task is seen as an always-running task whatever the capacity of the cpu (even at max compute capacity). In this case, we can discard the "stolen" idle times which becomes meaningless. In order to cope with rounding effect of PELT algo we take a margin and consider task with utilization greater than 1000 (vs 1024 max) as an always-running task. Then, we can use the same algorithm for both utilization and load and simplify __update_load_avg now that the load of a task doesn't have to be capped by CPU uarch. The responsivness of PELT is improved when CPU is not running at max capacity with this new algorithm. I have put below some examples of duration to reach some typical load values according to the capacity of the CPU with current implementation and with this patch. Util (%) max capacity half capacity(mainline) half capacity(w/ patch) 972 (95%) 138ms not reachable 276ms 486 (47.5%) 30ms 138ms 60ms 256 (25%) 13ms 32ms 26ms On my hikey (octo ARM platform) with schedutil governor, the time to reach max OPP when starting from a null utilization, decreases from 223ms with current scale invariance down to 121ms with the new algorithm. For this test, i have enable arch_scale_freq for arm64. Signed-off-by: Vincent Guittot --- include/linux/sched.h | 1 + kernel/sched/fair.c | 49 ++++++++++++++++++++++++++++++++++--------------- 2 files changed, 35 insertions(+), 15 deletions(-) -- 2.7.4 diff --git a/include/linux/sched.h b/include/linux/sched.h index d67eee8..ca9d00f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -313,6 +313,7 @@ struct load_weight { */ struct sched_avg { u64 last_update_time; + u64 stolen_idle_time; u64 load_sum; u32 util_sum; u32 period_contrib; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 31453d5..d1514cb 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -735,6 +735,7 @@ void init_entity_runnable_average(struct sched_entity *se) struct sched_avg *sa = &se->avg; sa->last_update_time = 0; + sa->stolen_idle_time = 0; /* * sched_avg's period_contrib should be strictly less then 1024, so * we give it 1023 to make sure it is almost a period (1024us), and @@ -2852,10 +2853,9 @@ static __always_inline int __update_load_avg(u64 now, int cpu, struct sched_avg *sa, unsigned long weight, int running, struct cfs_rq *cfs_rq) { - u64 delta, scaled_delta, periods; + u64 delta, periods; u32 contrib; - unsigned int delta_w, scaled_delta_w, decayed = 0; - unsigned long scale_freq, scale_cpu; + unsigned int delta_w, decayed = 0; delta = now - sa->last_update_time; /* @@ -2876,8 +2876,30 @@ __update_load_avg(u64 now, int cpu, struct sched_avg *sa, return 0; sa->last_update_time = now; - scale_freq = arch_scale_freq_capacity(NULL, cpu); - scale_cpu = arch_scale_cpu_capacity(NULL, cpu); + if (running) { + sa->stolen_idle_time += delta; + /* + * scale the elapsed time to reflect the real amount of + * computation + */ + delta = cap_scale(delta, arch_scale_freq_capacity(NULL, cpu)); + delta = cap_scale(delta, arch_scale_cpu_capacity(NULL, cpu)); + + /* + * Track the amount of stolen idle time due to running at + * lower capacity + */ + sa->stolen_idle_time -= delta; + } else if (!weight) { + if (sa->util_sum < (LOAD_AVG_MAX * 1000)) { + /* + * Add the idle time stolen by running at lower compute + * capacity + */ + delta += sa->stolen_idle_time; + } + sa->stolen_idle_time = 0; + } /* delta_w is the amount already accumulated against our next period */ delta_w = sa->period_contrib; @@ -2893,16 +2915,15 @@ __update_load_avg(u64 now, int cpu, struct sched_avg *sa, * period and accrue it. */ delta_w = 1024 - delta_w; - scaled_delta_w = cap_scale(delta_w, scale_freq); if (weight) { - sa->load_sum += weight * scaled_delta_w; + sa->load_sum += weight * delta_w; if (cfs_rq) { cfs_rq->runnable_load_sum += - weight * scaled_delta_w; + weight * delta_w; } } if (running) - sa->util_sum += scaled_delta_w * scale_cpu; + sa->util_sum += delta_w << SCHED_CAPACITY_SHIFT; delta -= delta_w; @@ -2919,25 +2940,23 @@ __update_load_avg(u64 now, int cpu, struct sched_avg *sa, /* Efficiently calculate \sum (1..n_period) 1024*y^i */ contrib = __compute_runnable_contrib(periods); - contrib = cap_scale(contrib, scale_freq); if (weight) { sa->load_sum += weight * contrib; if (cfs_rq) cfs_rq->runnable_load_sum += weight * contrib; } if (running) - sa->util_sum += contrib * scale_cpu; + sa->util_sum += contrib << SCHED_CAPACITY_SHIFT; } /* Remainder of delta accrued against u_0` */ - scaled_delta = cap_scale(delta, scale_freq); if (weight) { - sa->load_sum += weight * scaled_delta; + sa->load_sum += weight * delta; if (cfs_rq) - cfs_rq->runnable_load_sum += weight * scaled_delta; + cfs_rq->runnable_load_sum += weight * delta; } if (running) - sa->util_sum += scaled_delta * scale_cpu; + sa->util_sum += delta << SCHED_CAPACITY_SHIFT; sa->period_contrib += delta;