{ config, pkgs, ... }: with pkgs.lib; let cfg = config.services.cgroups; cgconfigConf = pkgs.writeText "cgconfig.conf" cfg.groups; cgrulesConf = pkgs.writeText "cgrules.conf" cfg.rules; in { ###### interface options = { services.cgroups.enable = mkOption { type = types.bool; default = false; description = '' Whether to enable support for control groups, a Linux kernel feature for resource management. It allows you to assign processes to groups that share certain resource limits (e.g., CPU or memory). The cgrulesengd daemon automatically assigns processes to the right cgroup depending on the rules defined in . ''; }; services.cgroups.groups = mkOption { type = types.string; default = '' mount { cpu = /sys/fs/cgroup/cpu; } ''; example = '' mount { cpu = /sys/fs/cgroup/cpu; cpuacct = /sys/fs/cgroup/cpuacct; } # Create a "www" cgroup with a lower share of the CPU (the # default is 1024). group www { cpu { cpu.shares = "500"; } } ''; description = '' The contents of the cgconfig.conf configuration file, which defines the cgroups. ''; }; services.cgroups.rules = mkOption { type = types.string; default = ""; example = '' # All processes executed by the "wwwrun" uid should be # assigned to the "www" CPU cgroup. wwwrun cpu www ''; description = '' The contents of the cgrules.conf configuration file, which determines to which cgroups processes should be assigned by the cgrulesengd daemon. ''; }; }; ###### implementation config = mkIf cfg.enable { environment.systemPackages = [ pkgs.libcgroup ]; environment.etc = [ { source = cgconfigConf; target = "cgconfig.conf"; } { source = cgrulesConf; target = "cgrules.conf"; } ]; # The daemon requires the userspace<->kernelspace netlink # connector. boot.kernelModules = [ "cn" ]; jobs.cgroups = { startOn = "startup"; description = "Control groups daemon"; path = [ pkgs.libcgroup pkgs.procps pkgs.utillinux ]; preStart = '' if [ -d /sys/fs/cgroup ]; then if ! mountpoint -q /sys/fs/cgroup; then mount -t tmpfs -o mode=755 /dev/cgroup /sys/fs/cgroup fi fi cgclear || true # Mount the cgroup hierarchies. Note: we refer to the # store path of cgconfig.conf here to ensure that the job # gets reloaded if the configuration changes. cgconfigparser -l ${cgconfigConf} # Move existing processes to the right cgroup. cgclassify --cancel-sticky $(ps --no-headers -eL o tid) || true # Force a restart if the rules change: # ${cgrulesConf} ''; # Run the daemon that moves new processes to the right cgroup. exec = "cgrulesengd"; daemonType = "fork"; postStop = '' cgclear ''; }; }; }