Linux Documentation
 help / color / mirror / Atom feed
From: Fernand Sieber <sieberf@amazon.com>
To: <mingo@redhat.com>, <peterz@infradead.org>,
	<juri.lelli@redhat.com>, <vincent.guittot@linaro.org>
Cc: <tj@kernel.org>, <bsegall@google.com>, <dietmar.eggemann@arm.com>,
	<rostedt@goodmis.org>, <mgorman@suse.de>, <vschneid@redhat.com>,
	<kprateek.nayak@amd.com>, <hannes@cmpxchg.org>,
	<mkoutny@suse.com>, <skhan@linuxfoundation.org>, <corbet@lwn.net>,
	<rdunlap@infradead.org>, <cgroups@vger.kernel.org>,
	<linux-doc@vger.kernel.org>, <linux-kselftest@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <nh-open-source@amazon.com>,
	<hborghor@amazon.de>, <fmubeen@amazon.de>, <dwmw@amazon.co.uk>,
	<sieberf@amazon.com>
Subject: [PATCH v3 0/2] sched/fair: cpu.max.runtime and idle refill for a burstable budget
Date: Wed, 11 Nov 2026 14:29:47 +0200	[thread overview]
Message-ID: <cover.1794398404.git.sieberf@amazon.com> (raw)
In-Reply-To: <cover.1794303670.git.sieberf@amazon.com>

This series makes the CFS bandwidth controller's bucket a burstable CPU
budget that userspace can save and restore. It lets cpu.max.burst exceed
the quota, so the bucket can hold more than one quota, and adds
cpu.max.runtime to read and set what it holds (patch 1). It makes a
group that is not running keep earning quota up to quota + burst
(patch 2).

v2 had two further patches that passed the level on to a BPF scheduler.
Tejun asked for the fair side first and on its own, so they are dropped
here and will be proposed separately if this is accepted.

Use case
========

We run virtual machines whose CPU time is governed by CPU credits, as
burstable instances are. An instance earns credits while it runs below
its baseline, spends them above it, and holds at most a capped amount;
with none left it is held to the baseline. The starting credits, the
baseline and the cap are part of the instance type's guarantee and must
hold whatever the host does to the instance.

Each instance's vCPU threads run in their own cgroup, and the controller
already is that bucket of credits: the quota per period is the rate
credits are earned at, quota + burst is the cap, and the runtime is the
level. It does the per-CPU charging and the throttling in the scheduler,
at a granularity userspace accounting cannot match. What is missing is a
cap above one quota, a way to read and write the level, and earning
while idle. An instance that idles for a minute with a 100ms period
earns one quota instead of up to 600.

The level has to be saved and restored by the host's control software:
an instance starts with the credits its type grants, not with one quota;
a host kernel live update (kexec) or a reboot creates the cgroups anew,
so every level has to be read before and written back after, or every
instance loses or gains credits; a live migration moves the level with
the instance; and the control plane raises or lowers it when credits
move between instances. A container checkpoint and restore has the same
problem.

Ben pointed out that a cpu.max or cpu.max.burst write already adds a
quota to the runtime, and that cpuacct gives the usage. That falls
short. A write can only add, and only one quota, so setting a level
means writing a temporary quota equal to the difference and then the
real quota back, and lowering one means shrinking the burst until the
cap cuts the runtime and widening it again; each leaves the cgroup
running with the wrong bandwidth in between, and each write visits every
CPU's cfs_rq. And usage is not the level: deriving it means replaying
every period's refill in userspace, including the periods the timer
slept through, which duplicates the controller's accounting.

Patch 2 changes behavior for existing cpu.max.burst users. A group with
a burst that becomes runnable after idling has up to quota + burst, as
if it had been running below its quota throughout, instead of the
runtime it had when the timer stopped. Groups without a burst see no
change.

Testing
=======

On tip/sched/core in qemu with lockdep, the cgroup test_cpu selftests
pass, 18 of 18, including the nine new ones for these two patches, with
no lockdep report in dmesg. Both patches build with W=1 and no warning
in kernel/sched, with and without CONFIG_CFS_BANDWIDTH and on 32-bit,
and kernel-doc reports nothing on the files they touch.

An AI coding assistant (Claude Code) helped write the selftests and
changelogs and ran the build and test matrix; I reviewed all of it.

Changes in v3
=============

