CPU fairness: distinguish weights, quotas, and placement
Analyze relative fair-class weights and aggregate CPU budgets without treating either as an exclusive core or a latency guarantee.
On this page
The question for today
What you’ll understand
- Calculate ideal relative shares among continuously runnable siblings.
- Separate an aggregate quota ceiling from placement and guaranteed progress.
- Design a victim/aggressor comparison that exposes CPU interference.
A training data loader and an inference gateway can interfere even when their CPU limits appear sensible. One can consume shared run queues; another can burn a period’s aggregate quota in a short parallel burst and then be throttled. Linux 6.12 cgroup v2 supplies different controls for relative weighting, bandwidth ceilings, and placement. Understanding their distinct scopes prevents a common mistake: interpreting a numerical CPU limit as ownership of that many physically independent cores.
Relative weight applies to active competition
For ordinary fair-class scheduling, cpu.weight expresses relative weight among competing sibling cgroups, subject to the hierarchy and the actual runnable workload. An idealized division of a fully busy parent’s capacity is proportional to the active weights. This is a useful budgeting model, not a promise that every millisecond follows the same ratio. Runnable-thread counts, affinity, scheduling granularity, ancestor restrictions, and other scheduling classes can alter what a short observation sees. Measure CPU time over an appropriate interval and inspect the actual parent topology.
Weights are work-conserving: an idle sibling does not usually retain an unused time reservation that everyone else must leave untouched. If one tenant sleeps, another may consume more of the available parent capacity, subject to other restrictions. This borrowing improves utilization but also means that an observed solo rate is not a guaranteed shared rate. Compare tenants under controlled simultaneous demand. Do not tune a weight from a quiet cluster experiment and then call the resulting solo latency an entitlement under saturation.
Bandwidth ceilings and placement answer different questions
The cpu.max quota and period bound aggregate fair-class CPU execution within the relevant bandwidth-control semantics. Multiple threads can consume that aggregate budget concurrently, leaving later work throttled until replenishment. A quota equivalent to one CPU can therefore coexist with bursts on several CPUs; it does not identify one permanently assigned core. An ancestor can impose a tighter effective restriction than the child’s own setting. Inspect throttling statistics and effective hierarchy rather than reading one leaf configuration in isolation.
Placement controls constrain eligible CPUs, but eligible CPUs can still have shared execution resources. Logical siblings may share a physical core, and different cores may share last-level cache, memory bandwidth, power, or thermal limits. Reserving a CPU set therefore requires a precise claim about exclusivity, sibling placement, and host work. For a latency-sensitive decoder, compare run-queue delay and throttling alongside application timings. A low average utilization graph cannot exclude brief exhaustion of the quota that repeatedly delays the critical path.
Expose interference with matched useful work
Hold the victim’s request mix, token lengths, batching, and concurrency fixed while adding a CPU aggressor. Record offered load, admitted work, CPU time, throttled duration, run-queue delay, and deadline success. An aggressor that changes memory bandwidth as well as CPU demand tests a broader boundary than a compute-only loop. Repeat across relevant placement arrangements and distinguish a tenant’s configured ceiling from the useful work it actually receives. A result should identify which shared mechanism explains the degradation rather than attribute every slowdown to scheduling weights.
The queue lab illustrates an average service imbalance without modeling a Linux scheduler. Reset, explicitly set arrival two and service three, predict drainage of the initial four items, then Play or Step. In a separate run Reset and explicitly set arrival four and service three before predicting growth. Editing rates retains elapsed time and recomputes from the initial backlog, so it is not a live throttling experiment. The lab has no runnable threads, cgroups, periods, CPU sets, or kernel scheduling classes; actual CPU evidence must come from the matched workload experiment.
Work it through
A relative share is not a hard reservation
A hypothetical parent can deliver four CPU-seconds per second. Two sufficiently parallel, continuously runnable children have weights 100 and 300. Ignore other bottlenecks initially, then consider the first child alone with a quota ceiling of 1.5 CPU equivalents.
The total active weight is 400. Under the stated ideal sharing model, the first child receives four times 100/400, or one CPU equivalent; the second receives four times 300/400, or three.
If the second child becomes idle, the first child’s active relative share can rise toward the available four CPU equivalents. The idle child’s former share is not a permanently inaccessible reservation under this weight model.
Adding the first child’s aggregate quota ceiling of 1.5 caps its modeled sustained CPU execution at no more than 1.5 CPU equivalents under the applicable enforcement semantics. It does not guarantee that service, reserve a particular physical core, or remove shared-cache interference.
Weights allocate relative opportunity under contention; the separate quota can prevent a lone child from borrowing all idle parent capacity.
The living notebook
Explore the model
Interactive lab · queue
Average service pressure, not CFS execution
Use independent Reset → explicitly set BOTH rates → predict → Play/Step runs for (λ,μ)=(2,3) and (4,3). Each begins from q=4 and computes q=max(0,4+(λ−μ)t). No quota periods or runnable threads are represented.
- Fluid backlog
- 4
- Net rate · λ − μ
- −1 /s
- M/M/1 mean residence
- 1 s
Fluid backlog starts at 4 and follows max(0, 4 + (λ − μ)t). The separate M/M/1 residence-time formula assumes Poisson arrivals, exponential service and λ < μ. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.
Look forA service-rate margin matters to backlog, but CPU fairness and throttling require scheduler-specific measurements.
Pause & reason
Check your understanding
Your turn
Try it yourself
Three continuously runnable siblings have weights 100, 100, and 200 under a parent with eight CPU equivalents of usable capacity. Calculate the ideal shares. If the largest-weight child sleeps, what are the remaining ideal shares before considering quotas?
Take a moment to make a prediction or work it out on paper. Open a hint when you need one.
Give me a hint
Normalize by the active total weight, and recompute that total after the child becomes inactive.
Compare with the solution
With all three active, the shares are two, two, and four CPU equivalents. With the 200-weight child idle, each remaining child has half the active weight and can ideally receive four. This is a work-conserving proportional model, not an exclusive-core assignment or a deadline guarantee. Verify sufficient parallelism, affinity, ancestor bandwidth, host work, and shared-resource contention before comparing the model to measured service. A local quota could limit either child below four even while the other child has spare opportunity.
Keep the idea
Take it with you
- Weights describe relative competition among active peers.
- Aggregate quota consumption can be parallel and lead to throttling.
- Placement and shared microarchitecture require separate interference evidence.
Read further
Original sources and deeper explanations to follow at your own pace.
Optional progress, saved in this browser when available. Revisit any lesson at any time.
Lesson not marked complete.