Meziantou.Framework.Unix.ControlGroups
1.0.1
Prefix Reserved
dotnet add package Meziantou.Framework.Unix.ControlGroups --version 1.0.1
NuGet\Install-Package Meziantou.Framework.Unix.ControlGroups -Version 1.0.1
<PackageReference Include="Meziantou.Framework.Unix.ControlGroups" Version="1.0.1" />
<PackageVersion Include="Meziantou.Framework.Unix.ControlGroups" Version="1.0.1" />
<PackageReference Include="Meziantou.Framework.Unix.ControlGroups" />
paket add Meziantou.Framework.Unix.ControlGroups --version 1.0.1
#r "nuget: Meziantou.Framework.Unix.ControlGroups, 1.0.1"
#:package Meziantou.Framework.Unix.ControlGroups@1.0.1
#addin nuget:?package=Meziantou.Framework.Unix.ControlGroups&version=1.0.1
#tool nuget:?package=Meziantou.Framework.Unix.ControlGroups&version=1.0.1
Meziantou.Framework.Unix.ControlGroups
A .NET library for managing Linux Control Groups v2 (cgroups v2).
Features
- Create, delete, and manage cgroup hierarchies
- Add/remove processes and threads to/from cgroups
- Configure resource limits:
- CPU: Weight-based scheduling, bandwidth limits
- Memory: Hard limits, soft limits, protection levels, swap control
- IO: Weight-based scheduling, bandwidth/IOPS limits per device
- PIDs: Limit number of processes
- Cpuset: CPU and memory node affinity
- Freeze/unfreeze processes in a cgroup
- Kill all processes in a cgroup
- Read statistics (CPU usage, memory usage, etc.)
- Enable/disable controllers per cgroup
Requirements
- Linux kernel 4.5+ with cgroup v2 enabled
- cgroup v2 filesystem mounted at
/sys/fs/cgroup(default on most modern distributions) - Appropriate permissions to manage cgroups
Usage
Basic Operations
using Meziantou.Framework.Unix.ControlGroups;
// Get the root cgroup
var root = CGroup2.Root;
// Create a new cgroup
var myGroup = root.CreateOrGetChild("myapp");
// Add the current process to the cgroup
myGroup.AssociateProcess(Environment.ProcessId);
// Create nested cgroups
var subGroup = myGroup.CreateOrGetChild("worker1");
CPU Control
// Enable CPU controller
myGroup.SetControllers("cpu");
// Set CPU weight (relative share, 1-10000, default 100)
myGroup.SetCpuWeight(200); // 2x the default share
// Set CPU bandwidth limit (max 50% of 1 CPU)
myGroup.SetCpuMax(50_000, 100_000); // 50ms per 100ms period
// Remove limit
myGroup.RemoveCpuMax();
// Get CPU statistics
var cpuStat = myGroup.GetCpuStat();
if (cpuStat != null)
{
Console.WriteLine($"CPU Usage: {cpuStat.UsageMicroseconds} μs");
Console.WriteLine($"User time: {cpuStat.UserMicroseconds} μs");
Console.WriteLine($"System time: {cpuStat.SystemMicroseconds} μs");
}
Memory Control
// Enable memory controller
myGroup.SetControllers("memory");
// Set hard memory limit (1 GB)
myGroup.SetMemoryMax(1024L * 1024 * 1024);
// Set soft limit (throttling starts at 512 MB)
myGroup.SetMemoryHigh(512L * 1024 * 1024);
// Set memory protection (best-effort, prevents reclaim below 256 MB)
myGroup.SetMemoryLow(256L * 1024 * 1024);
// Set swap limit
myGroup.SetSwapMax(512L * 1024 * 1024);
// Get current memory usage
var currentMemory = myGroup.GetMemoryCurrent();
Console.WriteLine($"Current memory usage: {currentMemory} bytes");
// Get detailed memory statistics
var memoryStat = myGroup.GetMemoryStat();
if (memoryStat != null)
{
Console.WriteLine($"Anonymous memory: {memoryStat.Anon} bytes");
Console.WriteLine($"File cache: {memoryStat.File} bytes");
Console.WriteLine($"Page faults: {memoryStat.PageFault}");
}
IO Control
// Enable IO controller
myGroup.SetControllers("io");
// Set default IO weight
myGroup.SetDefaultIoWeight(200);
// Set IO weight for specific device (major:minor = 8:0 for /dev/sda)
myGroup.SetIoWeight(8, 0, 300);
// Set IO bandwidth limits (10 MB/s read, 5 MB/s write)
myGroup.SetIoMax(
major: 8,
minor: 0,
readBytesPerSecond: 10 * 1024 * 1024,
writeBytesPerSecond: 5 * 1024 * 1024
);
// Set IOPS limits
myGroup.SetIoMax(
major: 8,
minor: 0,
readIopsPerSecond: 1000,
writeIopsPerSecond: 500
);
// Remove limits
myGroup.RemoveIoMax(8, 0);
PID Control
// Enable PIDs controller
myGroup.SetControllers("pids");
// Limit to 100 processes
myGroup.SetPidsMax(100);
// Get current number of processes
var currentPids = myGroup.GetPidsCurrent();
Console.WriteLine($"Current processes: {currentPids}");
// Get limit
var maxPids = myGroup.GetPidsMax();
Console.WriteLine($"Max processes: {maxPids}");
CPU Affinity (Cpuset)
// Enable cpuset controller
myGroup.SetControllers("cpuset");
// Restrict to CPUs 0, 1, 2
myGroup.SetCpusetCpus(0, 1, 2);
// Or use range format
myGroup.SetCpusetCpusRaw("0-2,4,6-8");
// Restrict to memory nodes 0 and 1
myGroup.SetCpusetMems(0, 1);
// Get effective CPUs (actually granted)
var effectiveCpus = myGroup.GetCpusetCpusEffective();
Console.WriteLine($"Effective CPUs: {string.Join(", ", effectiveCpus ?? [])}");
// Set partition type
myGroup.SetCpusetPartition("isolated");
HugeTLB Control
// Enable hugetlb controller (if available)
// Note: HugeTLB support depends on kernel configuration
// Set HugeTLB limit for 2MB pages
myGroup.SetHugeTlbMax("2MB", 100 * 1024 * 1024); // 100 MB
// Get current HugeTLB usage
var current = myGroup.GetHugeTlbCurrent("2MB");
Console.WriteLine($"Current 2MB HugeTLB usage: {current} bytes");
// Get limit hit count
var limitHits = myGroup.GetHugeTlbEventsMax("2MB");
Console.WriteLine($"HugeTLB limit hits: {limitHits}");
Process Management
// Associate a process
using var process = Process.Start("myapp");
myGroup.AssociateProcess(process);
// Or by PID
myGroup.AssociateProcess(1234);
// Add a thread by TID
myGroup.AssociateThread(5678);
// Get all processes in the cgroup
foreach (var pid in myGroup.GetProcesses())
{
Console.WriteLine($"Process: {pid}");
}
// Get all threads
foreach (var tid in myGroup.GetThreads())
{
Console.WriteLine($"Thread: {tid}");
}
Freezer
// Freeze all processes (SIGSTOP)
myGroup.Freeze();
// Check if frozen
if (myGroup.IsFrozen())
{
Console.WriteLine("Cgroup is frozen");
}
// Unfreeze
myGroup.Unfreeze();
Kill All Processes
// Kill all processes in the cgroup (SIGKILL)
myGroup.Kill();
Controller Management
// Get available controllers
var available = myGroup.GetAvailableControllers();
Console.WriteLine($"Available: {string.Join(", ", available)}");
// Get enabled controllers
var enabled = myGroup.GetEnabledControllers();
Console.WriteLine($"Enabled: {string.Join(", ", enabled)}");
// Enable multiple controllers at once
myGroup.SetControllers("cpu", "memory", "io");
// Disable a controller
// Prefixing a controller name with '-' disables that controller. For example, "-io" disables the IO controller.
myGroup.SetControllers("-io");
Cleanup
// Delete a cgroup (must be empty - no processes, no child cgroups)
subGroup.Delete();
myGroup.Delete();
Important Notes
Permissions: Managing cgroups typically requires root privileges or appropriate capabilities.
No Internal Process Constraint: Non-root cgroups can only enable controllers if they don't contain any processes. Move processes to leaf cgroups first.
Hierarchical: Resource limits are hierarchical. A child cgroup can't use more resources than its parent allows.
Culture Invariant: All number parsing and formatting use
CultureInfo.InvariantCulturefor consistency.cgroup v2 Only: This library only supports cgroup v2. For systems still using cgroup v1, consider upgrading or use v1-specific tools.
Error Handling: File operations may throw
IOException,UnauthorizedAccessException, orDirectoryNotFoundException. Handle these appropriately.
Example: Complete Application Resource Limiting
using Meziantou.Framework.Unix.ControlGroups;
using System.Diagnostics;
// Create a cgroup for the application
var appGroup = CGroup2.Root.CreateOrGetChild("myapp");
// Enable controllers
appGroup.SetControllers("cpu", "memory", "io", "pids");
// Configure limits
appGroup.SetCpuWeight(100); // Normal priority
appGroup.SetCpuMax(200_000, 100_000); // Max 2 CPUs
appGroup.SetMemoryMax(2L * 1024 * 1024 * 1024); // 2 GB
appGroup.SetMemoryHigh(1536L * 1024 * 1024 * 1024); // Start throttling at 1.5 GB
appGroup.SetPidsMax(200); // Max 200 processes
// Start your application
var process = Process.Start("myapp");
appGroup.AssociateProcess(process);
// Monitor
while (!process.HasExited)
{
var cpuStat = appGroup.GetCpuStat();
var memCurrent = appGroup.GetMemoryCurrent();
var pidsCurrent = appGroup.GetPidsCurrent();
Console.WriteLine($"CPU: {cpuStat?.UsageMicroseconds} μs");
Console.WriteLine($"Memory: {memCurrent / (1024.0 * 1024):F2} MB");
Console.WriteLine($"Processes: {pidsCurrent}");
await Task.Delay(1000);
}
// Cleanup
appGroup.Delete();
References
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.