mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/4] sched/fair: cpu.max.runtime and idle refill for CPU credits
@ 2026-11-10 11:08 Fernand Sieber
  2026-11-10 11:08 ` [PATCH v2 1/4] sched/fair: expose cpu.max.runtime to set bandwidth runtime directly Fernand Sieber
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Fernand Sieber @ 2026-11-10 11:08 UTC (permalink / raw)
  To: mingo, peterz, juri.lelli, vincent.guittot, tj
  Cc: bsegall, dietmar.eggemann, rostedt, mgorman, vschneid,
	kprateek.nayak, hannes, mkoutny, void, arighi, changwoo, skhan,
	corbet, rdunlap, cgroups, sched-ext, linux-doc, linux-kselftest,
	bpf, linux-kernel, nh-open-source, hborghor, fmubeen, dwmw,
	karataev, sieberf

This series adds cpu.max.runtime, a cgroup v2 file to read and set the
runtime the CFS bandwidth controller has for a cgroup, lets
cpu.max.burst exceed the quota, and makes an idle group keep earning
quota up to quota + burst. Patch 3 passes the writes on to BPF
schedulers, and patch 4 lets them charge their tasks to the same
runtime.

Use case
========

We run virtual machines whose CPU time is governed by CPU credits, as
burstable instances are. Each instance has a baseline, which is the
share of its vCPUs it may always use. Running below the baseline earns
credits, running above it spends them, and the credits an instance holds
are capped. When it has none left, the instance is held to its 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.
An instance must neither lose credits nor gain credits it did not earn.

Each instance's vCPU threads run in their own cgroup, and the CFS
bandwidth controller is that bucket of credits as it stands:

  - quota per period is the rate credits are earned at, the baseline;
  - quota + burst is the cap, the most credits an instance can hold;
  - the runtime is the credit level. The controller refills it by the
    quota every period, up to quota + burst, and throttles the cgroup
    when it runs out.

The controller already does the per-CPU charging and the throttling in
the scheduler, at a granularity that userspace accounting cannot match.
Three things are missing. The cap cannot exceed one quota, because
burst is limited to the quota (patch 1 drops that limit). The level
cannot be read or set (patch 1). An idle group does not earn (patch 2),
because the period timer stops after a period in which the group did
not run, and the periods it sleeps through refill nothing. For example,
an instance that idles for a minute with a 100ms period earns one quota
instead of up to 600.

The level has to be read and set by the host's control software:

  - at launch, an instance starts with the credits its type grants, not
    with one quota;
  - across a host kernel live update (kexec) or a reboot, the cgroups
    are created anew, so their levels have to be read before and
    written back after, or every instance loses or gains credits;
  - a live migration moves the level with the instance to the new host;
  - the control plane raises or lowers the level, for example when
    credits move between instances.

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 of the cases above:

  - it can only add, and only one quota per write. Setting a level
    requires writing a temporary quota equal to the difference and then
    the real quota back. Lowering a level, which a restore or a transfer
    may need, requires shrinking the burst until the cap cuts the
    runtime and then widening it again. Each of these leaves the cgroup
    running with the wrong bandwidth in between, and each write goes
    through tg_set_cfs_bandwidth(), which visits every CPU's cfs_rq;
  - usage is not the level. Deriving the level from the usage requires
    replaying every period's refill in userspace, including the periods
    the timer slept through, which duplicates the controller's
    accounting.

Keeping the credits in a BPF scheduler instead (patch 3 lets sched_ext
follow the level) does not remove the need. The credit guarantee has to
hold before a BPF scheduler loads, after it exits or errors out, and on
hosts that run no BPF scheduler. The tasks are then on CFS, where the
bandwidth controller is the only enforcement, and it has no BPF hook to
refill or set the runtime.

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,
including eight new ones for patches 1 and 2, and so does the new
sched_ext selftest cgroup_runtime, which covers patches 3 and 4. Every
patch builds with W=1 and no new warnings, with and without
CONFIG_CFS_BANDWIDTH and on 32-bit.

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 v2
=============

- New patch 2: refill the periods the period timer slept through.
- New patch 4: with the new SCX_OPS_CHARGE_CPU_MAX flag, a BPF
  scheduler's tasks are charged to the fair class's runtime, read with
  the new kfunc scx_bpf_task_cpu_max_runtime(); selftest
  cgroup_runtime.
- Patch 1: a write distributes the runtime to throttled cfs_rqs at once
  (Ben); a write moves runtime_snap so it is not counted as burst
  usage; a read is capped at quota + burst so it can be written back;
  a write needs a quota; burst is bounded so quota + burst cannot
  overflow (Ben); cpu.max.runtime needs CONFIG_CFS_BANDWIDTH (v1 did
  not build with CONFIG_EXT_GROUP_SCHED=y and CONFIG_CFS_BANDWIDTH=n);
  documented in cgroup-v2.rst and sched-bwc.rst; four more selftests.
- Patch 3: the callback is invoked on every write, since writing the
  same value again adds back what the cgroup ran; it is serialized with
  cpu.max writes and may be sleepable; the cached value is dropped; the
  cid-form variant, ops.cpuctl_set_runtime(), is added. Both writes hold
  a new mutex across the fair class's update and the callback, so
  cpu.max and cpu.max.runtime writes reach the scheduler in the order
  the fair class applied them.
- Use case described (Tejun). Rebased on tip/sched/core.

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

Fernand Sieber (4):
  sched/fair: expose cpu.max.runtime to set bandwidth runtime directly
  sched/fair: refill bandwidth for the periods the timer slept through
  sched_ext: add cgroup_set_runtime ops callback
  sched_ext: charge BPF scheduler tasks to cpu.max bandwidth

 Documentation/admin-guide/cgroup-v2.rst       |  27 +-
 Documentation/scheduler/sched-bwc.rst         |  14 +-
 kernel/sched/core.c                           |  61 +-
 kernel/sched/ext/ext.c                        |  53 ++
 kernel/sched/ext/ext.h                        |   2 +
 kernel/sched/ext/internal.h                   |  45 +-
 kernel/sched/fair.c                           | 260 ++++++-
 kernel/sched/sched.h                          |  15 +
 tools/sched_ext/include/scx/common.bpf.h      |   1 +
 tools/sched_ext/include/scx/compat.h          |   1 +
 tools/testing/selftests/cgroup/test_cpu.c     | 519 ++++++++++++++
 tools/testing/selftests/sched_ext/Makefile    |   1 +
 .../selftests/sched_ext/cgroup_runtime.bpf.c  | 195 ++++++
 .../selftests/sched_ext/cgroup_runtime.c      | 652 ++++++++++++++++++
 tools/testing/selftests/sched_ext/config      |   1 +
 15 files changed, 1836 insertions(+), 11 deletions(-)
 create mode 100644 tools/testing/selftests/sched_ext/cgroup_runtime.bpf.c
 create mode 100644 tools/testing/selftests/sched_ext/cgroup_runtime.c


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


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-11-10 11:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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-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-10 11:08 ` [PATCH v2 4/4] sched_ext: charge BPF scheduler tasks to cpu.max bandwidth Fernand Sieber

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®