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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Meziantou.Framework.Unix.ControlGroups" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Meziantou.Framework.Unix.ControlGroups" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Meziantou.Framework.Unix.ControlGroups" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Meziantou.Framework.Unix.ControlGroups --version 1.0.1
                    
#r "nuget: Meziantou.Framework.Unix.ControlGroups, 1.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Meziantou.Framework.Unix.ControlGroups@1.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Meziantou.Framework.Unix.ControlGroups&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Meziantou.Framework.Unix.ControlGroups&version=1.0.1
                    
Install as a Cake Tool

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

  1. Permissions: Managing cgroups typically requires root privileges or appropriate capabilities.

  2. No Internal Process Constraint: Non-root cgroups can only enable controllers if they don't contain any processes. Move processes to leaf cgroups first.

  3. Hierarchical: Resource limits are hierarchical. A child cgroup can't use more resources than its parent allows.

  4. Culture Invariant: All number parsing and formatting use CultureInfo.InvariantCulture for consistency.

  5. cgroup v2 Only: This library only supports cgroup v2. For systems still using cgroup v1, consider upgrading or use v1-specific tools.

  6. Error Handling: File operations may throw IOException, UnauthorizedAccessException, or DirectoryNotFoundException. 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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.

Version Downloads Last Updated
1.0.1 95 11/16/2025
1.0.0 160 10/31/2025