- Patches 3 and 4, the sched_ext side, dropped (Tejun).
- Patch 1: cpu.max.runtime reads 0 while cpu.max is "max" instead of a
  level the group no longer has, and taking a group's quota away drops
  its runtime instead of keeping it for the next quota (kernel-patches
  CI); the lockdep_assert_irqs_disabled() in distribute_cfs_runtime()
  is gone, as both bandwidth timers run with hardirqs enabled on
  PREEMPT_RT, and a comment states the real precondition; the
  burst_kept selftest grants the runtime after a period has started,
  so a hog cannot burn it while the test waits; CONFIG_CFS_BANDWIDTH
  added to tools/testing/selftests/cgroup/config.
- Patch 2: a cpu.max write starts the next period from the write, so
  the first refill under a new period is one new period away and not up
  to one old period away; selftest for it.

v2: https://lore.kernel.org/all/cover.1794303670.git.sieberf@amazon.com/
v1: https://lore.kernel.org/all/20260525193622.70282-1-sieberf@amazon.com/

Fernand Sieber (2):
  sched/fair: expose cpu.max.runtime to set bandwidth runtime directly
  sched/fair: refill bandwidth for the periods the timer slept through

 Documentation/admin-guide/cgroup-v2.rst   |  24 +-
 Documentation/scheduler/sched-bwc.rst     |  14 +-
 kernel/sched/core.c                       |  56 ++-
 kernel/sched/fair.c                       | 163 +++++-
 kernel/sched/sched.h                      |   4 +
 tools/testing/selftests/cgroup/config     |   1 +
 tools/testing/selftests/cgroup/test_cpu.c | 587 ++++++++++++++++++++++
 7 files changed, 839 insertions(+), 10 deletions(-)


base-commit: d7e670601af6c564ccf6d3b2ddf70ee4f41a6d1c
-- 
2.47.3




Amazon Development Centre (South Africa) (Proprietary) Limited
29 Gogosoa Street, Observatory, Cape Town, Western Cape, 7925, South Africa
Registration Number: 2004 / 034463 / 07


  parent reply	other threads:[~2026-11-11 12:30 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 11:08 [PATCH v2 0/4] sched/fair: cpu.max.runtime and idle refill for CPU credits Fernand Sieber
2026-11-10 11:08 ` [PATCH v2 1/4] sched/fair: expose cpu.max.runtime to set bandwidth runtime directly Fernand Sieber
2026-11-11  8:28   ` bot+bpf-ci
2026-11-10 11:08 ` [PATCH v2 2/4] sched/fair: refill bandwidth for the periods the timer slept through Fernand Sieber
2026-11-10 11:08 ` [PATCH v2 3/4] sched_ext: add cgroup_set_runtime ops callback Fernand Sieber
2026-11-11  8:08   ` bot+bpf-ci
2026-11-10 11:08 ` [PATCH v2 4/4] sched_ext: charge BPF scheduler tasks to cpu.max bandwidth Fernand Sieber
2026-11-11  8:28   ` bot+bpf-ci
2026-11-10 20:10 ` [PATCH v2 0/4] sched/fair: cpu.max.runtime and idle refill for CPU credits Tejun Heo
2026-11-11 12:20   ` Fernand Sieber
2026-11-11 17:26     ` Tejun Heo
2026-11-11 12:29 ` Fernand Sieber [this message]
2026-11-11 12:29   ` [PATCH v3 1/2] sched/fair: expose cpu.max.runtime to set bandwidth runtime directly Fernand Sieber
2026-11-11 12:29   ` [PATCH v3 2/2] sched/fair: refill bandwidth for the periods the timer slept through Fernand Sieber

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cover.1794398404.git.sieberf@amazon.com \
    --to=sieberf@amazon.com \
    --cc=bsegall@google.com \
    --cc=cgroups@vger.kernel.org \
    --cc=corbet@lwn.net \
    --cc=dietmar.eggemann@arm.com \
    --cc=dwmw@amazon.co.uk \
    --cc=fmubeen@amazon.de \
    --cc=hannes@cmpxchg.org \
    --cc=hborghor@amazon.de \
    --cc=juri.lelli@redhat.com \
    --cc=kprateek.nayak@amd.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mgorman@suse.de \
    --cc=mingo@redhat.com \
    --cc=mkoutny@suse.com \
    --cc=nh-open-source@amazon.com \
    --cc=peterz@infradead.org \
    --cc=rdunlap@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=skhan@linuxfoundation.org \
    --cc=tj@kernel.org \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox