
After final improvements to the official formatter implementation,
this commit now performs the first treewide reformat of Nix files using it.
This is part of the implementation of RFC 166.
Only "inactive" files are reformatted, meaning only files that
aren't being touched by any PR with activity in the past 2 months.
This is to avoid conflicts for PRs that might soon be merged.
Later we can do a full treewide reformat to get the rest,
which should not cause as many conflicts.
A CI check has already been running for some time to ensure that new and
already-formatted files are formatted, so the files being reformatted here
should also stay formatted.
This commit was automatically created and can be verified using
nix-build a08b3a4d19
.tar.gz \
--argstr baseRev b32a0943687d2a5094a6d92f25a4b6e16a76b5b7
result/bin/apply-formatting $NIXPKGS_PATH
373 lines
10 KiB
Nix
373 lines
10 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
|
|
let
|
|
cfg = config.services.system76-scheduler;
|
|
|
|
inherit (builtins)
|
|
concatStringsSep
|
|
map
|
|
toString
|
|
attrNames
|
|
;
|
|
inherit (lib)
|
|
boolToString
|
|
types
|
|
mkOption
|
|
literalExpression
|
|
optional
|
|
mkIf
|
|
mkMerge
|
|
;
|
|
inherit (types)
|
|
nullOr
|
|
listOf
|
|
bool
|
|
int
|
|
ints
|
|
float
|
|
str
|
|
enum
|
|
;
|
|
|
|
withDefaults =
|
|
optionSpecs: defaults:
|
|
lib.genAttrs (attrNames optionSpecs) (
|
|
name:
|
|
mkOption (
|
|
optionSpecs.${name}
|
|
// {
|
|
default = optionSpecs.${name}.default or defaults.${name} or null;
|
|
}
|
|
)
|
|
);
|
|
|
|
latencyProfile = withDefaults {
|
|
latency = {
|
|
type = int;
|
|
description = "`sched_latency_ns`.";
|
|
};
|
|
nr-latency = {
|
|
type = int;
|
|
description = "`sched_nr_latency`.";
|
|
};
|
|
wakeup-granularity = {
|
|
type = float;
|
|
description = "`sched_wakeup_granularity_ns`.";
|
|
};
|
|
bandwidth-size = {
|
|
type = int;
|
|
description = "`sched_cfs_bandwidth_slice_us`.";
|
|
};
|
|
preempt = {
|
|
type = enum [
|
|
"none"
|
|
"voluntary"
|
|
"full"
|
|
];
|
|
description = "Preemption mode.";
|
|
};
|
|
};
|
|
schedulerProfile = withDefaults {
|
|
nice = {
|
|
type = nullOr (ints.between (-20) 19);
|
|
description = "Niceness.";
|
|
};
|
|
class = {
|
|
type = nullOr (enum [
|
|
"idle"
|
|
"batch"
|
|
"other"
|
|
"rr"
|
|
"fifo"
|
|
]);
|
|
example = literalExpression "\"batch\"";
|
|
description = "CPU scheduler class.";
|
|
};
|
|
prio = {
|
|
type = nullOr (ints.between 1 99);
|
|
example = literalExpression "49";
|
|
description = "CPU scheduler priority.";
|
|
};
|
|
ioClass = {
|
|
type = nullOr (enum [
|
|
"idle"
|
|
"best-effort"
|
|
"realtime"
|
|
]);
|
|
example = literalExpression "\"best-effort\"";
|
|
description = "IO scheduler class.";
|
|
};
|
|
ioPrio = {
|
|
type = nullOr (ints.between 0 7);
|
|
example = literalExpression "4";
|
|
description = "IO scheduler priority.";
|
|
};
|
|
matchers = {
|
|
type = nullOr (listOf str);
|
|
default = [ ];
|
|
example = literalExpression ''
|
|
[
|
|
"include cgroup=\"/user.slice/*.service\" parent=\"systemd\""
|
|
"emacs"
|
|
]
|
|
'';
|
|
description = "Process matchers.";
|
|
};
|
|
};
|
|
|
|
cfsProfileToString =
|
|
name:
|
|
let
|
|
p = cfg.settings.cfsProfiles.${name};
|
|
in
|
|
"${name} latency=${toString p.latency} nr-latency=${toString p.nr-latency} wakeup-granularity=${toString p.wakeup-granularity} bandwidth-size=${toString p.bandwidth-size} preempt=\"${p.preempt}\"";
|
|
|
|
prioToString = class: prio: if prio == null then "\"${class}\"" else "(${class})${toString prio}";
|
|
|
|
schedulerProfileToString =
|
|
name: a: indent:
|
|
concatStringsSep " " (
|
|
[ "${indent}${name}" ]
|
|
++ (optional (a.nice != null) "nice=${toString a.nice}")
|
|
++ (optional (a.class != null) "sched=${prioToString a.class a.prio}")
|
|
++ (optional (a.ioClass != null) "io=${prioToString a.ioClass a.ioPrio}")
|
|
++ (optional ((builtins.length a.matchers) != 0) (
|
|
"{\n${concatStringsSep "\n" (map (m: " ${indent}${m}") a.matchers)}\n${indent}}"
|
|
))
|
|
);
|
|
|
|
in
|
|
{
|
|
options = {
|
|
services.system76-scheduler = {
|
|
enable = lib.mkEnableOption "system76-scheduler";
|
|
|
|
package = mkOption {
|
|
type = types.package;
|
|
default = pkgs.system76-scheduler;
|
|
defaultText = literalExpression "pkgs.system76-scheduler";
|
|
description = "Which System76-Scheduler package to use.";
|
|
};
|
|
|
|
useStockConfig = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description = ''
|
|
Use the (reasonable and featureful) stock configuration.
|
|
|
|
When this option is `true`, `services.system76-scheduler.settings`
|
|
are ignored.
|
|
'';
|
|
};
|
|
|
|
settings = {
|
|
cfsProfiles = {
|
|
enable = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description = "Tweak CFS latency parameters when going on/off battery";
|
|
};
|
|
|
|
default = latencyProfile {
|
|
latency = 6;
|
|
nr-latency = 8;
|
|
wakeup-granularity = 1.0;
|
|
bandwidth-size = 5;
|
|
preempt = "voluntary";
|
|
};
|
|
responsive = latencyProfile {
|
|
latency = 4;
|
|
nr-latency = 10;
|
|
wakeup-granularity = 0.5;
|
|
bandwidth-size = 3;
|
|
preempt = "full";
|
|
};
|
|
};
|
|
|
|
processScheduler = {
|
|
enable = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description = "Tweak scheduling of individual processes in real time.";
|
|
};
|
|
|
|
useExecsnoop = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description = "Use execsnoop (otherwise poll the precess list periodically).";
|
|
};
|
|
|
|
refreshInterval = mkOption {
|
|
type = int;
|
|
default = 60;
|
|
description = "Process list poll interval, in seconds";
|
|
};
|
|
|
|
foregroundBoost = {
|
|
enable = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description = ''
|
|
Boost foreground process priorities.
|
|
|
|
(And de-boost background ones). Note that this option needs cooperation
|
|
from the desktop environment to work. On Gnome the client side is
|
|
implemented by the "System76 Scheduler" shell extension.
|
|
'';
|
|
};
|
|
foreground = schedulerProfile {
|
|
nice = 0;
|
|
ioClass = "best-effort";
|
|
ioPrio = 0;
|
|
};
|
|
background = schedulerProfile {
|
|
nice = 6;
|
|
ioClass = "idle";
|
|
};
|
|
};
|
|
|
|
pipewireBoost = {
|
|
enable = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
description = "Boost Pipewire client priorities.";
|
|
};
|
|
profile = schedulerProfile {
|
|
nice = -6;
|
|
ioClass = "best-effort";
|
|
ioPrio = 0;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
assignments = mkOption {
|
|
type = types.attrsOf (
|
|
types.submodule {
|
|
options = schedulerProfile { };
|
|
}
|
|
);
|
|
default = { };
|
|
example = literalExpression ''
|
|
{
|
|
nix-builds = {
|
|
nice = 15;
|
|
class = "batch";
|
|
ioClass = "idle";
|
|
matchers = [
|
|
"nix-daemon"
|
|
];
|
|
};
|
|
}
|
|
'';
|
|
description = "Process profile assignments.";
|
|
};
|
|
|
|
exceptions = mkOption {
|
|
type = types.listOf str;
|
|
default = [ ];
|
|
example = literalExpression ''
|
|
[
|
|
"include descends=\"schedtool\""
|
|
"schedtool"
|
|
]
|
|
'';
|
|
description = "Processes that are left alone.";
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
environment.systemPackages = [ cfg.package ];
|
|
services.dbus.packages = [ cfg.package ];
|
|
|
|
systemd.services.system76-scheduler = {
|
|
description = "Manage process priorities and CFS scheduler latencies for improved responsiveness on the desktop";
|
|
wantedBy = [ "multi-user.target" ];
|
|
path = [
|
|
# execsnoop needs those to extract kernel headers:
|
|
pkgs.kmod
|
|
pkgs.gnutar
|
|
pkgs.xz
|
|
];
|
|
serviceConfig = {
|
|
Type = "dbus";
|
|
BusName = "com.system76.Scheduler";
|
|
ExecStart = "${cfg.package}/bin/system76-scheduler daemon";
|
|
ExecReload = "${cfg.package}/bin/system76-scheduler daemon reload";
|
|
};
|
|
};
|
|
|
|
environment.etc = mkMerge [
|
|
(mkIf cfg.useStockConfig {
|
|
# No custom settings: just use stock configuration with a fix for Pipewire
|
|
"system76-scheduler/config.kdl".source = "${cfg.package}/data/config.kdl";
|
|
"system76-scheduler/process-scheduler/00-dist.kdl".source = "${cfg.package}/data/pop_os.kdl";
|
|
"system76-scheduler/process-scheduler/01-fix-pipewire-paths.kdl".source =
|
|
../../../../pkgs/by-name/sy/system76-scheduler/01-fix-pipewire-paths.kdl;
|
|
})
|
|
|
|
(
|
|
let
|
|
settings = cfg.settings;
|
|
cfsp = settings.cfsProfiles;
|
|
ps = settings.processScheduler;
|
|
in
|
|
mkIf (!cfg.useStockConfig) {
|
|
"system76-scheduler/config.kdl".text = ''
|
|
version "2.0"
|
|
autogroup-enabled false
|
|
cfs-profiles enable=${boolToString cfsp.enable} {
|
|
${cfsProfileToString "default"}
|
|
${cfsProfileToString "responsive"}
|
|
}
|
|
process-scheduler enable=${boolToString ps.enable} {
|
|
execsnoop ${boolToString ps.useExecsnoop}
|
|
refresh-rate ${toString ps.refreshInterval}
|
|
assignments {
|
|
${
|
|
if ps.foregroundBoost.enable then
|
|
(schedulerProfileToString "foreground" ps.foregroundBoost.foreground " ")
|
|
else
|
|
""
|
|
}
|
|
${
|
|
if ps.foregroundBoost.enable then
|
|
(schedulerProfileToString "background" ps.foregroundBoost.background " ")
|
|
else
|
|
""
|
|
}
|
|
${
|
|
if ps.pipewireBoost.enable then
|
|
(schedulerProfileToString "pipewire" ps.pipewireBoost.profile " ")
|
|
else
|
|
""
|
|
}
|
|
}
|
|
}
|
|
'';
|
|
}
|
|
)
|
|
|
|
{
|
|
"system76-scheduler/process-scheduler/02-config.kdl".text =
|
|
"exceptions {\n${concatStringsSep "\n" (map (e: " ${e}") cfg.exceptions)}\n}\n"
|
|
+ "assignments {\n"
|
|
+ (concatStringsSep "\n" (
|
|
map (name: schedulerProfileToString name cfg.assignments.${name} " ") (attrNames cfg.assignments)
|
|
))
|
|
+ "\n}\n";
|
|
}
|
|
];
|
|
};
|
|
|
|
meta = {
|
|
maintainers = [ lib.maintainers.cmm ];
|
|
};
|
|
}
|