From nobody Sat Jun 13 02:56:18 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42D7837AA70; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501242; cv=none; b=AIJ+5efFbIq9+ac87dC1B4WAjcRLFUO736o2AyBLPxuLtG16SrFbVtHnWS6ficiq2JgjU487fOkFFwt/zMkCCwotXS4oQIUjUrfk7SSRqEk37dJfii8tKL/KZ3r2k93uZr1lZdlPwKMhpQTl0YoVihBIoHWJx2sf14qDi9Ui1J8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501242; c=relaxed/simple; bh=3F100iP4pB5ahm0qxWq2S4gYcxguC9KnpbuH61KE3D0=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=EtuAOjMU0MwZbD1d3alw0ED9nps5M4ta0T6HpjdjZk8k4G/gZIWKNTaur82m+rr63MDEWcrADtzR3m1xwHoH+4dr3Lhcc7ujsy1V0hWV04TPZaWnphW4AHFGG8YDlBmqH95S/6Gs3VrcdlOhgBOiS0U9t/g70sJmnj6hHiJ9kdQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=SGq+qh56; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="SGq+qh56" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=Li2IzmyteveydDL/ki4+K6/ktKsKujM5ayLTcdkUL+E=; b=SGq+qh56Jd1CUfUh4TSQv1PUGi OkcI/W8uyxq1j9sD2kbPv1J0zKv0TZjZnxH68we/feuSu/161TTdmflEqUeBGuww7t3bUpr+0ejUX wkc3wtxrpNnGstHjKwZvAmunqcPlJVPpgABPBmDoGFUN3NYEiIhTmM8CSCA9YREn3vjF4NEVeXKbT 1j9Iq9FLOhJ9/4SOch/uLGKXdGEL8Qt0keqVIdoeZgjMsPFaGUvXkQaCesX5CaUboNV5CbgJB9fr5 WU/VZajEK84BC5Ujp4KSohLO83VOv3RB+vCek6v1X9zrN50Hn5KXA0esYWXBp3zbhP0a1WWl3My4D Vw5HcT+g==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPZ-000000088m0-2Slj; Mon, 11 May 2026 12:07:01 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 0C79530075A; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.065013766@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:05 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 01/10] sched/debug: Use char * instead of char (*)[] References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Some of the fancy AI robots are getting 'upset'. Signed-off-by: Peter Zijlstra (Intel) --- kernel/sched/debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -136,7 +136,7 @@ sched_feat_write(struct file *filp, cons if (cnt > 63) cnt =3D 63; =20 - if (copy_from_user(&buf, ubuf, cnt)) + if (copy_from_user(buf, ubuf, cnt)) return -EFAULT; =20 buf[cnt] =3D 0; @@ -221,7 +221,7 @@ static ssize_t sched_dynamic_write(struc if (cnt > 15) cnt =3D 15; =20 - if (copy_from_user(&buf, ubuf, cnt)) + if (copy_from_user(buf, ubuf, cnt)) return -EFAULT; =20 buf[cnt] =3D 0; From nobody Sat Jun 13 02:56:18 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1B39237B019; Mon, 11 May 2026 12:07:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501241; cv=none; b=beKrbu4ctS4aKOaO76kWHaI6JYjC/+i7lrxABN5ji3BSXPv/L8WA2n7WEYWJ2KS/N1UmX6U8x9XPXSZQefhuS9J5PIDaNBf6ViBdaqQCkmIDA2HIJeDA/qsslenSS/jui/NB1VRLzdm6K+1tjC2Lp59kj5jNCTjgXqLocdPXuDs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501241; c=relaxed/simple; bh=74XIwVKXNdZdW2lgIMAjqDEX5lPpAsOLQAevkzqcgxU=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=jlFDwjYljH7JNheFWKYtrvhdJ+9LhDcmR1ZHP4TCrK6qs2zVur6F6m7KJsbh4G+o2roPu4ebCn+7nXeQqd4MNJHpOnfDR5dP7ioi+V9B0Gv1Mcouov2GUcvgMQJ4uTKDrdNodHSG1Wc7NiQfhRov1HhxMqjZb+cAruaSRKpt+C0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=ewnTeeEs; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="ewnTeeEs" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=/nBno72/K1OUhxB+muvWZ/oNtRySVk9xDO45q62blsY=; b=ewnTeeEsMU8nUt37TAm0yjckfz GYMDoTRT5Vqxq8/OjWMvWgIQ9a899LBv4ZoyQVvpI6yxLLT4iO1Njb0svRpYA2IOjYpmC39UTsWhv H58x6UfG4D0DXNWtQtT+ORERZ9dZ3JvazORCHE1iL/NHBbY9VP5aNesTCLzqsRYOV8JPp+C2rQqXs A1ktYUeJ6p3HHsATxB6XSin6umm8DIvCA8y7vim5ElIwZ00UwoTUoLv0hcyOlbSgN66nJF0/mPwRO NpDq54iAshYiaIABii/smhW6TDzTqk1w71MJSWEwKh7VarRL4U5sDlw++uJcxzZc6HInUDAqA9gXe l/sb41JQ==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPZ-0000000BZMS-1x3u; Mon, 11 May 2026 12:07:03 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 115B8301261; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.176946327@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:06 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 02/10] sched: Use {READ,WRITE}_ONCE() for preempt_dynamic_mode References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Robots figured out you can read and write this concurrently and got 'upset'. Gemini even noted sched_dynamic_show() can generate 'confusing' output if it observed different values during the printing. Signed-off-by: Peter Zijlstra (Intel) --- kernel/sched/core.c | 15 ++++++++------- kernel/sched/debug.c | 5 +++-- 2 files changed, 11 insertions(+), 9 deletions(-) --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7743,7 +7743,7 @@ static void __sched_dynamic_update(int m break; } =20 - preempt_dynamic_mode =3D mode; + WRITE_ONCE(preempt_dynamic_mode, mode); } =20 void sched_dynamic_update(int mode) @@ -7784,12 +7784,13 @@ static void __init preempt_dynamic_init( } } =20 -# define PREEMPT_MODEL_ACCESSOR(mode) \ - bool preempt_model_##mode(void) \ - { \ - WARN_ON_ONCE(preempt_dynamic_mode =3D=3D preempt_dynamic_undefined); \ - return preempt_dynamic_mode =3D=3D preempt_dynamic_##mode; \ - } \ +# define PREEMPT_MODEL_ACCESSOR(mode) \ + bool preempt_model_##mode(void) \ + { \ + int mode =3D READ_ONCE(preempt_dynamic_mode); \ + WARN_ON_ONCE(mode =3D=3D preempt_dynamic_undefined); \ + return mode =3D=3D preempt_dynamic_##mode; \ + } \ EXPORT_SYMBOL_GPL(preempt_model_##mode) =20 PREEMPT_MODEL_ACCESSOR(none); --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -239,6 +239,7 @@ static ssize_t sched_dynamic_write(struc static int sched_dynamic_show(struct seq_file *m, void *v) { int i =3D (IS_ENABLED(CONFIG_PREEMPT_RT) || IS_ENABLED(CONFIG_ARCH_HAS_PR= EEMPT_LAZY)) * 2; + int mode =3D READ_ONCE(preempt_dynamic_mode); int j; =20 /* Count entries in NULL terminated preempt_modes */ @@ -247,10 +248,10 @@ static int sched_dynamic_show(struct seq j -=3D !IS_ENABLED(CONFIG_ARCH_HAS_PREEMPT_LAZY); =20 for (; i < j; i++) { - if (preempt_dynamic_mode =3D=3D i) + if (mode =3D=3D i) seq_puts(m, "("); seq_puts(m, preempt_modes[i]); - if (preempt_dynamic_mode =3D=3D i) + if (mode =3D=3D i) seq_puts(m, ")"); =20 seq_puts(m, " "); From nobody Sat Jun 13 02:56:18 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0E2837B027; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501244; cv=none; b=PC1+uHjURijoQNir9l1V8mkidgUAXk7XB4ZfrQejcaw2QIINSQQOQT9DdDd1ZxZ8UZigraBFqbvC+5XffMz36QtbSlLCpRgwEXB8pJ/xNvxOK/ZH+U8tsuc5/pox+8FlbfsCysJ30ExKD5yh55NwxgXGKMx++2kBTzjSTSwkFTU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501244; c=relaxed/simple; bh=k+pTtIaHnkTkTKHeFxbxviXAACzwjbCoERO6tUUG+L4=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=BwWsdaa1q8ipBpFpYdLCBEHM9zc/LnPABQVV0JtjP6aQ+Hgi7uNA69CqVNbyu3ItXBgNfNr5g7zC3IO+mFTnnneZkB4kNYu0BsfnWANK2+KqQxTHI815bcDAZZlmVDWU7ijLcon/F9I5qkKNyY5Q2hsXQoOk+IGjxeFDSFcJ808= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=gBY4cj+a; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="gBY4cj+a" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=MfDnJaDuHfmTlNlHQofhOK4P8wdrC5bwkWlHclTuFTk=; b=gBY4cj+ak1BsL/7h5Ll8ILYeyr LQ+5eLAL94kuEJGQR8z7kueUciFt3VwRvPVBw6tKdlCa27U1O0KuYgthD2kqPWf3dGXlVM62MEW3d +alW+Np1TRPkSd7SSAQFOazSgTGqOah7RWvUyWkL8LwcEkLbqkGDq52JN7mnyzpA7hd+NTES5oPI2 QkmJSFzxuEJRzj/PiQeMRsVKiizI+wsbkgGrhsNAQpqZcz2jWZxAjFjfhVbpDMXXmQQzV8CQ5xaC5 Oep7vldSjmb+h+oRCh6x5p3wGFoIm5JVY07Bm+N9hF+OCMY6uC9xKId0RVn5/sR6vB5DA9+c6mkRU UmCDD5hA==; Received: from 77-249-17-252.cable.dynamic.v4.ziggo.nl ([77.249.17.252] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPZ-0000000BZMR-1yZd; Mon, 11 May 2026 12:07:03 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 1702B302F8E; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.281160085@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:07 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 03/10] sched/debug: Collapse subsequent CONFIG_SCHED_CLASS_EXT sections References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: Peter Zijlstra (Intel) --- kernel/sched/debug.c | 92 ++++++++++++++++++++++++----------------------= ----- 1 file changed, 44 insertions(+), 48 deletions(-) --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -446,6 +446,8 @@ static const struct file_operations fair .release =3D single_release, }; =20 +static struct dentry *debugfs_sched; + #ifdef CONFIG_SCHED_CLASS_EXT static ssize_t sched_ext_server_runtime_write(struct file *filp, const char __user *ubuf, @@ -478,75 +480,92 @@ static const struct file_operations ext_ .llseek =3D seq_lseek, .release =3D single_release, }; -#endif /* CONFIG_SCHED_CLASS_EXT */ =20 static ssize_t -sched_fair_server_period_write(struct file *filp, const char __user *ubuf, - size_t cnt, loff_t *ppos) +sched_ext_server_period_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) { long cpu =3D (long) ((struct seq_file *) filp->private_data)->private; struct rq *rq =3D cpu_rq(cpu); =20 return sched_server_write_common(filp, ubuf, cnt, ppos, DL_PERIOD, - &rq->fair_server); + &rq->ext_server); } =20 -static int sched_fair_server_period_show(struct seq_file *m, void *v) +static int sched_ext_server_period_show(struct seq_file *m, void *v) { unsigned long cpu =3D (unsigned long) m->private; struct rq *rq =3D cpu_rq(cpu); =20 - return sched_server_show_common(m, v, DL_PERIOD, &rq->fair_server); + return sched_server_show_common(m, v, DL_PERIOD, &rq->ext_server); } =20 -static int sched_fair_server_period_open(struct inode *inode, struct file = *filp) +static int sched_ext_server_period_open(struct inode *inode, struct file *= filp) { - return single_open(filp, sched_fair_server_period_show, inode->i_private); + return single_open(filp, sched_ext_server_period_show, inode->i_private); } =20 -static const struct file_operations fair_server_period_fops =3D { - .open =3D sched_fair_server_period_open, - .write =3D sched_fair_server_period_write, +static const struct file_operations ext_server_period_fops =3D { + .open =3D sched_ext_server_period_open, + .write =3D sched_ext_server_period_write, .read =3D seq_read, .llseek =3D seq_lseek, .release =3D single_release, }; =20 -#ifdef CONFIG_SCHED_CLASS_EXT +static void debugfs_ext_server_init(void) +{ + struct dentry *d_ext; + unsigned long cpu; + + d_ext =3D debugfs_create_dir("ext_server", debugfs_sched); + if (!d_ext) + return; + + for_each_possible_cpu(cpu) { + struct dentry *d_cpu; + char buf[32]; + + snprintf(buf, sizeof(buf), "cpu%lu", cpu); + d_cpu =3D debugfs_create_dir(buf, d_ext); + + debugfs_create_file("runtime", 0644, d_cpu, (void *) cpu, &ext_server_ru= ntime_fops); + debugfs_create_file("period", 0644, d_cpu, (void *) cpu, &ext_server_per= iod_fops); + } +} +#endif /* CONFIG_SCHED_CLASS_EXT */ + static ssize_t -sched_ext_server_period_write(struct file *filp, const char __user *ubuf, - size_t cnt, loff_t *ppos) +sched_fair_server_period_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *ppos) { long cpu =3D (long) ((struct seq_file *) filp->private_data)->private; struct rq *rq =3D cpu_rq(cpu); =20 return sched_server_write_common(filp, ubuf, cnt, ppos, DL_PERIOD, - &rq->ext_server); + &rq->fair_server); } =20 -static int sched_ext_server_period_show(struct seq_file *m, void *v) +static int sched_fair_server_period_show(struct seq_file *m, void *v) { unsigned long cpu =3D (unsigned long) m->private; struct rq *rq =3D cpu_rq(cpu); =20 - return sched_server_show_common(m, v, DL_PERIOD, &rq->ext_server); + return sched_server_show_common(m, v, DL_PERIOD, &rq->fair_server); } =20 -static int sched_ext_server_period_open(struct inode *inode, struct file *= filp) +static int sched_fair_server_period_open(struct inode *inode, struct file = *filp) { - return single_open(filp, sched_ext_server_period_show, inode->i_private); + return single_open(filp, sched_fair_server_period_show, inode->i_private); } =20 -static const struct file_operations ext_server_period_fops =3D { - .open =3D sched_ext_server_period_open, - .write =3D sched_ext_server_period_write, +static const struct file_operations fair_server_period_fops =3D { + .open =3D sched_fair_server_period_open, + .write =3D sched_fair_server_period_write, .read =3D seq_read, .llseek =3D seq_lseek, .release =3D single_release, }; -#endif /* CONFIG_SCHED_CLASS_EXT */ - -static struct dentry *debugfs_sched; =20 static void debugfs_fair_server_init(void) { @@ -569,29 +588,6 @@ static void debugfs_fair_server_init(voi } } =20 -#ifdef CONFIG_SCHED_CLASS_EXT -static void debugfs_ext_server_init(void) -{ - struct dentry *d_ext; - unsigned long cpu; - - d_ext =3D debugfs_create_dir("ext_server", debugfs_sched); - if (!d_ext) - return; - - for_each_possible_cpu(cpu) { - struct dentry *d_cpu; - char buf[32]; - - snprintf(buf, sizeof(buf), "cpu%lu", cpu); - d_cpu =3D debugfs_create_dir(buf, d_ext); - - debugfs_create_file("runtime", 0644, d_cpu, (void *) cpu, &ext_server_ru= ntime_fops); - debugfs_create_file("period", 0644, d_cpu, (void *) cpu, &ext_server_per= iod_fops); - } -} -#endif /* CONFIG_SCHED_CLASS_EXT */ - static __init int sched_init_debug(void) { struct dentry __maybe_unused *numa; From nobody Sat Jun 13 02:56:18 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 42E5E37C0E7; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501243; cv=none; b=lvd7omCyspJfECfGSTN22xBf14corAhGGuRAyw32ARSRFy1hg3io+4ni4lufbPQSGlRNkPLp6VR5vNpv2hyozlzswg2jsmluivzs68nYLI4nGmWVRwdzoaJ0DB5oRwW6W83iWMF19fou2YZtdGifIfvaZNcn8QmH2i69P7QN+sc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501243; c=relaxed/simple; bh=HsCiTJriNz7P+UAsCex8rfRYxLoS04uNTkz3vJjdaJ8=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=UJvBwo+X6ZLLAd3VTuk/4tRczh4+uzJEtGS4KonRBvFnjlFHgVH3XcRjKN5nchE+nHUq3Mv+OggcHE3lUqZEfGfUYVspJoQy9TACeEgCfgHL4Zi+gm7sHkxDC61m3P3zQEaQVFVSyPcSnE3T/VTyGWzFx4B3ogR1QreL/SfQhuw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=kb+fXUwn; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="kb+fXUwn" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=N6IhCAKrZ70BhYGxpBPqHG3qjQiDxSwYn76oXPLANQY=; b=kb+fXUwnrRps0i25uPEUlLBL/E MsFHvv4viLdMX/QIQB70DsV7dgkKBy0yBaB1RyEUM8Ke8w+1Hzud+C2m45o0Ms3naZy6DoU37ji8U 782cVQ/RxJDchiDDHcZCGgJBiHxpsKdsJAWVG1aGUAfgWy2aoq/mc2DbXCN5/ddl+f/WqWMF7DTSU MtBnViV4EJtSl8RVcdMvl66Ggcjww/8Yac4Vo+GwkwkhSUOkWNd7uDdbFk4cX9WZ9FsCOd4KN/e8P HQZubhwtofMRLllfYLVWN05Q7OYYJTii9lIr4q+IwY47xg5IN3SlgRQiy0tgi0wy0opJ0VxvVOpRB kAT3YGcQ==; Received: from 77-249-17-252.cable.dynamic.v4.ziggo.nl ([77.249.17.252] helo=noisy.programming.kicks-ass.net) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPZ-000000088m1-2PbO; Mon, 11 May 2026 12:07:01 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 1BB6D303032; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.433054685@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:08 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 04/10] sched/fair: Add cgroup_mode switch References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Since calc_group_shares() has issues with 'many' CPUs, specifically the computed shares value gets to be roughly 1/nr_cpus, prepare to add a few alternative methods. Signed-off-by: Peter Zijlstra (Intel) --- kernel/sched/debug.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++= +++++ kernel/sched/sched.h | 1=20 2 files changed, 75 insertions(+) --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -588,6 +588,76 @@ static void debugfs_fair_server_init(voi } } =20 +#ifdef CONFIG_FAIR_GROUP_SCHED +int cgroup_mode =3D 0; + +static const char *cgroup_mode_str[] =3D { + "smp", +}; + +static int sched_cgroup_mode(const char *str) +{ + for (int i =3D 0; i < ARRAY_SIZE(cgroup_mode_str); i++) { + if (!strcmp(str, cgroup_mode_str[i])) + return i; + } + return -EINVAL; +} + +static ssize_t sched_cgroup_write(struct file *filp, const char __user *ub= uf, + size_t cnt, loff_t *ppos) +{ + char buf[16]; + int mode; + + if (cnt > 15) + cnt =3D 15; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + + buf[cnt] =3D 0; + mode =3D sched_cgroup_mode(strstrip(buf)); + if (mode < 0) + return mode; + + WRITE_ONCE(cgroup_mode, mode); + + *ppos +=3D cnt; + return cnt; +} + +static int sched_cgroup_show(struct seq_file *m, void *v) +{ + int mode =3D READ_ONCE(cgroup_mode); + + for (int i =3D 0; i < ARRAY_SIZE(cgroup_mode_str); i++) { + if (mode =3D=3D i) + seq_puts(m, "("); + seq_puts(m, cgroup_mode_str[i]); + if (mode =3D=3D i) + seq_puts(m, ")"); + + seq_puts(m, " "); + } + seq_puts(m, "\n"); + return 0; +} + +static int sched_cgroup_open(struct inode *inode, struct file *filp) +{ + return single_open(filp, sched_cgroup_show, NULL); +} + +static const struct file_operations sched_cgroup_fops =3D { + .open =3D sched_cgroup_open, + .write =3D sched_cgroup_write, + .read =3D seq_read, + .llseek =3D seq_lseek, + .release =3D single_release, +}; +#endif + static __init int sched_init_debug(void) { struct dentry __maybe_unused *numa; @@ -625,6 +695,10 @@ static __init int sched_init_debug(void) =20 debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops= ); =20 +#ifdef CONFIG_FAIR_GROUP_SCHED + debugfs_create_file("cgroup_mode", 0644, debugfs_sched, NULL, &sched_cgro= up_fops); +#endif + debugfs_fair_server_init(); #ifdef CONFIG_SCHED_CLASS_EXT debugfs_ext_server_init(); --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -565,6 +565,7 @@ static inline struct task_group *css_tg( extern int tg_nop(struct task_group *tg, void *data); =20 #ifdef CONFIG_FAIR_GROUP_SCHED +extern int cgroup_mode; extern void free_fair_sched_group(struct task_group *tg); extern int alloc_fair_sched_group(struct task_group *tg, struct task_group= *parent); extern void online_fair_sched_group(struct task_group *tg); From nobody Sat Jun 13 02:56:18 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A922837B40C; Mon, 11 May 2026 12:07:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501244; cv=none; b=pVewIgGPyjalleN6cdMluS9lLIPi0pTWUzINb0Cb6wAVK9sZCHc6nl7S/dUnDGSaSZIhF6bfHQnaxaSz9QAI9CGHXXCou+i4/Iz1rgsuoeZyGpM/2U2oxBMVDvA57F78ieprqv3trxut5G1OErzoS/36Dy9inLGXVRqoa/i78ds= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501244; c=relaxed/simple; bh=7WZiidKf/QSpiQu+Wq97gNh/r7ibrr9HmrfjaGfAEtA=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=rg+LeFpjia9T90lw98AG9t3IwpwFR8Xbaw7TeAx+L/gBnDSa/8mx5MlUzuylXxi9YXU4/jA582NQV6ayf/yuz9Pxd5VeWBl+QGZdyPFlUHSmoIjdAQUczTDFAsQTSjCHBFaQ7wWAyduVoLHPb5duDBD7EgvFlYIFh8+MnJg7XO8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=VF8ceFE+; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="VF8ceFE+" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=H9fAEjauTnGfYqGrALj1lwI49DvVQ9DpcV3mAqAYu5I=; b=VF8ceFE+Ap4xxRZHvdWwkKjPNs tL8VLChZWU6jILDjoCrQub9kOiELAvymLlvQbbSY2npy/dEJJYaCDGE/Vo44oWEM9rxR4/Sr6M/Ck 5FmkqdAB08UT7t2gAPFixNMLwBMrtcf4p3kToLIFDS/WusPKog5/cU3RfafkiZu0FRpAbq275ZXZr EUZA2xw5KoJF18WoO3waRnCiTEniqlTBb9DsVvz/Fn9MIGa1IaRiu9laxGw/Uhp0GBy6o/V6UR9R0 /SNWRaM3sid2FXcSD50xCTiD2Rnkn6xql8bG70Xfs1faKx9NlCsxkE/zWvFUrPkxRszqw14bUm43l Hnbs6aWQ==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPa-000000088mQ-0tbT; Mon, 11 May 2026 12:07:02 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 20E62303038; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.592793383@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:09 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 05/10] sched/fair: Add cgroup_mode: UP References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Instead of calculating the proportional fraction of tg->shares for each CPU, just give each CPU the full measure, ignoring these pesky SMP problems. Signed-off-by: Peter Zijlstra (Intel) --- kernel/sched/debug.c | 3 ++- kernel/sched/fair.c | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -589,9 +589,10 @@ static void debugfs_fair_server_init(voi } =20 #ifdef CONFIG_FAIR_GROUP_SCHED -int cgroup_mode =3D 0; +int cgroup_mode =3D 1; =20 static const char *cgroup_mode_str[] =3D { + "up", "smp", }; =20 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4150,7 +4150,7 @@ static inline int throttled_hierarchy(st * * hence icky! */ -static long calc_group_shares(struct cfs_rq *cfs_rq) +static long calc_smp_shares(struct cfs_rq *cfs_rq) { long tg_weight, tg_shares, load, shares; struct task_group *tg =3D cfs_rq->tg; @@ -4185,6 +4185,25 @@ static long calc_group_shares(struct cfs } =20 /* + * Ignore this pesky SMP stuff, use (4). + */ +static long calc_up_shares(struct cfs_rq *cfs_rq) +{ + struct task_group *tg =3D cfs_rq->tg; + return READ_ONCE(tg->shares); +} + +static long calc_group_shares(struct cfs_rq *cfs_rq) +{ + int mode =3D READ_ONCE(cgroup_mode); + + if (mode =3D=3D 0) + return calc_up_shares(cfs_rq); + + return calc_smp_shares(cfs_rq); +} + +/* * Recomputes the group entity based on the current state of its group * runqueue. */ From nobody Sat Jun 13 02:56:18 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EFA8C37B012; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501243; cv=none; b=NXlxXmQ7jifaegtlG83uqcDsa00OWddzTQhv/lxbWe3jphuGVbcqH/NdDRk06Q473i+Po48iCWpsKzjTNV+AUGW7AK249tVOX9L3AgzIcv+ZAs2niSzT9w+wrUTp0oL5ZvDFBkNAsWVLf+Trs0rxhXccKy4YyjQyuYx+AQqpm7c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501243; c=relaxed/simple; bh=l4dMnXD2h3p2MzhM1/gUhNNAztN6IxaTksmz8LwOBUg=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=YLjL1PZm/hOCxZGl3Nf47d5MRq401aFy3i9bfxMsgKKDY3BXVsO9Bnc5UJDjOPXoEA1+M6viH7urow/c6VS36o/DVLp8JgiZDbj9m2YIwqnsLMZ7PX8wq5Zsz7MyBz/Hfr+430uWP3e//ZU25LfnFy1w3GapfMp/kyDxOAdxrrw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=BGXMaeek; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="BGXMaeek" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=/hl7CkGPa8QagrOg/MoFz/yn/ve0/GzVR17AckAYuSQ=; b=BGXMaeek1XsxyUulDTaFf9TzmM IUan7CA+jWkMbuC6XgykuKpObERgBb1hkEAeN5MOSINx5v5WUlXKBztocx1pSlgRkLmWdk08QhMMb o7vP+5V6S1Wm6M2VnK7ItJXo1Lu3Exv+1d68kswTQRYqQ1L1ktXZGYLjafJDMKDSjh3cEx8pPQN6u u10H3m5x8+p42xBHzSil/zwyuObkdHAw74P5FQSH3bX7/iT+Dd3nLFVRcd3g1GYPQcWrycQgz31qM SYzkwOLBCpvIqxtGexMXUFh7AgK0oF0p1m2OITFB/N8a4vHRZyAG+LrDldBY6bsigWTZNHE6PvCsn Fd3hLwlg==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPZ-0000000BZMo-3qaI; Mon, 11 May 2026 12:07:03 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 24D6330303E; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.710598934@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:10 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 06/10] sched/fair: Add cgroup_mode: MAX References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In order to avoid the CPU shares becoming tiny '1 / nr_cpus', assume each cgroup is maximally concurrent and distrubute 'nr_cpus * tg->shares', such that each CPU ends up with a 'tg->shares' sized fraction (on average). There is the corner case, when a cgroup is minimally loaded, eg a single spinner, therefore limit the CPU shares to that of a nice -20 task to avoid getting too much load. It was previously suggested to allow raising cpu.weight to '100 * nr_cpus' to combat this same problem, but the problem there is the above corner case, allowing multiple cgroups with such immense weight to the runqueue has significant problems. It would drown the kthreads, but it also risks overflowing the load values. Signed-off-by: Peter Zijlstra (Intel) --- include/linux/cpuset.h | 6 +++++ kernel/cgroup/cpuset.c | 15 ++++++++++++++ kernel/sched/debug.c | 1=20 kernel/sched/fair.c | 52 ++++++++++++++++++++++++++++++++++++++++++++= ----- 4 files changed, 69 insertions(+), 5 deletions(-) --- a/include/linux/cpuset.h +++ b/include/linux/cpuset.h @@ -80,6 +80,7 @@ extern void lockdep_assert_cpuset_lock_h extern void cpuset_cpus_allowed_locked(struct task_struct *p, struct cpuma= sk *mask); extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mas= k); extern bool cpuset_cpus_allowed_fallback(struct task_struct *p); +extern int cpuset_num_cpus(struct cgroup *cgroup); extern nodemask_t cpuset_mems_allowed(struct task_struct *p); #define cpuset_current_mems_allowed (current->mems_allowed) void cpuset_init_current_mems_allowed(void); @@ -216,6 +217,11 @@ static inline bool cpuset_cpus_allowed_f return false; } =20 +static inline int cpuset_num_cpus(struct cgroup *cgroup) +{ + return num_online_cpus(); +} + static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) { return node_possible_map; --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -4100,6 +4100,21 @@ bool cpuset_cpus_allowed_fallback(struct return changed; } =20 +int cpuset_num_cpus(struct cgroup *cgrp) +{ + int nr =3D num_online_cpus(); + struct cpuset *cs; + + if (is_in_v2_mode()) { + guard(rcu)(); + cs =3D css_cs(cgroup_e_css(cgrp, &cpuset_cgrp_subsys)); + if (cs) + nr =3D cpumask_weight(cs->effective_cpus); + } + + return nr; +} + void __init cpuset_init_current_mems_allowed(void) { nodes_setall(current->mems_allowed); --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -594,6 +594,7 @@ int cgroup_mode =3D 1; static const char *cgroup_mode_str[] =3D { "up", "smp", + "max", }; =20 static int sched_cgroup_mode(const char *str) --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4150,12 +4150,10 @@ static inline int throttled_hierarchy(st * * hence icky! */ -static long calc_smp_shares(struct cfs_rq *cfs_rq) +static long __calc_smp_shares(struct cfs_rq *cfs_rq, long tg_shares, long = shares_max) { - long tg_weight, tg_shares, load, shares; struct task_group *tg =3D cfs_rq->tg; - - tg_shares =3D READ_ONCE(tg->shares); + long tg_weight, load, shares; =20 load =3D max(scale_load_down(cfs_rq->load.weight), cfs_rq->avg.load_avg); =20 @@ -4181,7 +4179,48 @@ static long calc_smp_shares(struct cfs_r * case no task is runnable on a CPU MIN_SHARES=3D2 should be returned * instead of 0. */ - return clamp_t(long, shares, MIN_SHARES, tg_shares); + return clamp_t(long, shares, MIN_SHARES, shares_max); +} + +static int tg_cpus(struct task_group *tg) +{ + int nr =3D num_online_cpus(); + + if (cpusets_enabled()) { + struct cgroup *cgrp =3D tg->css.cgroup; + if (cgrp) + nr =3D cpuset_num_cpus(cgrp); + } + + return nr; +} + +/* + * Func: min(fraction(num_cpus * tg->shares), nice -20) + * + * Scale tg->shares by the maximal number of CPUs; but clip the max shares= at + * nice -20, otherwise a single spinner on a 512 CPU machine would result = in + * 512*NICE_0_LOAD, which is also crazy. + */ +static long calc_max_shares(struct cfs_rq *cfs_rq) +{ + struct task_group *tg =3D cfs_rq->tg; + int nr =3D tg_cpus(tg); + long tg_shares =3D READ_ONCE(tg->shares); + long max_shares =3D scale_load(sched_prio_to_weight[0]); + return __calc_smp_shares(cfs_rq, tg_shares * nr, max_shares); +} + +/* + * Func: fraction(tg->shares) + * + * This infamously results in tiny shares when you have many CPUs. + */ +static long calc_smp_shares(struct cfs_rq *cfs_rq) +{ + struct task_group *tg =3D cfs_rq->tg; + long tg_shares =3D READ_ONCE(tg->shares); + return __calc_smp_shares(cfs_rq, tg_shares, tg_shares); } =20 /* @@ -4200,6 +4239,9 @@ static long calc_group_shares(struct cfs if (mode =3D=3D 0) return calc_up_shares(cfs_rq); =20 + if (mode =3D=3D 2) + return calc_max_shares(cfs_rq); + return calc_smp_shares(cfs_rq); } From nobody Sat Jun 13 02:56:18 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 518F737B01C; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501244; cv=none; b=iGPryHTOldkTVai2O7YKkU4OUoINuM1LDxtshpW/nxFfvpCSs59iiXPzY/6wYXbklq2GZHmpctDPWbFkp/4N72sG1GSTGYL423gy58kKysHzViZTN3J0i7Y8ndZCeNNN7BPOiyXjIjqEM+RQFcGzk2TSpc2GgUljdq4TcQskGms= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501244; c=relaxed/simple; bh=kPWp0zdalOeesi/bRYpUPSDaIbZ3pumjIro3BOeJoKo=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=YwA0L6DTA32pGo/48wXFYoZNdm2INx+RZEE4/pMeibxkGuMAy37LBkQRJnuHxq67OV9EDe8o9h2/xKwyHK/Uyx9gloTJ0AdlJe9yKHO3Zlc5ebkLpbghRNXM6Os41zLGjr//ALi/as9VPAIWMtipF06LiWQAQ3SrnysGmGaiFL0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=gvKBIvh1; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="gvKBIvh1" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=RMka6uWXz+MEpo+IzMSoQp473kglO3d0dwEXELJJ06Q=; b=gvKBIvh1u4cXfkWQqnDL5nuep+ 6zR8Jxj3aOVhyEKhF5Brm0A/SUWq4ZiheI0GVoFN4qw/t6f+EldlUA1CK5T6tRmCjOOaOQAmIbtD6 0nTW5mRXc6Vg389wAGFlmsiShHMg2pLrRH48ZRB1qZ33rfTGGEine5WihJ5AU5CEaXechfbPpFCxf UX34KCmXxNHIwKWMGPGSfW6zHIGXK2R7bPgUdQMRmIk/3+7rvF+9HL9BbZUXUw8Wjq41x6fQd6Mm0 iynhEELMr47CnUJJWhf0Hlwj0Ppq/w+aPm+oJu1jLGFHRD/gZEnTmw/7T4zk4s4fWTX31jD/Q8iyR X9mB1TIw==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPa-000000088mT-1EEO; Mon, 11 May 2026 12:07:02 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 2A045303096; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.829222375@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:11 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 07/10] sched/fair: Add cgroup_mode: CONCUR References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A variation of MAX; where instead of assuming maximal concurrent, this scal= es with 'min(nr_tasks, nr_cpus)'. This handles the low concurrency cases more gracefully, with the exception of CPU affnity. Note: the tracking of tg->tasks is somewhat expensive :-/ Signed-off-by: Peter Zijlstra (Intel) --- kernel/sched/debug.c | 1 + kernel/sched/fair.c | 39 ++++++++++++++++++++++++++++++++++++--- kernel/sched/sched.h | 3 +++ 3 files changed, 40 insertions(+), 3 deletions(-) --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -594,6 +594,7 @@ int cgroup_mode =3D 1; static const char *cgroup_mode_str[] =3D { "up", "smp", + "concur", "max", }; =20 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -4211,6 +4211,30 @@ static long calc_max_shares(struct cfs_r return __calc_smp_shares(cfs_rq, tg_shares * nr, max_shares); } =20 +static inline int tg_tasks(struct task_group *tg) +{ + return max(1, atomic_long_read(&tg->tasks)); +} + +/* + * Func: min(fraction(num * tg->shares), nice -20); where + * num =3D min(nr_tasks, nr_cpus) + * + * Similar to max, except scale with min(nr_tasks, nr_cpus), which gives + * a far more natural distrubution. Can still create edge case using CPU + * affinity. + */ +static long calc_concur_shares(struct cfs_rq *cfs_rq) +{ + struct task_group *tg =3D cfs_rq->tg; + int nr_cpus =3D tg_cpus(tg); + int nr_tasks =3D tg_tasks(tg); + int nr =3D min(nr_tasks, nr_cpus); + long tg_shares =3D READ_ONCE(tg->shares); + long max_shares =3D scale_load(sched_prio_to_weight[0]); + return __calc_smp_shares(cfs_rq, nr * tg_shares, max_shares); +} + /* * Func: fraction(tg->shares) * @@ -4240,6 +4264,9 @@ static long calc_group_shares(struct cfs return calc_up_shares(cfs_rq); =20 if (mode =3D=3D 2) + return calc_concur_shares(cfs_rq); + + if (mode =3D=3D 3) return calc_max_shares(cfs_rq); =20 return calc_smp_shares(cfs_rq); @@ -4385,7 +4412,7 @@ static inline bool cfs_rq_is_decayed(str */ static inline void update_tg_load_avg(struct cfs_rq *cfs_rq) { - long delta; + long delta, dt; u64 now; =20 /* @@ -4407,16 +4434,19 @@ static inline void update_tg_load_avg(st return; =20 delta =3D cfs_rq->avg.load_avg - cfs_rq->tg_load_avg_contrib; - if (abs(delta) > cfs_rq->tg_load_avg_contrib / 64) { + dt =3D cfs_rq->h_nr_queued - cfs_rq->tg_tasks_contrib; + if (dt || abs(delta) > cfs_rq->tg_load_avg_contrib / 64) { atomic_long_add(delta, &cfs_rq->tg->load_avg); + atomic_long_add(dt, &cfs_rq->tg->tasks); cfs_rq->tg_load_avg_contrib =3D cfs_rq->avg.load_avg; + cfs_rq->tg_tasks_contrib =3D cfs_rq->h_nr_queued; cfs_rq->last_update_tg_load_avg =3D now; } } =20 static inline void clear_tg_load_avg(struct cfs_rq *cfs_rq) { - long delta; + long delta, dt; u64 now; =20 /* @@ -4427,8 +4457,11 @@ static inline void clear_tg_load_avg(str =20 now =3D sched_clock_cpu(cpu_of(rq_of(cfs_rq))); delta =3D 0 - cfs_rq->tg_load_avg_contrib; + dt =3D 0 - cfs_rq->tg_tasks_contrib; atomic_long_add(delta, &cfs_rq->tg->load_avg); + atomic_long_add(dt, &cfs_rq->tg->tasks); cfs_rq->tg_load_avg_contrib =3D 0; + cfs_rq->tg_tasks_contrib =3D 0; cfs_rq->last_update_tg_load_avg =3D now; } =20 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -491,6 +491,8 @@ struct task_group { * will also be accessed at each tick. */ atomic_long_t load_avg ____cacheline_aligned; + atomic_long_t tasks; + #endif /* CONFIG_FAIR_GROUP_SCHED */ =20 #ifdef CONFIG_RT_GROUP_SCHED @@ -720,6 +722,7 @@ struct cfs_rq { #ifdef CONFIG_FAIR_GROUP_SCHED u64 last_update_tg_load_avg; unsigned long tg_load_avg_contrib; + unsigned long tg_tasks_contrib; long propagate; long prop_runnable_sum; From nobody Sat Jun 13 02:56:18 2026 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 51A783806C1; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501242; cv=none; b=VefU8gzKyFojQqFc2SzJGtAmLsFxo695SESYDKoOViL3RQVYLOZApxwLscpA9BoDRkqzZb0V997DvmGV2+k/j3qXrrXSeDg/mJuGjb9UELLzJZYYNNeODfmaU0fyHkG5CqbwvnpBpr0tSuU/vYZ8/dSnyREDOylxByPA8HcZkH4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501242; c=relaxed/simple; bh=ydNjD1b6VjzRmA/AvRTkngfGzc+2CDYKjvACvyQ/DUI=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=jRp+u1klWE1NPcQuPBSCLdjl8RY70nNeN9m1Rfj6hktc8FV9jVahXEEVHCe5GY44YHzX7NHIonQkNsNlZMPmMc+ecmUZFsilQrWWPPrNirC3s1M8NfB+3AiM5Ex3s651pfGGWiIM2vGEX2Fao67NqWfLb8SxtOwzVUJ9QgZaxvE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=rCv39yfZ; arc=none smtp.client-ip=90.155.50.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="rCv39yfZ" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=QGTqD1eGQix9gKqNGYA+CLlyDJime6VdW+xYhMpi23A=; b=rCv39yfZaFJxOyTZwF0VZ0R/t6 NVgSM4dLBhh57mxNtDhl9juee9JAoML/K7okg3tmfPG+XQXmqrcRj6WjrigANFiBDRJvOnWfHcOyp 7XsQrfGRNOZHH3s31B4Az5JOUVNW31p8GEmUrykdpW6XmmlpQAxPv6Qr+L+D1MUAPyPUn7bHwQ745 8NTVGVfjYGG4PpKJ5byH1vbY0lwsE9w6ni3iBbXKbPZWTcTT3vY6gqV2/i6D72KKOFspIACAbWn0f yV/6KRpocntyl8XHo0ENYxbqqu7n8mYe73v1P23xkdTMNew+68XfbAZuHVULBNxe76gE4fGqzVwoy tF5oa/vw==; Received: from 77-249-17-252.cable.dynamic.v4.ziggo.nl ([77.249.17.252] helo=noisy.programming.kicks-ass.net) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPa-000000088mU-16QE; Mon, 11 May 2026 12:07:02 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 2E2063030CA; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120627.944705718@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:12 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 08/10] sched/fair: Add newidle balance to pick_task_fair() References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" With commit 50653216e4ff ("sched: Add support to pick functions to take rf") removing the balance callback, the pick_task() callback is in charge of newidle balancing. This means pick_task_fair() should do so too. This hasn't been a problem in practise because pick_next_task_fair() is used. However, since we'll be removing that one shortly, make sure pick_next_task() is up to scratch. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Vincent Guittot Tested-by: Sven Schnelle --- kernel/sched/fair.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9215,16 +9215,18 @@ static void wakeup_preempt_fair(struct r } =20 static struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *= rf) + __must_hold(__rq_lockp(rq)) { struct sched_entity *se; struct cfs_rq *cfs_rq; struct task_struct *p; bool throttled; + int new_tasks; =20 again: cfs_rq =3D &rq->cfs; if (!cfs_rq->nr_queued) - return NULL; + goto idle; =20 throttled =3D false; =20 @@ -9245,6 +9247,14 @@ static struct task_struct *pick_task_fai if (unlikely(throttled)) task_throttle_setup_work(p); return p; + +idle: + new_tasks =3D sched_balance_newidle(rq, rf); + if (new_tasks < 0) + return RETRY_TASK; + if (new_tasks > 0) + goto again; + return NULL; } =20 static void __set_next_task_fair(struct rq *rq, struct task_struct *p, boo= l first); @@ -9256,12 +9266,12 @@ pick_next_task_fair(struct rq *rq, struc { struct sched_entity *se; struct task_struct *p; - int new_tasks; =20 -again: p =3D pick_task_fair(rq, rf); + if (unlikely(p =3D=3D RETRY_TASK)) + return p; if (!p) - goto idle; + return p; se =3D &p->se; =20 #ifdef CONFIG_FAIR_GROUP_SCHED @@ -9311,29 +9321,11 @@ pick_next_task_fair(struct rq *rq, struc #endif /* CONFIG_FAIR_GROUP_SCHED */ put_prev_set_next_task(rq, prev, p); return p; - -idle: - if (rf) { - new_tasks =3D sched_balance_newidle(rq, rf); - - /* - * Because sched_balance_newidle() releases (and re-acquires) - * rq->lock, it is possible for any higher priority task to - * appear. In that case we must re-start the pick_next_entity() - * loop. - */ - if (new_tasks < 0) - return RETRY_TASK; - - if (new_tasks > 0) - goto again; - } - - return NULL; } =20 static struct task_struct * fair_server_pick_task(struct sched_dl_entity *dl_se, struct rq_flags *rf) + __must_hold(__rq_lockp(dl_se->rq)) { return pick_task_fair(dl_se->rq, rf); } From nobody Sat Jun 13 02:56:18 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD35837AA7E; Mon, 11 May 2026 12:07:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501243; cv=none; b=miTLnF2oPAanF/0pLug4uW08/4t91j1o+JIbj+PuDL9pgx3AWYyePSjWh+AEab4EpJTEaCl/TdDXHyWsd9ngOCPtUa0cxxnBHAgSSKPqTEGnr2eNBO4xI6jJyLm7iIhWVUTpP7MPqWj4LyrvwQTMRReqGdtVjJoK01IfXLLSVAg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501243; c=relaxed/simple; bh=hxLQPb3dZmxgpnnb5eMMN5QzCDrXRzIkJMRiqBnHDRU=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=Vy/5dULV0EU+BmC73JcRYK/eTFbLkbGk+iZ7xqG2sN3PIWS3zW2nZGfzMFiH/K7qW1h7EEH53kTOjP2+rU3meRo3hgamV/YUQ+LsZDOZsKzNl0W1k35As8HkZkkCzaV8KU/6C4ec+L4IxQaYiogzOlQOQRS8fDmCyrtiPUG8Pe0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=dHPYRult; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="dHPYRult" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=S0mi3ejVRKZtD/+6BvinHRssu4pdxxO2hzy61vpyyO8=; b=dHPYRultxTY3aIYkyfLKk1lH23 rfSK6/lCjY4HHaLv0apiYL3YvMtnUubcD7lpbLbwh1j5pI/KmfkLfhiawbNNA5EYH/BfHbRT1Ha/R qoNVzko2sn0xh287gdeS1sM+ozRI5J6YHpfjvNtXv3QeqP+kqLO2XgEqg7Ic/3lIAprw2Q1FgziSr nH2LzCqpB3fPC4m8pTPLuymfp/tydtXaqh5Mx8k13vfI9k6QF4y4VjxafEBTeysfturHb9N/jFnZB dB11EXagVAbivdgILQrUismejpF3XL0qIVd4r31vjDoRScT4/QAbOcBKXQhL4C5v9k1nN1Qfk3QRZ X5vHzrfA==; Received: from 77-249-17-252.cable.dynamic.v4.ziggo.nl ([77.249.17.252] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPa-0000000BZMq-04y4; Mon, 11 May 2026 12:07:03 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 325DC3030E7; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120628.057634261@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:13 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 09/10] sched: Remove sched_class::pick_next_task() References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The reason for pick_next_task_fair() is the put/set optimization that avoids touching the common ancestors. However, it is possible to implement this in the put_prev_task() and set_next_task() calls as used in put_prev_set_next_task(). Notably, put_prev_set_next_task() is the only site that: - calls put_prev_task() with a .next argument; - calls set_next_task() with .first =3D true. This means that put_prev_task() can determine the common hierarchy and stop there, and then set_next_task() can terminate where put_prev_task stopped. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Vincent Guittot --- kernel/sched/core.c | 27 +++------ kernel/sched/fair.c | 139 +++++++++++++++++-----------------------------= ----- kernel/sched/sched.h | 14 ----- 3 files changed, 57 insertions(+), 123 deletions(-) --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5980,16 +5980,15 @@ __pick_next_task(struct rq *rq, struct t if (likely(!sched_class_above(prev->sched_class, &fair_sched_class) && rq->nr_running =3D=3D rq->cfs.h_nr_queued)) { =20 - p =3D pick_next_task_fair(rq, prev, rf); + p =3D pick_task_fair(rq, rf); if (unlikely(p =3D=3D RETRY_TASK)) goto restart; =20 /* Assume the next prioritized class is idle_sched_class */ - if (!p) { + if (!p) p =3D pick_task_idle(rq, rf); - put_prev_set_next_task(rq, prev, p); - } =20 + put_prev_set_next_task(rq, prev, p); return p; } =20 @@ -5997,20 +5996,12 @@ __pick_next_task(struct rq *rq, struct t prev_balance(rq, prev, rf); =20 for_each_active_class(class) { - if (class->pick_next_task) { - p =3D class->pick_next_task(rq, prev, rf); - if (unlikely(p =3D=3D RETRY_TASK)) - goto restart; - if (p) - return p; - } else { - p =3D class->pick_task(rq, rf); - if (unlikely(p =3D=3D RETRY_TASK)) - goto restart; - if (p) { - put_prev_set_next_task(rq, prev, p); - return p; - } + p =3D class->pick_task(rq, rf); + if (unlikely(p =3D=3D RETRY_TASK)) + goto restart; + if (p) { + put_prev_set_next_task(rq, prev, p); + return p; } } =20 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -9214,7 +9214,7 @@ static void wakeup_preempt_fair(struct r resched_curr_lazy(rq); } =20 -static struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *= rf) +struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *rf) __must_hold(__rq_lockp(rq)) { struct sched_entity *se; @@ -9257,72 +9257,6 @@ static struct task_struct *pick_task_fai return NULL; } =20 -static void __set_next_task_fair(struct rq *rq, struct task_struct *p, boo= l first); -static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool = first); - -struct task_struct * -pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_fla= gs *rf) - __must_hold(__rq_lockp(rq)) -{ - struct sched_entity *se; - struct task_struct *p; - - p =3D pick_task_fair(rq, rf); - if (unlikely(p =3D=3D RETRY_TASK)) - return p; - if (!p) - return p; - se =3D &p->se; - -#ifdef CONFIG_FAIR_GROUP_SCHED - if (prev->sched_class !=3D &fair_sched_class) - goto simple; - - __put_prev_set_next_dl_server(rq, prev, p); - - /* - * Because of the set_next_buddy() in dequeue_task_fair() it is rather - * likely that a next task is from the same cgroup as the current. - * - * Therefore attempt to avoid putting and setting the entire cgroup - * hierarchy, only change the part that actually changes. - * - * Since we haven't yet done put_prev_entity and if the selected task - * is a different task than we started out with, try and touch the - * least amount of cfs_rqs. - */ - if (prev !=3D p) { - struct sched_entity *pse =3D &prev->se; - struct cfs_rq *cfs_rq; - - while (!(cfs_rq =3D is_same_group(se, pse))) { - int se_depth =3D se->depth; - int pse_depth =3D pse->depth; - - if (se_depth <=3D pse_depth) { - put_prev_entity(cfs_rq_of(pse), pse); - pse =3D parent_entity(pse); - } - if (se_depth >=3D pse_depth) { - set_next_entity(cfs_rq_of(se), se, true); - se =3D parent_entity(se); - } - } - - put_prev_entity(cfs_rq, pse); - set_next_entity(cfs_rq, se, true); - - __set_next_task_fair(rq, p, true); - } - - return p; - -simple: -#endif /* CONFIG_FAIR_GROUP_SCHED */ - put_prev_set_next_task(rq, prev, p); - return p; -} - static struct task_struct * fair_server_pick_task(struct sched_dl_entity *dl_se, struct rq_flags *rf) __must_hold(__rq_lockp(dl_se->rq)) @@ -9346,10 +9280,33 @@ static void put_prev_task_fair(struct rq { struct sched_entity *se =3D &prev->se; struct cfs_rq *cfs_rq; + struct sched_entity *nse =3D NULL; =20 - for_each_sched_entity(se) { +#ifdef CONFIG_FAIR_GROUP_SCHED + if (next && next->sched_class =3D=3D &fair_sched_class) + nse =3D &next->se; +#endif + + while (se) { cfs_rq =3D cfs_rq_of(se); - put_prev_entity(cfs_rq, se); + if (!nse || cfs_rq->curr) + put_prev_entity(cfs_rq, se); +#ifdef CONFIG_FAIR_GROUP_SCHED + if (nse) { + if (is_same_group(se, nse)) + break; + + int d =3D nse->depth - se->depth; + if (d >=3D 0) { + /* nse has equal or greater depth, ascend */ + nse =3D parent_entity(nse); + /* if nse is the deeper, do not ascend se */ + if (d > 0) + continue; + } + } +#endif + se =3D parent_entity(se); } } =20 @@ -13896,10 +13853,30 @@ static void switched_to_fair(struct rq * } } =20 -static void __set_next_task_fair(struct rq *rq, struct task_struct *p, boo= l first) +/* + * Account for a task changing its policy or group. + * + * This routine is mostly called to set cfs_rq->curr field when a task + * migrates between groups/classes. + */ +static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool = first) { struct sched_entity *se =3D &p->se; =20 + for_each_sched_entity(se) { + struct cfs_rq *cfs_rq =3D cfs_rq_of(se); + + if (IS_ENABLED(CONFIG_FAIR_GROUP_SCHED) && + first && cfs_rq->curr) + break; + + set_next_entity(cfs_rq, se, first); + /* ensure bandwidth has been allocated on our new cfs_rq */ + account_cfs_rq_runtime(cfs_rq, 0); + } + + se =3D &p->se; + if (task_on_rq_queued(p)) { /* * Move the next running task to the front of the list, so our @@ -13919,27 +13896,6 @@ static void __set_next_task_fair(struct sched_fair_update_stop_tick(rq, p); } =20 -/* - * Account for a task changing its policy or group. - * - * This routine is mostly called to set cfs_rq->curr field when a task - * migrates between groups/classes. - */ -static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool = first) -{ - struct sched_entity *se =3D &p->se; - - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq =3D cfs_rq_of(se); - - set_next_entity(cfs_rq, se, first); - /* ensure bandwidth has been allocated on our new cfs_rq */ - account_cfs_rq_runtime(cfs_rq, 0); - } - - __set_next_task_fair(rq, p, first); -} - void init_cfs_rq(struct cfs_rq *cfs_rq) { cfs_rq->tasks_timeline =3D RB_ROOT_CACHED; @@ -14251,7 +14207,6 @@ DEFINE_SCHED_CLASS(fair) =3D { .wakeup_preempt =3D wakeup_preempt_fair, =20 .pick_task =3D pick_task_fair, - .pick_next_task =3D pick_next_task_fair, .put_prev_task =3D put_prev_task_fair, .set_next_task =3D set_next_task_fair, =20 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2555,17 +2555,6 @@ struct sched_class { * schedule/pick_next_task: rq->lock */ struct task_struct *(*pick_task)(struct rq *rq, struct rq_flags *rf); - /* - * Optional! When implemented pick_next_task() should be equivalent to: - * - * next =3D pick_task(); - * if (next) { - * put_prev_task(prev); - * set_next_task_first(next); - * } - */ - struct task_struct *(*pick_next_task)(struct rq *rq, struct task_struct *= prev, - struct rq_flags *rf); =20 /* * sched_change: @@ -2789,8 +2778,7 @@ static inline bool sched_fair_runnable(s return rq->cfs.nr_queued > 0; } =20 -extern struct task_struct *pick_next_task_fair(struct rq *rq, struct task_= struct *prev, - struct rq_flags *rf); +extern struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *= rf); extern struct task_struct *pick_task_idle(struct rq *rq, struct rq_flags *= rf); =20 #define SCA_CHECK 0x01 From nobody Sat Jun 13 02:56:18 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 512C83815DB; Mon, 11 May 2026 12:07:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501250; cv=none; b=jKJk4g7z950xZR5FkeZpQz7EAgW/vi6NzZFg9SXuaQxQb+jVTKnyVV40PyHW53gVh/wTtc0Ko/8AOgCkcfCeAtAiJPbYbiXRgZx5E7FRKipxVkEjBhzZFid0J5wAxJIw27b/wxoQu+UF4wYTPPBgtu7NxWTlSrLNwCDmW8QS/NQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778501250; c=relaxed/simple; bh=4Ra6XPO5+e9kaIf00U64hgah1mY6gsZYyOrNzykhs40=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=b1q/P+Yx7GqMGIo0SQoDA6WZSuBNw79NnKyF9iIGA01Ly5qW7XxACRNjx3uz4MFUlTSItPfCv/Zx6VW5nxLMWW+F4ysRfZZ6yTYr2rp4FK++biHgxSZ44sVd24vW2nb9JmJTHdYt0j9Q+nd7Hhyiq75FdLk1R4nB6NALHxoP3VE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=Hth+fdrq; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="Hth+fdrq" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=RhOHJEXt+ki1hL7MGiECAMpOClZS7GRpVd2ckda8LtA=; b=Hth+fdrqWrACEXFOpkQC/DPAY9 BTPZ/Cs8iqTLr7c/YSJakX03RvSJOGK19BVOqPh7WU/lkW3pRAVS/xLxG/ZBbDGmT+jy+bZGK2mOh 6Z3a5tLFhChCvd16kthFOye94LKcpvzFavGX6dIbDYfjZrw86E1N2/HkV09uzqgy3FTEz/BxxzgHx gaLS35GB7Dp03wj5z32hFctsNguSpDJEawnRCgMSspnYugov8H9OFVVbWu5wp6SonT1tSDWiPjnIr fB9cDbRYwqGUodFkFcBaNH70mxKJPrsbxD0R7Feel9Ib+gAE0TR7AtsfwfQtbAmkv3F17nichHuQh FGLsPPlw==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wMPPa-0000000BZMr-0BHN; Mon, 11 May 2026 12:07:03 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id 371CC3030E9; Mon, 11 May 2026 14:07:00 +0200 (CEST) Message-ID: <20260511120628.206700041@infradead.org> User-Agent: quilt/0.68 Date: Mon, 11 May 2026 13:31:14 +0200 From: Peter Zijlstra To: mingo@kernel.org Cc: longman@redhat.com, chenridong@huaweicloud.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, tj@kernel.org, hannes@cmpxchg.org, mkoutny@suse.com, cgroups@vger.kernel.org, linux-kernel@vger.kernel.org, jstultz@google.com, kprateek.nayak@amd.com, qyousef@layalina.io Subject: [PATCH v2 10/10] sched/eevdf: Move to a single runqueue References: <20260511113104.563854162@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Change fair/cgroup to a single runqueue. Infamously fair/cgroup isn't working for a number of people; typically the complaint is latencies and/or overhead. The latency issue is due to the intermediate entries that represent a combination of tasks and thereby obfuscate the runnability of tasks. The approach here is to leave the cgroup hierarchy as is; including the intermediate enqueue/dequeue but move the actual EEVDF runqueue outside. This means things like the shares_weight approximation are fully preserved. That is, given a hierarchy like: R | se--G1 / \ G2--se se--G3 / \ | T1--se se--T2 se--T3 This is fully maintained for load tracking, however the EEVDF parts of cfs_rq/se go unused for the intermediates and are instead connected like: _R_ / | \ T1 T2 T3 Since the effective weight of the entities is determined by the hierarchy, this gets recomputed on enqueue,set_next_task and tick. Notably, the effective weight (se->h_load) is computed from the hierarchical fraction: se->load / cfs_rq->load. Since EEVDF is now exclusive operating on rq->cfs, it needs to consider cfs_rq->h_nr_queued rather than cfs_rq->nr_queued. Similarly, only tasks can get delayed, simplifying some of the cgroup cleanup. One place where additional information was required was set_next_task() / put_prev_task(), where we need to track 'current' both in the hierarchical sense (cfs_rq->h_curr) and in the flat sense (cfs_rq->curr). As a result of only having a single level to pick from, much of the complications in pick_next_task() and preemption go away. Since many of the hierarchical operations are still there, this won't immediately fix the performance issues, but hopefully it will fix some of the latency issues. TODO: split struct cfs_rq / struct sched_entity TODO: try and get rid of h_curr Signed-off-by: Peter Zijlstra (Intel) Tested-by: Zhang Qiao --- include/linux/sched.h | 1=20 kernel/sched/core.c | 5=20 kernel/sched/debug.c | 9=20 kernel/sched/fair.c | 789 +++++++++++++++++++++------------------------= ----- kernel/sched/pelt.c | 6=20 kernel/sched/sched.h | 26 - 6 files changed, 366 insertions(+), 470 deletions(-) --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -575,6 +575,7 @@ struct sched_statistics { struct sched_entity { /* For load-balancing: */ struct load_weight load; + struct load_weight h_load; struct rb_node run_node; u64 deadline; u64 min_vruntime; --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5539,11 +5539,8 @@ EXPORT_PER_CPU_SYMBOL(kernel_cpustat); */ static inline void prefetch_curr_exec_start(struct task_struct *p) { -#ifdef CONFIG_FAIR_GROUP_SCHED - struct sched_entity *curr =3D p->se.cfs_rq->curr; -#else struct sched_entity *curr =3D task_rq(p)->cfs.curr; -#endif + prefetch(curr); prefetch(&curr->exec_start); } --- a/kernel/sched/debug.c +++ b/kernel/sched/debug.c @@ -911,10 +911,11 @@ print_task(struct seq_file *m, struct rq else SEQ_printf(m, " %c", task_state_to_char(p)); =20 - SEQ_printf(m, " %15s %5d %9Ld.%06ld %c %9Ld.%06ld %c %9Ld.%06ld %9Ld.= %06ld %9Ld %5d ", + SEQ_printf(m, " %15s %5d %10ld %9Ld.%06ld %c %9Ld.%06ld %c %9Ld.%06ld= %9Ld.%06ld %9Ld %5d ", p->comm, task_pid_nr(p), + p->se.h_load.weight, SPLIT_NS(p->se.vruntime), - entity_eligible(cfs_rq_of(&p->se), &p->se) ? 'E' : 'N', + entity_eligible(&rq->cfs, &p->se) ? 'E' : 'N', SPLIT_NS(p->se.deadline), p->se.custom_slice ? 'S' : ' ', SPLIT_NS(p->se.slice), @@ -943,7 +944,7 @@ static void print_rq(struct seq_file *m, =20 SEQ_printf(m, "\n"); SEQ_printf(m, "runnable tasks:\n"); - SEQ_printf(m, " S task PID vruntime eligible " + SEQ_printf(m, " S task PID weight vruntime eligi= ble " "deadline slice sum-exec switches " "prio wait-time sum-sleep sum-block" #ifdef CONFIG_NUMA_BALANCING @@ -1051,6 +1052,8 @@ void print_cfs_rq(struct seq_file *m, in cfs_rq->tg_load_avg_contrib); SEQ_printf(m, " .%-30s: %ld\n", "tg_load_avg", atomic_long_read(&cfs_rq->tg->load_avg)); + SEQ_printf(m, " .%-30s: %lu\n", "h_load", + cfs_rq->h_load); #endif /* CONFIG_FAIR_GROUP_SCHED */ #ifdef CONFIG_CFS_BANDWIDTH SEQ_printf(m, " .%-30s: %d\n", "throttled", --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -296,8 +296,8 @@ static u64 __calc_delta(u64 delta_exec, */ static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se) { - if (unlikely(se->load.weight !=3D NICE_0_LOAD)) - delta =3D __calc_delta(delta, NICE_0_LOAD, &se->load); + if (se->h_load.weight !=3D NICE_0_LOAD) + delta =3D __calc_delta(delta, NICE_0_LOAD, &se->h_load); =20 return delta; } @@ -427,38 +427,6 @@ static inline struct sched_entity *paren return se->parent; } =20 -static void -find_matching_se(struct sched_entity **se, struct sched_entity **pse) -{ - int se_depth, pse_depth; - - /* - * preemption test can be made between sibling entities who are in the - * same cfs_rq i.e who have a common parent. Walk up the hierarchy of - * both tasks until we find their ancestors who are siblings of common - * parent. - */ - - /* First walk up until both entities are at same depth */ - se_depth =3D (*se)->depth; - pse_depth =3D (*pse)->depth; - - while (se_depth > pse_depth) { - se_depth--; - *se =3D parent_entity(*se); - } - - while (pse_depth > se_depth) { - pse_depth--; - *pse =3D parent_entity(*pse); - } - - while (!is_same_group(*se, *pse)) { - *se =3D parent_entity(*se); - *pse =3D parent_entity(*pse); - } -} - static int tg_is_idle(struct task_group *tg) { return tg->idle > 0; @@ -502,11 +470,6 @@ static inline struct sched_entity *paren return NULL; } =20 -static inline void -find_matching_se(struct sched_entity **se, struct sched_entity **pse) -{ -} - static inline int tg_is_idle(struct task_group *tg) { return 0; @@ -685,7 +648,7 @@ static inline unsigned long avg_vruntime static inline void __sum_w_vruntime_add(struct cfs_rq *cfs_rq, struct sched_entity *se) { - unsigned long weight =3D avg_vruntime_weight(cfs_rq, se->load.weight); + unsigned long weight =3D avg_vruntime_weight(cfs_rq, se->h_load.weight); s64 w_vruntime, key =3D entity_key(cfs_rq, se); =20 w_vruntime =3D key * weight; @@ -702,7 +665,7 @@ sum_w_vruntime_add_paranoid(struct cfs_r s64 key, tmp; =20 again: - weight =3D avg_vruntime_weight(cfs_rq, se->load.weight); + weight =3D avg_vruntime_weight(cfs_rq, se->h_load.weight); key =3D entity_key(cfs_rq, se); =20 if (check_mul_overflow(key, weight, &key)) @@ -748,7 +711,7 @@ sum_w_vruntime_add(struct cfs_rq *cfs_rq static void sum_w_vruntime_sub(struct cfs_rq *cfs_rq, struct sched_entity *se) { - unsigned long weight =3D avg_vruntime_weight(cfs_rq, se->load.weight); + unsigned long weight =3D avg_vruntime_weight(cfs_rq, se->h_load.weight); s64 key =3D entity_key(cfs_rq, se); =20 cfs_rq->sum_w_vruntime -=3D key * weight; @@ -790,7 +753,7 @@ u64 avg_vruntime(struct cfs_rq *cfs_rq) s64 runtime =3D cfs_rq->sum_w_vruntime; =20 if (curr) { - unsigned long w =3D avg_vruntime_weight(cfs_rq, curr->load.weight); + unsigned long w =3D avg_vruntime_weight(cfs_rq, curr->h_load.weight); =20 runtime +=3D entity_key(cfs_rq, curr) * w; weight +=3D w; @@ -861,8 +824,6 @@ bool update_entity_lag(struct cfs_rq *cf u64 avruntime =3D avg_vruntime(cfs_rq); s64 vlag =3D entity_lag(cfs_rq, se, avruntime); =20 - WARN_ON_ONCE(!se->on_rq); - if (se->sched_delayed) { /* previous vlag < 0 otherwise se would not be delayed */ vlag =3D max(vlag, se->vlag); @@ -898,7 +859,7 @@ static int vruntime_eligible(struct cfs_ long load =3D cfs_rq->sum_weight; =20 if (curr && curr->on_rq) { - unsigned long weight =3D avg_vruntime_weight(cfs_rq, curr->load.weight); + unsigned long weight =3D avg_vruntime_weight(cfs_rq, curr->h_load.weight= ); =20 avg +=3D entity_key(cfs_rq, curr) * weight; load +=3D weight; @@ -1039,6 +1000,9 @@ RB_DECLARE_CALLBACKS(static, min_vruntim */ static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *s= e) { + WARN_ON_ONCE(&rq_of(cfs_rq)->cfs !=3D cfs_rq); + WARN_ON_ONCE(!entity_is_task(se)); + sum_w_vruntime_add(cfs_rq, se); se->min_vruntime =3D se->vruntime; se->min_slice =3D se->slice; @@ -1048,6 +1012,9 @@ static void __enqueue_entity(struct cfs_ =20 static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *s= e) { + WARN_ON_ONCE(&rq_of(cfs_rq)->cfs !=3D cfs_rq); + WARN_ON_ONCE(!entity_is_task(se)); + rb_erase_augmented_cached(&se->run_node, &cfs_rq->tasks_timeline, &min_vruntime_cb); sum_w_vruntime_sub(cfs_rq, se); @@ -1144,7 +1111,7 @@ static struct sched_entity *pick_eevdf(s * We can safely skip eligibility check if there is only one entity * in this cfs_rq, saving some cycles. */ - if (cfs_rq->nr_queued =3D=3D 1) + if (cfs_rq->h_nr_queued =3D=3D 1) return curr && curr->on_rq ? curr : se; =20 /* @@ -1391,8 +1358,6 @@ static s64 update_se(struct rq *rq, stru return delta_exec; } =20 -static void set_next_buddy(struct sched_entity *se); - /* * Used by other classes to account runtime. */ @@ -1412,7 +1377,7 @@ static void update_curr(struct cfs_rq *c * not necessarily be the actual task running * (rq->curr.se). This is easy to confuse! */ - struct sched_entity *curr =3D cfs_rq->curr; + struct sched_entity *curr =3D cfs_rq->h_curr; struct rq *rq =3D rq_of(cfs_rq); s64 delta_exec; bool resched; @@ -1424,26 +1389,29 @@ static void update_curr(struct cfs_rq *c if (unlikely(delta_exec <=3D 0)) return; =20 + account_cfs_rq_runtime(cfs_rq, delta_exec); + + if (!entity_is_task(curr)) + return; + + cfs_rq =3D &rq->cfs; + curr->vruntime +=3D calc_delta_fair(delta_exec, curr); resched =3D update_deadline(cfs_rq, curr); =20 - if (entity_is_task(curr)) { - /* - * If the fair_server is active, we need to account for the - * fair_server time whether or not the task is running on - * behalf of fair_server or not: - * - If the task is running on behalf of fair_server, we need - * to limit its time based on the assigned runtime. - * - Fair task that runs outside of fair_server should account - * against fair_server such that it can account for this time - * and possibly avoid running this period. - */ - dl_server_update(&rq->fair_server, delta_exec); - } - - account_cfs_rq_runtime(cfs_rq, delta_exec); + /* + * If the fair_server is active, we need to account for the + * fair_server time whether or not the task is running on + * behalf of fair_server or not: + * - If the task is running on behalf of fair_server, we need + * to limit its time based on the assigned runtime. + * - Fair task that runs outside of fair_server should account + * against fair_server such that it can account for this time + * and possibly avoid running this period. + */ + dl_server_update(&rq->fair_server, delta_exec); =20 - if (cfs_rq->nr_queued =3D=3D 1) + if (cfs_rq->h_nr_queued =3D=3D 1) return; =20 if (resched || !protect_slice(curr)) { @@ -1454,7 +1422,10 @@ static void update_curr(struct cfs_rq *c =20 static void update_curr_fair(struct rq *rq) { - update_curr(cfs_rq_of(&rq->donor->se)); + struct sched_entity *se =3D &rq->donor->se; + + for_each_sched_entity(se) + update_curr(cfs_rq_of(se)); } =20 static inline void @@ -1530,7 +1501,7 @@ update_stats_enqueue_fair(struct cfs_rq * Are we enqueueing a waiting task? (for current tasks * a dequeue/enqueue event is a NOP) */ - if (se !=3D cfs_rq->curr) + if (se !=3D cfs_rq->h_curr) update_stats_wait_start_fair(cfs_rq, se); =20 if (flags & ENQUEUE_WAKEUP) @@ -1548,7 +1519,7 @@ update_stats_dequeue_fair(struct cfs_rq * Mark the end of the wait period if dequeueing a * waiting task: */ - if (se !=3D cfs_rq->curr) + if (se !=3D cfs_rq->h_curr) update_stats_wait_end_fair(cfs_rq, se); =20 if ((flags & DEQUEUE_SLEEP) && entity_is_task(se)) { @@ -3875,6 +3846,7 @@ static inline void update_scan_period(st static void account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se) { + WARN_ON_ONCE(cfs_rq !=3D cfs_rq_of(se)); update_load_add(&cfs_rq->load, se->load.weight); if (entity_is_task(se)) { struct rq *rq =3D rq_of(cfs_rq); @@ -3888,6 +3860,7 @@ account_entity_enqueue(struct cfs_rq *cf static void account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se) { + WARN_ON_ONCE(cfs_rq !=3D cfs_rq_of(se)); update_load_sub(&cfs_rq->load, se->load.weight); if (entity_is_task(se)) { account_numa_dequeue(rq_of(cfs_rq), task_of(se)); @@ -3965,7 +3938,7 @@ dequeue_load_avg(struct cfs_rq *cfs_rq, static void rescale_entity(struct sched_entity *se, unsigned long weight, bool rel_vpr= ot) { - unsigned long old_weight =3D se->load.weight; + long old_weight =3D se->h_load.weight; =20 /* * VRUNTIME @@ -4065,16 +4038,17 @@ rescale_entity(struct sched_entity *se, se->vprot =3D div64_long(se->vprot * old_weight, weight); } =20 -static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, - unsigned long weight) +static void reweight_eevdf(struct cfs_rq *cfs_rq, struct sched_entity *se, + unsigned long weight, bool on_rq) { bool curr =3D cfs_rq->curr =3D=3D se; bool rel_vprot =3D false; u64 avruntime =3D 0; =20 - if (se->on_rq) { - /* commit outstanding execution time */ - update_curr(cfs_rq); + if (se->h_load.weight =3D=3D weight) + return; + + if (on_rq) { avruntime =3D avg_vruntime(cfs_rq); se->vlag =3D entity_lag(cfs_rq, se, avruntime); se->deadline -=3D avruntime; @@ -4084,46 +4058,90 @@ static void reweight_entity(struct cfs_r rel_vprot =3D true; } =20 - cfs_rq->nr_queued--; + cfs_rq->h_nr_queued--; if (!curr) __dequeue_entity(cfs_rq, se); - update_load_sub(&cfs_rq->load, se->load.weight); } - dequeue_load_avg(cfs_rq, se); =20 rescale_entity(se, weight, rel_vprot); =20 - update_load_set(&se->load, weight); + update_load_set(&se->h_load, weight); =20 - do { - u32 divider =3D get_pelt_divider(&se->avg); - se->avg.load_avg =3D div_u64(se_weight(se) * se->avg.load_sum, divider); - } while (0); - - enqueue_load_avg(cfs_rq, se); - if (se->on_rq) { + if (on_rq) { if (rel_vprot) se->vprot +=3D avruntime; se->deadline +=3D avruntime; se->rel_deadline =3D 0; se->vruntime =3D avruntime - se->vlag; =20 - update_load_add(&cfs_rq->load, se->load.weight); if (!curr) __enqueue_entity(cfs_rq, se); - cfs_rq->nr_queued++; + cfs_rq->h_nr_queued++; } } =20 +static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, + unsigned long weight) +{ + if (se->load.weight =3D=3D weight) + return; + + if (se->on_rq) { + WARN_ON_ONCE(cfs_rq !=3D cfs_rq_of(se)); + update_load_sub(&cfs_rq->load, se->load.weight); + } + dequeue_load_avg(cfs_rq, se); + + update_load_set(&se->load, weight); + + do { + u32 divider =3D get_pelt_divider(&se->avg); + se->avg.load_avg =3D div_u64(se_weight(se) * se->avg.load_sum, divider); + } while (0); + + enqueue_load_avg(cfs_rq, se); + + if (se->on_rq) + update_load_add(&cfs_rq->load, se->load.weight); +} + +/* + * weight =3D NICE_0_LOAD; + * for_each_entity_se(se) + * weight =3D __calc_prop_weight(cfs_rq_of(se), se, weight); + */ +static __always_inline +unsigned long __calc_prop_weight(struct cfs_rq *cfs_rq, struct sched_entit= y *se, + unsigned long weight) +{ + weight *=3D se->load.weight; + if (parent_entity(se)) + weight /=3D cfs_rq->load.weight; + else + weight /=3D NICE_0_LOAD; + + return max(weight, MIN_SHARES); +} + static void reweight_task_fair(struct rq *rq, struct task_struct *p, const struct load_weight *lw) { struct sched_entity *se =3D &p->se; - struct cfs_rq *cfs_rq =3D cfs_rq_of(se); - struct load_weight *load =3D &se->load; + unsigned long weight =3D NICE_0_LOAD; + + if (se->on_rq) + update_curr_fair(rq); + + reweight_entity(cfs_rq_of(se), se, lw->weight); + se->load.inv_weight =3D lw->inv_weight; + + if (!se->on_rq) + return; + + for_each_sched_entity(se) + weight =3D __calc_prop_weight(cfs_rq_of(se), se, weight); =20 - reweight_entity(cfs_rq, se, lw->weight); - load->inv_weight =3D lw->inv_weight; + reweight_eevdf(&rq->cfs, &p->se, weight, p->se.on_rq); } =20 static inline int throttled_hierarchy(struct cfs_rq *cfs_rq); @@ -4331,7 +4349,6 @@ static long calc_group_shares(struct cfs static void update_cfs_group(struct sched_entity *se) { struct cfs_rq *gcfs_rq =3D group_cfs_rq(se); - long shares; =20 /* * When a group becomes empty, preserve its weight. This matters for @@ -4340,9 +4357,7 @@ static void update_cfs_group(struct sche if (!gcfs_rq || !gcfs_rq->load.weight) return; =20 - shares =3D calc_group_shares(gcfs_rq); - if (unlikely(se->load.weight !=3D shares)) - reweight_entity(cfs_rq_of(se), se, shares); + reweight_entity(cfs_rq_of(se), se, calc_group_shares(gcfs_rq)); } =20 #else /* !CONFIG_FAIR_GROUP_SCHED: */ @@ -4460,7 +4475,7 @@ static inline bool cfs_rq_is_decayed(str * differential update where we store the last value we propagated. This in * turn allows skipping updates if the differential is 'small'. * - * Updating tg's load_avg is necessary before update_cfs_share(). + * Updating tg's load_avg is necessary before update_cfs_group(). */ static inline void update_tg_load_avg(struct cfs_rq *cfs_rq) { @@ -4926,7 +4941,7 @@ static void migrate_se_pelt_lag(struct s * The cfs_rq avg is the direct sum of all its entities (blocked and runna= ble) * avg. The immediate corollary is that all (fair) tasks must be attached. * - * cfs_rq->avg is used for task_h_load() and update_cfs_share() for exampl= e. + * cfs_rq->avg is used for task_h_load() and update_cfs_group() for exampl= e. * * Return: true if the load decayed or we removed load. * @@ -5475,6 +5490,7 @@ static void place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) { u64 vslice, vruntime =3D avg_vruntime(cfs_rq); + unsigned int nr_queued =3D cfs_rq->h_nr_queued; bool update_zero =3D false; s64 lag =3D 0; =20 @@ -5482,6 +5498,9 @@ place_entity(struct cfs_rq *cfs_rq, stru se->slice =3D sysctl_sched_base_slice; vslice =3D calc_delta_fair(se->slice, se); =20 + if (flags & ENQUEUE_QUEUED) + nr_queued -=3D 1; + /* * Due to how V is constructed as the weighted average of entities, * adding tasks with positive lag, or removing tasks with negative lag @@ -5490,7 +5509,7 @@ place_entity(struct cfs_rq *cfs_rq, stru * * EEVDF: placement strategy #1 / #2 */ - if (sched_feat(PLACE_LAG) && cfs_rq->nr_queued && se->vlag) { + if (sched_feat(PLACE_LAG) && nr_queued && se->vlag) { struct sched_entity *curr =3D cfs_rq->curr; long load, weight; =20 @@ -5550,9 +5569,9 @@ place_entity(struct cfs_rq *cfs_rq, stru */ load =3D cfs_rq->sum_weight; if (curr && curr->on_rq) - load +=3D avg_vruntime_weight(cfs_rq, curr->load.weight); + load +=3D avg_vruntime_weight(cfs_rq, curr->h_load.weight); =20 - weight =3D avg_vruntime_weight(cfs_rq, se->load.weight); + weight =3D avg_vruntime_weight(cfs_rq, se->h_load.weight); lag *=3D load + weight; if (WARN_ON_ONCE(!load)) load =3D 1; @@ -5611,22 +5630,8 @@ static void check_enqueue_throttle(struc static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq); =20 static void -requeue_delayed_entity(struct sched_entity *se); - -static void enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) { - bool curr =3D cfs_rq->curr =3D=3D se; - - /* - * If we're the current task, we must renormalise before calling - * update_curr(). - */ - if (curr) - place_entity(cfs_rq, se, flags); - - update_curr(cfs_rq); - /* * When enqueuing a sched_entity, we must: * - Update loads to have both entity and cfs_rq synced with now. @@ -5645,13 +5650,6 @@ enqueue_entity(struct cfs_rq *cfs_rq, st */ update_cfs_group(se); =20 - /* - * XXX now that the entity has been re-weighted, and it's lag adjusted, - * we can place the entity. - */ - if (!curr) - place_entity(cfs_rq, se, flags); - account_entity_enqueue(cfs_rq, se); =20 /* Entity has migrated, no longer consider this task hot */ @@ -5660,8 +5658,6 @@ enqueue_entity(struct cfs_rq *cfs_rq, st =20 check_schedstat_required(); update_stats_enqueue_fair(cfs_rq, se, flags); - if (!curr) - __enqueue_entity(cfs_rq, se); se->on_rq =3D 1; =20 if (cfs_rq->nr_queued =3D=3D 1) { @@ -5679,21 +5675,19 @@ enqueue_entity(struct cfs_rq *cfs_rq, st } } =20 -static void __clear_buddies_next(struct sched_entity *se) +static void set_next_buddy(struct cfs_rq *cfs_rq, struct sched_entity *se) { - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq =3D cfs_rq_of(se); - if (cfs_rq->next !=3D se) - break; - - cfs_rq->next =3D NULL; - } + if (WARN_ON_ONCE(!se->on_rq || se->sched_delayed)) + return; + if (se_is_idle(se)) + return; + cfs_rq->next =3D se; } =20 static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se) { if (cfs_rq->next =3D=3D se) - __clear_buddies_next(se); + cfs_rq->next =3D NULL; } =20 static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq); @@ -5704,7 +5698,7 @@ static void set_delayed(struct sched_ent =20 /* * Delayed se of cfs_rq have no tasks queued on them. - * Do not adjust h_nr_runnable since dequeue_entities() + * Do not adjust h_nr_runnable since __dequeue_task() * will account it for blocked tasks. */ if (!entity_is_task(se)) @@ -5737,37 +5731,11 @@ static void clear_delayed(struct sched_e } } =20 -static bool +static void dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) { - bool sleep =3D flags & DEQUEUE_SLEEP; int action =3D UPDATE_TG; =20 - update_curr(cfs_rq); - clear_buddies(cfs_rq, se); - - if (flags & DEQUEUE_DELAYED) { - WARN_ON_ONCE(!se->sched_delayed); - } else { - bool delay =3D sleep; - /* - * DELAY_DEQUEUE relies on spurious wakeups, special task - * states must not suffer spurious wakeups, excempt them. - */ - if (flags & (DEQUEUE_SPECIAL | DEQUEUE_THROTTLE)) - delay =3D false; - - WARN_ON_ONCE(delay && se->sched_delayed); - - if (sched_feat(DELAY_DEQUEUE) && delay && - !entity_eligible(cfs_rq, se)) { - update_load_avg(cfs_rq, se, 0); - update_entity_lag(cfs_rq, se); - set_delayed(se); - return false; - } - } - if (entity_is_task(se) && task_on_rq_migrating(task_of(se))) action |=3D DO_DETACH; =20 @@ -5785,14 +5753,6 @@ dequeue_entity(struct cfs_rq *cfs_rq, st =20 update_stats_dequeue_fair(cfs_rq, se, flags); =20 - update_entity_lag(cfs_rq, se); - if (sched_feat(PLACE_REL_DEADLINE) && !sleep) { - se->deadline -=3D se->vruntime; - se->rel_deadline =3D 1; - } - - if (se !=3D cfs_rq->curr) - __dequeue_entity(cfs_rq, se); se->on_rq =3D 0; account_entity_dequeue(cfs_rq, se); =20 @@ -5801,9 +5761,6 @@ dequeue_entity(struct cfs_rq *cfs_rq, st =20 update_cfs_group(se); =20 - if (flags & DEQUEUE_DELAYED) - clear_delayed(se); - if (cfs_rq->nr_queued =3D=3D 0) { update_idle_cfs_rq_clock_pelt(cfs_rq); #ifdef CONFIG_CFS_BANDWIDTH @@ -5816,15 +5773,11 @@ dequeue_entity(struct cfs_rq *cfs_rq, st } #endif } - - return true; } =20 static void -set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, bool first) +set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) { - clear_buddies(cfs_rq, se); - /* 'current' is not kept within the tree. */ if (se->on_rq) { /* @@ -5833,16 +5786,12 @@ set_next_entity(struct cfs_rq *cfs_rq, s * runqueue. */ update_stats_wait_end_fair(cfs_rq, se); - __dequeue_entity(cfs_rq, se); update_load_avg(cfs_rq, se, UPDATE_TG); - - if (first) - set_protect_slice(cfs_rq, se); } =20 update_stats_curr_start(cfs_rq, se); - WARN_ON_ONCE(cfs_rq->curr); - cfs_rq->curr =3D se; + WARN_ON_ONCE(cfs_rq->h_curr); + cfs_rq->h_curr =3D se; =20 /* * Track our maximum slice length, if the CPU's load is at @@ -5862,23 +5811,17 @@ set_next_entity(struct cfs_rq *cfs_rq, s se->prev_sum_exec_runtime =3D se->sum_exec_runtime; } =20 -static int dequeue_entities(struct rq *rq, struct sched_entity *se, int fl= ags); +static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags= ); =20 -/* - * Pick the next process, keeping these things in mind, in this order: - * 1) keep things fair between processes/task groups - * 2) pick the "next" process, since someone really wants that to run - * 3) pick the "last" process, for cache locality - * 4) do not run the "skip" process, if something else is available - */ static struct sched_entity * -pick_next_entity(struct rq *rq, struct cfs_rq *cfs_rq, bool protect) +pick_next_entity(struct rq *rq, bool protect) { + struct cfs_rq *cfs_rq =3D &rq->cfs; struct sched_entity *se; =20 se =3D pick_eevdf(cfs_rq, protect); if (se->sched_delayed) { - dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); + __dequeue_task(rq, task_of(se), DEQUEUE_SLEEP | DEQUEUE_DELAYED); /* * Must not reference @se again, see __block_task(). */ @@ -5903,13 +5846,11 @@ static void put_prev_entity(struct cfs_r =20 if (prev->on_rq) { update_stats_wait_start_fair(cfs_rq, prev); - /* Put 'current' back into the tree. */ - __enqueue_entity(cfs_rq, prev); /* in !on_rq case, update occurred at dequeue */ update_load_avg(cfs_rq, prev, 0); } - WARN_ON_ONCE(cfs_rq->curr !=3D prev); - cfs_rq->curr =3D NULL; + WARN_ON_ONCE(cfs_rq->h_curr !=3D prev); + cfs_rq->h_curr =3D NULL; } =20 static void @@ -6062,7 +6003,7 @@ static void __account_cfs_rq_runtime(str * if we're unable to extend our runtime we resched so that the active * hierarchy can be throttled */ - if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr)) + if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->h_curr)) resched_curr(rq_of(cfs_rq)); } =20 @@ -6420,7 +6361,7 @@ void unthrottle_cfs_rq(struct cfs_rq *cf assert_list_leaf_cfs_rq(rq); =20 /* Determine whether we need to wake up potentially idle CPU: */ - if (rq->curr =3D=3D rq->idle && rq->cfs.nr_queued) + if (rq->curr =3D=3D rq->idle && rq->cfs.h_nr_queued) resched_curr(rq); } =20 @@ -6761,7 +6702,7 @@ static void check_enqueue_throttle(struc return; =20 /* an active group must be handled by the update_curr()->put() path */ - if (!cfs_rq->runtime_enabled || cfs_rq->curr) + if (!cfs_rq->runtime_enabled || cfs_rq->h_curr) return; =20 /* ensure the group is not already throttled */ @@ -7156,7 +7097,7 @@ static void hrtick_start_fair(struct rq resched_curr(rq); return; } - delta =3D (se->load.weight * vdelta) / NICE_0_LOAD; + delta =3D (se->h_load.weight * vdelta) / NICE_0_LOAD; =20 /* * Correct for instantaneous load of other classes. @@ -7256,10 +7197,8 @@ static int choose_idle_cpu(int cpu, stru } =20 static void -requeue_delayed_entity(struct sched_entity *se) +requeue_delayed_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) { - struct cfs_rq *cfs_rq =3D cfs_rq_of(se); - /* * se->sched_delayed should imply: se->on_rq =3D=3D 1. * Because a delayed entity is one that is still on @@ -7269,19 +7208,58 @@ requeue_delayed_entity(struct sched_enti WARN_ON_ONCE(!se->on_rq); =20 if (update_entity_lag(cfs_rq, se)) { - cfs_rq->nr_queued--; + cfs_rq->h_nr_queued--; if (se !=3D cfs_rq->curr) __dequeue_entity(cfs_rq, se); place_entity(cfs_rq, se, 0); if (se !=3D cfs_rq->curr) __enqueue_entity(cfs_rq, se); - cfs_rq->nr_queued++; + cfs_rq->h_nr_queued++; } =20 update_load_avg(cfs_rq, se, 0); clear_delayed(se); } =20 +static unsigned long enqueue_hierarchy(struct task_struct *p, int flags) +{ + unsigned long weight =3D NICE_0_LOAD; + int task_new =3D !(flags & ENQUEUE_WAKEUP); + struct sched_entity *se =3D &p->se; + int h_nr_idle =3D task_has_idle_policy(p); + int h_nr_runnable =3D 1; + + if (task_new && se->sched_delayed) + h_nr_runnable =3D 0; + + for_each_sched_entity(se) { + struct cfs_rq *cfs_rq =3D cfs_rq_of(se); + + update_curr(cfs_rq); + + if (!se->on_rq) { + enqueue_entity(cfs_rq, se, flags); + } else { + update_load_avg(cfs_rq, se, UPDATE_TG); + se_update_runnable(se); + update_cfs_group(se); + } + + cfs_rq->h_nr_runnable +=3D h_nr_runnable; + cfs_rq->h_nr_queued++; + cfs_rq->h_nr_idle +=3D h_nr_idle; + + if (cfs_rq_is_idle(cfs_rq)) + h_nr_idle =3D 1; + + weight =3D __calc_prop_weight(cfs_rq, se, weight); + + flags =3D ENQUEUE_WAKEUP; + } + + return weight; +} + /* * The enqueue_task method is called before nr_running is * increased. Here we update the fair scheduling stats and @@ -7290,13 +7268,12 @@ requeue_delayed_entity(struct sched_enti static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) { - struct cfs_rq *cfs_rq; - struct sched_entity *se =3D &p->se; - int h_nr_idle =3D task_has_idle_policy(p); - int h_nr_runnable =3D 1; - int task_new =3D !(flags & ENQUEUE_WAKEUP); int rq_h_nr_queued =3D rq->cfs.h_nr_queued; - u64 slice =3D 0; + int task_new =3D !(flags & ENQUEUE_WAKEUP); + struct sched_entity *se =3D &p->se; + struct cfs_rq *cfs_rq =3D &rq->cfs; + unsigned long weight; + bool curr; =20 if (task_is_throttled(p) && enqueue_throttled_task(p)) return; @@ -7308,10 +7285,10 @@ enqueue_task_fair(struct rq *rq, struct * estimated utilization, before we update schedutil. */ if (!p->se.sched_delayed || (flags & ENQUEUE_DELAYED)) - util_est_enqueue(&rq->cfs, p); + util_est_enqueue(cfs_rq, p); =20 if (flags & ENQUEUE_DELAYED) { - requeue_delayed_entity(se); + requeue_delayed_entity(cfs_rq, se); return; } =20 @@ -7323,57 +7300,22 @@ enqueue_task_fair(struct rq *rq, struct if (p->in_iowait) cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT); =20 - if (task_new && se->sched_delayed) - h_nr_runnable =3D 0; - - for_each_sched_entity(se) { - if (se->on_rq) { - if (se->sched_delayed) - requeue_delayed_entity(se); - break; - } - cfs_rq =3D cfs_rq_of(se); - - /* - * Basically set the slice of group entries to the min_slice of - * their respective cfs_rq. This ensures the group can service - * its entities in the desired time-frame. - */ - if (slice) { - se->slice =3D slice; - se->custom_slice =3D 1; - } - enqueue_entity(cfs_rq, se, flags); - slice =3D cfs_rq_min_slice(cfs_rq); - - cfs_rq->h_nr_runnable +=3D h_nr_runnable; - cfs_rq->h_nr_queued++; - cfs_rq->h_nr_idle +=3D h_nr_idle; - - if (cfs_rq_is_idle(cfs_rq)) - h_nr_idle =3D 1; - - flags =3D ENQUEUE_WAKEUP; - } - - for_each_sched_entity(se) { - cfs_rq =3D cfs_rq_of(se); - - update_load_avg(cfs_rq, se, UPDATE_TG); - se_update_runnable(se); - update_cfs_group(se); + /* + * XXX comment on the curr thing + */ + curr =3D (cfs_rq->curr =3D=3D se); + if (curr) + place_entity(cfs_rq, se, flags); =20 - se->slice =3D slice; - if (se !=3D cfs_rq->curr) - min_vruntime_cb_propagate(&se->run_node, NULL); - slice =3D cfs_rq_min_slice(cfs_rq); + if (se->on_rq && se->sched_delayed) + requeue_delayed_entity(cfs_rq, se); =20 - cfs_rq->h_nr_runnable +=3D h_nr_runnable; - cfs_rq->h_nr_queued++; - cfs_rq->h_nr_idle +=3D h_nr_idle; + weight =3D enqueue_hierarchy(p, flags); =20 - if (cfs_rq_is_idle(cfs_rq)) - h_nr_idle =3D 1; + if (!curr) { + reweight_eevdf(cfs_rq, se, weight, false); + place_entity(cfs_rq, se, flags | ENQUEUE_QUEUED); + __enqueue_entity(cfs_rq, se); } =20 if (!rq_h_nr_queued && rq->cfs.h_nr_queued) @@ -7404,105 +7346,107 @@ enqueue_task_fair(struct rq *rq, struct hrtick_update(rq); } =20 -/* - * Basically dequeue_task_fair(), except it can deal with dequeue_entity() - * failing half-way through and resume the dequeue later. - * - * Returns: - * -1 - dequeue delayed - * 0 - dequeue throttled - * 1 - dequeue complete - */ -static int dequeue_entities(struct rq *rq, struct sched_entity *se, int fl= ags) +static void dequeue_hierarchy(struct task_struct *p, int flags) { - bool was_sched_idle =3D sched_idle_rq(rq); + struct sched_entity *se =3D &p->se; bool task_sleep =3D flags & DEQUEUE_SLEEP; bool task_delayed =3D flags & DEQUEUE_DELAYED; bool task_throttled =3D flags & DEQUEUE_THROTTLE; - struct task_struct *p =3D NULL; - int h_nr_idle =3D 0; - int h_nr_queued =3D 0; int h_nr_runnable =3D 0; - struct cfs_rq *cfs_rq; - u64 slice =3D 0; + int h_nr_idle =3D task_has_idle_policy(p); + bool dequeue =3D true; =20 - if (entity_is_task(se)) { - p =3D task_of(se); - h_nr_queued =3D 1; - h_nr_idle =3D task_has_idle_policy(p); - if (task_sleep || task_delayed || !se->sched_delayed) - h_nr_runnable =3D 1; - } + if (task_sleep || task_delayed || !se->sched_delayed) + h_nr_runnable =3D 1; =20 for_each_sched_entity(se) { - cfs_rq =3D cfs_rq_of(se); + struct cfs_rq *cfs_rq =3D cfs_rq_of(se); =20 - if (!dequeue_entity(cfs_rq, se, flags)) { - if (p && &p->se =3D=3D se) - return -1; + update_curr(cfs_rq); =20 - slice =3D cfs_rq_min_slice(cfs_rq); - break; + if (dequeue) { + dequeue_entity(cfs_rq, se, flags); + /* Don't dequeue parent if it has other entities besides us */ + if (cfs_rq->load.weight) + dequeue =3D false; + } else { + update_load_avg(cfs_rq, se, UPDATE_TG); + se_update_runnable(se); + update_cfs_group(se); } =20 cfs_rq->h_nr_runnable -=3D h_nr_runnable; - cfs_rq->h_nr_queued -=3D h_nr_queued; + cfs_rq->h_nr_queued--; cfs_rq->h_nr_idle -=3D h_nr_idle; =20 if (cfs_rq_is_idle(cfs_rq)) - h_nr_idle =3D h_nr_queued; + h_nr_idle =3D 1; =20 if (throttled_hierarchy(cfs_rq) && task_throttled) record_throttle_clock(cfs_rq); =20 - /* Don't dequeue parent if it has other entities besides us */ - if (cfs_rq->load.weight) { - slice =3D cfs_rq_min_slice(cfs_rq); - - /* Avoid re-evaluating load for this entity: */ - se =3D parent_entity(se); - /* - * Bias pick_next to pick a task from this cfs_rq, as - * p is sleeping when it is within its sched_slice. - */ - if (task_sleep && se) - set_next_buddy(se); - break; - } flags |=3D DEQUEUE_SLEEP; flags &=3D ~(DEQUEUE_DELAYED | DEQUEUE_SPECIAL); } +} =20 - for_each_sched_entity(se) { - cfs_rq =3D cfs_rq_of(se); +/* + * The part of dequeue_task_fair() that is needed to dequeue delayed tasks. + * + * Returns: + * true - dequeued + * false - delayed + */ +static bool __dequeue_task(struct rq *rq, struct task_struct *p, int flags) +{ + struct sched_entity *se =3D &p->se; + struct cfs_rq *cfs_rq =3D &rq->cfs; + bool was_sched_idle =3D sched_idle_rq(rq); + bool task_sleep =3D flags & DEQUEUE_SLEEP; + bool task_delayed =3D flags & DEQUEUE_DELAYED; =20 - update_load_avg(cfs_rq, se, UPDATE_TG); - se_update_runnable(se); - update_cfs_group(se); + clear_buddies(cfs_rq, se); =20 - se->slice =3D slice; - if (se !=3D cfs_rq->curr) - min_vruntime_cb_propagate(&se->run_node, NULL); - slice =3D cfs_rq_min_slice(cfs_rq); + if (flags & DEQUEUE_DELAYED) { + WARN_ON_ONCE(!se->sched_delayed); + } else { + bool delay =3D task_sleep; + /* + * DELAY_DEQUEUE relies on spurious wakeups, special task + * states must not suffer spurious wakeups, excempt them. + */ + if (flags & (DEQUEUE_SPECIAL | DEQUEUE_THROTTLE)) + delay =3D false; =20 - cfs_rq->h_nr_runnable -=3D h_nr_runnable; - cfs_rq->h_nr_queued -=3D h_nr_queued; - cfs_rq->h_nr_idle -=3D h_nr_idle; + WARN_ON_ONCE(delay && se->sched_delayed); =20 - if (cfs_rq_is_idle(cfs_rq)) - h_nr_idle =3D h_nr_queued; + if (sched_feat(DELAY_DEQUEUE) && delay && + !entity_eligible(cfs_rq, se)) { + update_load_avg(cfs_rq_of(se), se, 0); + set_delayed(se); + return false; + } + } =20 - if (throttled_hierarchy(cfs_rq) && task_throttled) - record_throttle_clock(cfs_rq); + dequeue_hierarchy(p, flags); + + update_entity_lag(cfs_rq, se); + if (sched_feat(PLACE_REL_DEADLINE) && !task_sleep) { + se->deadline -=3D se->vruntime; + se->rel_deadline =3D 1; } + if (se !=3D cfs_rq->curr) + __dequeue_entity(cfs_rq, se); =20 - sub_nr_running(rq, h_nr_queued); + sub_nr_running(rq, 1); =20 /* balance early to pull high priority tasks */ if (unlikely(!was_sched_idle && sched_idle_rq(rq))) rq->next_balance =3D jiffies; =20 - if (p && task_delayed) { + if (task_delayed) { + clear_delayed(se); + WARN_ON_ONCE(!task_sleep); WARN_ON_ONCE(p->on_rq !=3D 1); =20 @@ -7514,7 +7458,7 @@ static int dequeue_entities(struct rq *r __block_task(rq, p); } =20 - return 1; + return true; } =20 /* @@ -7533,11 +7477,11 @@ static bool dequeue_task_fair(struct rq util_est_dequeue(&rq->cfs, p); =20 util_est_update(&rq->cfs, p, flags & DEQUEUE_SLEEP); - if (dequeue_entities(rq, &p->se, flags) < 0) + if (!__dequeue_task(rq, p, flags)) return false; =20 /* - * Must not reference @p after dequeue_entities(DEQUEUE_DELAYED). + * Must not reference @p after __dequeue_task(DEQUEUE_DELAYED). */ return true; } @@ -9021,19 +8965,6 @@ static void migrate_task_rq_fair(struct static void task_dead_fair(struct task_struct *p) { struct sched_entity *se =3D &p->se; - - if (se->sched_delayed) { - struct rq_flags rf; - struct rq *rq; - - rq =3D task_rq_lock(p, &rf); - if (se->sched_delayed) { - update_rq_clock(rq); - dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); - } - task_rq_unlock(rq, p, &rf); - } - remove_entity_load_avg(se); } =20 @@ -9067,21 +8998,10 @@ static void set_cpus_allowed_fair(struct set_task_max_allowed_capacity(p); } =20 -static void set_next_buddy(struct sched_entity *se) -{ - for_each_sched_entity(se) { - if (WARN_ON_ONCE(!se->on_rq)) - return; - if (se_is_idle(se)) - return; - cfs_rq_of(se)->next =3D se; - } -} - enum preempt_wakeup_action { PREEMPT_WAKEUP_NONE, /* No preemption. */ PREEMPT_WAKEUP_SHORT, /* Ignore slice protection. */ - PREEMPT_WAKEUP_PICK, /* Let __pick_eevdf() decide. */ + PREEMPT_WAKEUP_PICK, /* Let pick_eevdf() decide. */ PREEMPT_WAKEUP_RESCHED, /* Force reschedule. */ }; =20 @@ -9098,7 +9018,7 @@ set_preempt_buddy(struct cfs_rq *cfs_rq, if (cfs_rq->next && entity_before(cfs_rq->next, pse)) return false; =20 - set_next_buddy(pse); + set_next_buddy(cfs_rq, pse); return true; } =20 @@ -9188,7 +9108,6 @@ static void wakeup_preempt_fair(struct r if (!sched_feat(WAKEUP_PREEMPTION)) return; =20 - find_matching_se(&se, &pse); WARN_ON_ONCE(!pse); =20 cse_is_idle =3D se_is_idle(se); @@ -9216,8 +9135,7 @@ static void wakeup_preempt_fair(struct r if (unlikely(!normal_policy(p->policy))) return; =20 - cfs_rq =3D cfs_rq_of(se); - update_curr(cfs_rq); + update_curr_fair(rq); /* * If @p has a shorter slice than current and @p is eligible, override * current's slice protection in order to allow preemption. @@ -9261,18 +9179,15 @@ static void wakeup_preempt_fair(struct r } =20 pick: - nse =3D pick_next_entity(rq, cfs_rq, preempt_action !=3D PREEMPT_WAKEUP_S= HORT); - /* If @p has become the most eligible task, force preemption */ - if (nse =3D=3D pse) - goto preempt; - - /* - * Because p is enqueued, nse being null can only mean that we - * dequeued a delayed task. If there are still entities queued in - * cfs, check if the next one will be p. - */ - if (!nse && cfs_rq->nr_queued) - goto pick; + if (cfs_rq->h_nr_queued) { + nse =3D pick_next_entity(rq, preempt_action !=3D PREEMPT_WAKEUP_SHORT); + if (unlikely(!nse)) + goto pick; + + /* If @p has become the most eligible task, force preemption */ + if (nse =3D=3D pse) + goto preempt; + } =20 if (sched_feat(RUN_TO_PARITY)) update_protect_slice(cfs_rq, se); @@ -9291,34 +9206,25 @@ static void wakeup_preempt_fair(struct r struct task_struct *pick_task_fair(struct rq *rq, struct rq_flags *rf) __must_hold(__rq_lockp(rq)) { + struct cfs_rq *cfs_rq =3D &rq->cfs; struct sched_entity *se; - struct cfs_rq *cfs_rq; struct task_struct *p; - bool throttled; int new_tasks; =20 again: - cfs_rq =3D &rq->cfs; - if (!cfs_rq->nr_queued) + if (!cfs_rq->h_nr_queued) goto idle; =20 - throttled =3D false; - - do { - /* Might not have done put_prev_entity() */ - if (cfs_rq->curr && cfs_rq->curr->on_rq) - update_curr(cfs_rq); - - throttled |=3D check_cfs_rq_runtime(cfs_rq); + /* Might not have done put_prev_entity() */ + if (cfs_rq->curr && cfs_rq->curr->on_rq) + update_curr(cfs_rq); =20 - se =3D pick_next_entity(rq, cfs_rq, true); - if (!se) - goto again; - cfs_rq =3D group_cfs_rq(se); - } while (cfs_rq); + se =3D pick_next_entity(rq, true); + if (!se) + goto again; =20 p =3D task_of(se); - if (unlikely(throttled)) + if (unlikely(check_cfs_rq_runtime(cfs_rq_of(se)))) task_throttle_setup_work(p); return p; =20 @@ -9353,7 +9259,7 @@ void fair_server_init(struct rq *rq) static void put_prev_task_fair(struct rq *rq, struct task_struct *prev, st= ruct task_struct *next) { struct sched_entity *se =3D &prev->se; - struct cfs_rq *cfs_rq; + struct cfs_rq *cfs_rq =3D &rq->cfs; struct sched_entity *nse =3D NULL; =20 #ifdef CONFIG_FAIR_GROUP_SCHED @@ -9363,7 +9269,7 @@ static void put_prev_task_fair(struct rq =20 while (se) { cfs_rq =3D cfs_rq_of(se); - if (!nse || cfs_rq->curr) + if (!nse || cfs_rq->h_curr) put_prev_entity(cfs_rq, se); #ifdef CONFIG_FAIR_GROUP_SCHED if (nse) { @@ -9382,6 +9288,14 @@ static void put_prev_task_fair(struct rq #endif se =3D parent_entity(se); } + + /* Put 'current' back into the tree. */ + cfs_rq =3D &rq->cfs; + se =3D &prev->se; + WARN_ON_ONCE(cfs_rq->curr !=3D se); + cfs_rq->curr =3D NULL; + if (se->on_rq) + __enqueue_entity(cfs_rq, se); } =20 /* @@ -9390,8 +9304,8 @@ static void put_prev_task_fair(struct rq static void yield_task_fair(struct rq *rq) { struct task_struct *curr =3D rq->donor; - struct cfs_rq *cfs_rq =3D task_cfs_rq(curr); struct sched_entity *se =3D &curr->se; + struct cfs_rq *cfs_rq =3D &rq->cfs; =20 /* * Are we the only task in the tree? @@ -9432,11 +9346,11 @@ static bool yield_to_task_fair(struct rq struct sched_entity *se =3D &p->se; =20 /* !se->on_rq also covers throttled task */ - if (!se->on_rq) + if (!se->on_rq || se->sched_delayed) return false; =20 /* Tell the scheduler that we'd really like se to run next. */ - set_next_buddy(se); + set_next_buddy(&task_rq(p)->cfs, se); =20 yield_task_fair(rq); =20 @@ -9762,15 +9676,10 @@ static inline long migrate_degrades_loca */ static inline int task_is_ineligible_on_dst_cpu(struct task_struct *p, int= dest_cpu) { - struct cfs_rq *dst_cfs_rq; + struct cfs_rq *dst_cfs_rq =3D &cpu_rq(dest_cpu)->cfs; =20 -#ifdef CONFIG_FAIR_GROUP_SCHED - dst_cfs_rq =3D task_group(p)->cfs_rq[dest_cpu]; -#else - dst_cfs_rq =3D &cpu_rq(dest_cpu)->cfs; -#endif - if (sched_feat(PLACE_LAG) && dst_cfs_rq->nr_queued && - !entity_eligible(task_cfs_rq(p), &p->se)) + if (sched_feat(PLACE_LAG) && dst_cfs_rq->h_nr_queued && + !entity_eligible(&task_rq(p)->cfs, &p->se)) return 1; =20 return 0; @@ -10240,7 +10149,7 @@ static void update_cfs_rq_h_load(struct while ((se =3D READ_ONCE(cfs_rq->h_load_next)) !=3D NULL) { load =3D cfs_rq->h_load; load =3D div64_ul(load * se->avg.load_avg, - cfs_rq_load_avg(cfs_rq) + 1); + cfs_rq_load_avg(cfs_rq) + 1); cfs_rq =3D group_cfs_rq(se); cfs_rq->h_load =3D load; cfs_rq->last_h_load_update =3D now; @@ -13459,7 +13368,7 @@ static inline void task_tick_core(struct * MIN_NR_TASKS_DURING_FORCEIDLE - 1 tasks and use that to check * if we need to give up the CPU. */ - if (rq->core->core_forceidle_count && rq->cfs.nr_queued =3D=3D 1 && + if (rq->core->core_forceidle_count && rq->cfs.h_nr_queued =3D=3D 1 && __entity_slice_used(&curr->se, MIN_NR_TASKS_DURING_FORCEIDLE)) resched_curr(rq); } @@ -13668,30 +13577,8 @@ bool cfs_prio_less(const struct task_str =20 WARN_ON_ONCE(task_rq(b)->core !=3D rq->core); =20 -#ifdef CONFIG_FAIR_GROUP_SCHED - /* - * Find an se in the hierarchy for tasks a and b, such that the se's - * are immediate siblings. - */ - while (sea->cfs_rq->tg !=3D seb->cfs_rq->tg) { - int sea_depth =3D sea->depth; - int seb_depth =3D seb->depth; - - if (sea_depth >=3D seb_depth) - sea =3D parent_entity(sea); - if (sea_depth <=3D seb_depth) - seb =3D parent_entity(seb); - } - - se_fi_update(sea, rq->core->core_forceidle_seq, in_fi); - se_fi_update(seb, rq->core->core_forceidle_seq, in_fi); - - cfs_rqa =3D sea->cfs_rq; - cfs_rqb =3D seb->cfs_rq; -#else /* !CONFIG_FAIR_GROUP_SCHED: */ cfs_rqa =3D &task_rq(a)->cfs; cfs_rqb =3D &task_rq(b)->cfs; -#endif /* !CONFIG_FAIR_GROUP_SCHED */ =20 /* * Find delta after normalizing se's vruntime with its cfs_rq's @@ -13729,14 +13616,20 @@ static inline void task_tick_core(struct */ static void task_tick_fair(struct rq *rq, struct task_struct *curr, int qu= eued) { - struct cfs_rq *cfs_rq; struct sched_entity *se =3D &curr->se; + unsigned long weight =3D NICE_0_LOAD; + struct cfs_rq *cfs_rq; =20 for_each_sched_entity(se) { cfs_rq =3D cfs_rq_of(se); entity_tick(cfs_rq, se, queued); + + weight =3D __calc_prop_weight(cfs_rq, se, weight); } =20 + se =3D &curr->se; + reweight_eevdf(cfs_rq, se, weight, se->on_rq); + if (queued) return; =20 @@ -13772,7 +13665,7 @@ prio_changed_fair(struct rq *rq, struct if (p->prio =3D=3D oldprio) return; =20 - if (rq->cfs.nr_queued =3D=3D 1) + if (rq->cfs.h_nr_queued =3D=3D 1) return; =20 /* @@ -13901,29 +13794,40 @@ static void switched_to_fair(struct rq * } } =20 -/* - * Account for a task changing its policy or group. - * - * This routine is mostly called to set cfs_rq->curr field when a task - * migrates between groups/classes. - */ static void set_next_task_fair(struct rq *rq, struct task_struct *p, bool = first) { struct sched_entity *se =3D &p->se; + struct cfs_rq *cfs_rq =3D &rq->cfs; + unsigned long weight =3D NICE_0_LOAD; + bool on_rq =3D se->on_rq; + + clear_buddies(cfs_rq, se); + + if (on_rq) + __dequeue_entity(cfs_rq, se); =20 for_each_sched_entity(se) { - struct cfs_rq *cfs_rq =3D cfs_rq_of(se); + cfs_rq =3D cfs_rq_of(se); =20 - if (IS_ENABLED(CONFIG_FAIR_GROUP_SCHED) && - first && cfs_rq->curr) - break; + if (!IS_ENABLED(CONFIG_FAIR_GROUP_SCHED) || + !first || !cfs_rq->h_curr) + set_next_entity(cfs_rq, se); =20 - set_next_entity(cfs_rq, se, first); /* ensure bandwidth has been allocated on our new cfs_rq */ account_cfs_rq_runtime(cfs_rq, 0); + + if (on_rq) + weight =3D __calc_prop_weight(cfs_rq, se, weight); } =20 se =3D &p->se; + cfs_rq->curr =3D se; + + if (on_rq) { + reweight_eevdf(cfs_rq, se, weight, se->on_rq); + if (first) + set_protect_slice(cfs_rq, se); + } =20 if (task_on_rq_queued(p)) { /* @@ -14054,17 +13958,8 @@ void unregister_fair_sched_group(struct struct sched_entity *se =3D tg->se[cpu]; struct rq *rq =3D cpu_rq(cpu); =20 - if (se) { - if (se->sched_delayed) { - guard(rq_lock_irqsave)(rq); - if (se->sched_delayed) { - update_rq_clock(rq); - dequeue_entities(rq, se, DEQUEUE_SLEEP | DEQUEUE_DELAYED); - } - list_del_leaf_cfs_rq(cfs_rq); - } + if (se) remove_entity_load_avg(se); - } =20 /* * Only empty task groups can be destroyed; so we can speculatively --- a/kernel/sched/pelt.c +++ b/kernel/sched/pelt.c @@ -206,7 +206,7 @@ ___update_load_sum(u64 now, struct sched /* * running is a subset of runnable (weight) so running can't be set if * runnable is clear. But there are some corner cases where the current - * se has been already dequeued but cfs_rq->curr still points to it. + * se has been already dequeued but cfs_rq->h_curr still points to it. * This means that weight will be 0 but not running for a sched_entity * but also for a cfs_rq if the latter becomes idle. As an example, * this happens during sched_balance_newidle() which calls @@ -307,7 +307,7 @@ int __update_load_avg_blocked_se(u64 now int __update_load_avg_se(u64 now, struct cfs_rq *cfs_rq, struct sched_enti= ty *se) { if (___update_load_sum(now, &se->avg, !!se->on_rq, se_runnable(se), - cfs_rq->curr =3D=3D se)) { + cfs_rq->h_curr =3D=3D se)) { =20 ___update_load_avg(&se->avg, se_weight(se)); cfs_se_util_change(&se->avg); @@ -323,7 +323,7 @@ int __update_load_avg_cfs_rq(u64 now, st if (___update_load_sum(now, &cfs_rq->avg, scale_load_down(cfs_rq->load.weight), cfs_rq->h_nr_runnable, - cfs_rq->curr !=3D NULL)) { + cfs_rq->h_curr !=3D NULL)) { =20 ___update_load_avg(&cfs_rq->avg, 1); trace_pelt_cfs_tp(cfs_rq); --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -528,21 +528,8 @@ struct task_group { =20 }; =20 -#ifdef CONFIG_GROUP_SCHED_WEIGHT #define ROOT_TASK_GROUP_LOAD NICE_0_LOAD =20 -/* - * A weight of 0 or 1 can cause arithmetics problems. - * A weight of a cfs_rq is the sum of weights of which entities - * are queued on this cfs_rq, so a weight of a entity should not be - * too large, so as the shares value of a task group. - * (The default weight is 1024 - so there's no practical - * limitation from this.) - */ -#define MIN_SHARES (1UL << 1) -#define MAX_SHARES (1UL << 18) -#endif - typedef int (*tg_visitor)(struct task_group *, void *); =20 extern int walk_tg_tree_from(struct task_group *from, @@ -629,6 +616,17 @@ static inline bool cfs_task_bw_constrain =20 #endif /* !CONFIG_CGROUP_SCHED */ =20 +/* + * A weight of 0 or 1 can cause arithmetics problems. + * A weight of a cfs_rq is the sum of weights of which entities + * are queued on this cfs_rq, so a weight of a entity should not be + * too large, so as the shares value of a task group. + * (The default weight is 1024 - so there's no practical + * limitation from this.) + */ +#define MIN_SHARES (1UL << 1) +#define MAX_SHARES (1UL << 18) + extern void unregister_rt_sched_group(struct task_group *tg); extern void free_rt_sched_group(struct task_group *tg); extern int alloc_rt_sched_group(struct task_group *tg, struct task_group *= parent); @@ -707,6 +705,7 @@ struct cfs_rq { /* * CFS load tracking */ + struct sched_entity *h_curr; struct sched_avg avg; #ifndef CONFIG_64BIT u64 last_update_time_copy; @@ -2509,6 +2508,7 @@ extern const u32 sched_prio_to_wmult[40 #define ENQUEUE_MIGRATED 0x00040000 #define ENQUEUE_INITIAL 0x00080000 #define ENQUEUE_RQ_SELECTED 0x00100000 +#define ENQUEUE_QUEUED 0x00200000 =20 #define RETRY_TASK ((void *)-1UL)