Cgroup v2 CPU Placement: Read cpuset.cpus.effective After Parent and Hotplug Changes

A service’s cpuset.cpus file can continue to list CPUs that are no longer available to its cgroup. In cgroup v2, that file expresses the requested set. Read cpuset.cpus.effective to discover the online CPUs actually granted under the parent constraints.

This article pins the Linux v6.12 cgroup v2 documentation. It uses a synthetic ordinary cpuset hierarchy without exclusive partitions. No CPU was offlined, no task was moved, and no cgroup file was written.

Capture the hierarchy with the request

Begin with the cgroup that actually contains the service and verify that the cpuset controller is available and enabled along the relevant hierarchy. A pathname copied from another image is not proof that the same controller arrangement exists here.

Record the child’s requested CPUs, its effective CPUs, the parent’s effective CPUs and the system’s online CPU set together. Parent policy and CPU availability can change the child’s grant without rewriting the child’s request.

The v6.12 contract explicitly says cpuset.cpus remains unchanged by hotplug. The effective file reflects the online CPUs that the parent grants. Treat the pair as intention and current allowance, not as two redundant views of one fixed mask.

Walk a partial-loss example

Suppose the parent initially grants CPUs 0-3, all online, and a child requests 2-3. In the simple stated hierarchy, its effective set is 2-3.

Now consider a hypothetical observation after CPU 2 becomes unavailable while CPU 3 remains available. The child can still request 2-3, while its effective set is only 3. Comparing the unchanged request against a configuration repository would miss the reduced allowance.

The interpretation is narrow: the cgroup currently has CPU 3 available under these assumptions. It does not prove that a particular thread ran there, how much CPU time it received, or whether its deadline was met.

A child keeps requesting CPUs two and three while its effective set changes from both CPUs to CPU three and then to parent CPUs zero and one under the documented none-granted fallback.
Original synthetic cpuset snapshot diagram; no CPU hotplug test.

Include the none-granted fallback

A simple intersection rule is incomplete. The documentation states that if none of a nonempty requested set can be granted, the request is treated like an empty cpuset.cpus for effective-set purposes.

Continue the synthetic scenario until neither CPU 2 nor CPU 3 can be granted, while the parent still makes CPUs 0-1 available. The child’s literal request can remain 2-3, yet its effective set follows the available parent set, 0-1, under the stated ordinary hierarchy.

This fallback means the effective set need not always be a subset of the literal nonempty request. A monitor that declares “this service cannot run anywhere” after computing an empty intersection can therefore issue the wrong diagnosis.

Conversely, a product that intended the service to run only on CPUs 2 and 3 must notice that its intended placement contract is no longer satisfied. The kernel’s available fallback is not an application approval to continue a timing-sensitive workload unchanged. Define a product response to that mismatch separately.

Distinguish an empty request from an unavailable request

An empty cpuset.cpus intentionally inherits an ancestor setting, using the nearest nonempty ancestor request or the available CPUs when none exists. Its effective view then reports the parent CPUs available to that child.

For diagnostics, retain the original request even when two cases currently produce the same effective mask. An intentionally inherited placement and a specific request receiving no grant have different configuration meanings and may require different operator explanations.

Do not replace a specific request with an empty value merely to make the files agree. That would change policy and discard evidence of the original intent. This article proposes read-only interpretation, not a cgroup repair procedure.

Keep placement separate from execution evidence

Per-thread affinity and scheduler behavior are additional constraints and observations. A cgroup-wide allowed set is not a trace of where each thread executed. If the investigation asks where an acquisition thread actually ran, collect appropriate thread identity, affinity and scheduler evidence rather than infer execution from the cpuset files alone.

Likewise, CPU quota, exclusive partition ownership, IRQ placement and real-time isolation are different questions. Listing one available CPU does not establish exclusive ownership or a guaranteed fraction of processor time. This example deliberately avoids partition-root rules, which require their own review.

Make snapshots useful when the system changes

A proposed diagnostic fixture should preserve the three states: all requested CPUs granted, a partial grant, and no requested CPU granted with parent CPUs still available. Assert that the interpreter reports the actual effective set and flags divergence from the requested product policy.

Read related files close together and record observation time. If hotplug or parent configuration is changing concurrently, repeat the snapshot and mark inconsistent observations rather than present them as an atomic historical state.

The acceptance record should explain both what was requested and what the kernel currently permits. That small distinction prevents a static configuration mask from becoming misleading evidence about a changing embedded system.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *