Re: [PATCH] Docs/admin-guide/cgroup-v2: document hierarchical cpu.max throttling behavior

From: Shaojie Sun

Date: Sun Jul 26 2026 - 23:22:21 EST


Hi, Michal.

On Fri, 24 Jul 2026 13:21:46, Michal wrote:
>On Fri, Jul 24, 2026 at 06:25:00PM +0800, Shaojie Sun <sunshaojie@xxxxxxxxxx> wrote:
>> diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
>> index 14b8c571c0d1..3572d3e7f688 100644
>> --- a/Documentation/admin-guide/cgroup-v2.rst
>> +++ b/Documentation/admin-guide/cgroup-v2.rst
>
>> + and the resulting
>> + throttling may reflect the combined effect of multiple levels
>> + rather than any single level's limit alone (this differs from
>> + other Limits-type controllers such as memory.max and io.max,
>> + where the most restrictive limit along the hierarchy is
>> + applied).
>
>I'm not sure from the description what the "combined effect" is.
>Can you give an example where the cpu.max differs from that Limits-type
>semantics?

Here is an example to illustrate the difference. Consider:
Parent: cpu.max = 50000 100000 (50%)
Child: cpu.max = 20000 100000 (20%)
With cpu.max, when the child's processes consume CPU, throttling can be
triggered by either the child's own limit or the parent's limit
independently — both levels participate in enforcement. This is visible
in cpu.stat : the throttled_usec counter can accumulate non-zero values
at both the child and parent level. Even when the child's quota is
smaller than the parent's (20 < 50), the parent's limit still
participates; conversely, when a child's quota is larger than the
parent's, the child's own limit still participates.

Compare this with memory.max. If we had:
Parent: memory.max = 50M
Child: memory.max = 20M
The effective limit for the child is simply min(20M, 50M) = 20M — only the
most restrictive limit along the path applies. The child will never see an
OOM triggered by the parent's 50M limit before reaching its own 20M.

In short: cpu.max enforcement is per-level independent — every level with
cpu.max configured can independently throttle the group, and cpu.stat
counters at multiple levels can all accumulate throttled_usec for the same
workload. memory.max only enforces the tightest limit along the path.

Thanks,
Shaojie Sun