about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSandro <sandro.jaeckel@gmail.com>2024-05-18 15:52:30 +0200
committerGitHub <noreply@github.com>2024-05-18 15:52:30 +0200
commitc21d10ba30f90d5554f0e16fb73af52600f1f8f4 (patch)
treee7f22b24a44939ece33f6853f8000e0aaf0b8837
parentc7829cdc44581b1a589f6d84c125b2501fd158c5 (diff)
parent9f2f6359bb22bddf828ccd6cd4f5abcceffad39e (diff)
Merge pull request #263375 from lorenzleutgeb/benchexec
benchexec: init at 3.21
-rw-r--r--nixos/doc/manual/release-notes/rl-2405.section.md5
-rw-r--r--nixos/modules/module-list.nix3
-rw-r--r--nixos/modules/programs/benchexec.nix98
-rw-r--r--nixos/modules/programs/cpu-energy-meter.nix27
-rw-r--r--nixos/modules/programs/pqos-wrapper.nix27
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/benchexec.nix54
-rw-r--r--pkgs/by-name/be/benchexec/package.nix62
-rw-r--r--pkgs/by-name/cp/cpu-energy-meter/package.nix40
-rw-r--r--pkgs/by-name/pq/pqos-wrapper/package.nix28
10 files changed, 345 insertions, 0 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md
index da2f89824af81..696e9542253a4 100644
--- a/nixos/doc/manual/release-notes/rl-2405.section.md
+++ b/nixos/doc/manual/release-notes/rl-2405.section.md
@@ -92,6 +92,11 @@ Use `services.pipewire.extraConfig` or `services.pipewire.configPackages` for Pi
 
 - [Handheld Daemon](https://github.com/hhd-dev/hhd), support for gaming handhelds like the Legion Go, ROG Ally, and GPD Win. Available as [services.handheld-daemon](#opt-services.handheld-daemon.enable).
 
+- [BenchExec](https://github.com/sosy-lab/benchexec), a framework for reliable benchmarking and resource measurement, available as [programs.benchexec](#opt-programs.benchexec.enable),
+  As well as related programs
+  [CPU Energy Meter](https://github.com/sosy-lab/cpu-energy-meter), available as [programs.cpu-energy-meter](#opt-programs.cpu-energy-meter.enable), and
+  [PQoS Wrapper](https://gitlab.com/sosy-lab/software/pqos-wrapper), available as [programs.pqos-wrapper](#opt-programs.pqos-wrapper.enable).
+
 - [Guix](https://guix.gnu.org), a functional package manager inspired by Nix. Available as [services.guix](#opt-services.guix.enable).
 
 - [PhotonVision](https://photonvision.org/), a free, fast, and easy-to-use computer vision solution for the FIRSTĀ® Robotics Competition.
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index b14b83a8119ac..f446fa13ea26f 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -158,6 +158,7 @@
   ./programs/bash/ls-colors.nix
   ./programs/bash/undistract-me.nix
   ./programs/bcc.nix
+  ./programs/benchexec.nix
   ./programs/browserpass.nix
   ./programs/calls.nix
   ./programs/captive-browser.nix
@@ -167,6 +168,7 @@
   ./programs/chromium.nix
   ./programs/clash-verge.nix
   ./programs/cnping.nix
+  ./programs/cpu-energy-meter.nix
   ./programs/command-not-found/command-not-found.nix
   ./programs/coolercontrol.nix
   ./programs/criu.nix
@@ -250,6 +252,7 @@
   ./programs/pantheon-tweaks.nix
   ./programs/partition-manager.nix
   ./programs/plotinus.nix
+  ./programs/pqos-wrapper.nix
   ./programs/projecteur.nix
   ./programs/proxychains.nix
   ./programs/qdmr.nix
diff --git a/nixos/modules/programs/benchexec.nix b/nixos/modules/programs/benchexec.nix
new file mode 100644
index 0000000000000..652670c117ea3
--- /dev/null
+++ b/nixos/modules/programs/benchexec.nix
@@ -0,0 +1,98 @@
+{ lib
+, pkgs
+, config
+, options
+, ...
+}:
+let
+  cfg = config.programs.benchexec;
+  opt = options.programs.benchexec;
+
+  filterUsers = x:
+    if builtins.isString x then config.users.users ? ${x} else
+    if builtins.isInt    x then x                         else
+    throw "filterUsers expects string (username) or int (UID)";
+
+  uid = x:
+    if builtins.isString x then config.users.users.${x}.uid else
+    if builtins.isInt    x then x                           else
+    throw "uid expects string (username) or int (UID)";
+in
+{
+  options.programs.benchexec = {
+    enable = lib.mkEnableOption "BenchExec";
+    package = lib.options.mkPackageOption pkgs "benchexec" { };
+
+    users = lib.options.mkOption {
+      type = with lib.types; listOf (either str int);
+      description = ''
+        Users that intend to use BenchExec.
+        Provide usernames of users that are configured via {option}`${options.users.users}` as string,
+        and UIDs of "mutable users" as integers.
+        Control group delegation will be configured via systemd.
+        For more information, see <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#setting-up-cgroups>.
+      '';
+      default = [ ];
+      example = lib.literalExpression ''
+        [
+          "alice" # username of a user configured via ${options.users.users}
+          1007    # UID of a mutable user
+        ]
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    assertions = (map
+      (user: {
+        assertion = config.users.users ? ${user};
+        message = ''
+          The user '${user}' intends to use BenchExec (via `${opt.users}`), but is not configured via `${options.users.users}`.
+        '';
+      })
+      (builtins.filter builtins.isString cfg.users)
+    ) ++ (map
+      (id: {
+        assertion = config.users.mutableUsers;
+        message = ''
+          The user with UID '${id}' intends to use BenchExec (via `${opt.users}`), but mutable users are disabled via `${options.users.mutableUsers}`.
+        '';
+      })
+      (builtins.filter builtins.isInt cfg.users)
+    ) ++ [
+      {
+        assertion = config.systemd.enableUnifiedCgroupHierarchy == true;
+        message = ''
+          The BenchExec module `${opt.enable}` only supports control groups 2 (`${options.systemd.enableUnifiedCgroupHierarchy} = true`).
+        '';
+      }
+    ];
+
+    environment.systemPackages = [ cfg.package ];
+
+    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#setting-up-cgroups>.
+    systemd.services = builtins.listToAttrs (map
+      (user: {
+        name = "user@${builtins.toString (uid user)}";
+        value = {
+          serviceConfig.Delegate = "yes";
+          overrideStrategy = "asDropin";
+        };
+      })
+      (builtins.filter filterUsers cfg.users));
+
+    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#requirements>.
+    virtualisation.lxc.lxcfs.enable = lib.mkDefault true;
+
+    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#requirements>.
+    programs = {
+      cpu-energy-meter.enable = lib.mkDefault true;
+      pqos-wrapper.enable = lib.mkDefault true;
+    };
+
+    # See <https://github.com/sosy-lab/benchexec/blob/3.18/doc/INSTALL.md#kernel-requirements>.
+    security.unprivilegedUsernsClone = true;
+  };
+
+  meta.maintainers = with lib.maintainers; [ lorenzleutgeb ];
+}
diff --git a/nixos/modules/programs/cpu-energy-meter.nix b/nixos/modules/programs/cpu-energy-meter.nix
new file mode 100644
index 0000000000000..653ec067492d7
--- /dev/null
+++ b/nixos/modules/programs/cpu-energy-meter.nix
@@ -0,0 +1,27 @@
+{ config
+, lib
+, pkgs
+, ...
+}: {
+  options.programs.cpu-energy-meter = {
+    enable = lib.mkEnableOption "CPU Energy Meter";
+    package = lib.mkPackageOption pkgs "cpu-energy-meter" { };
+  };
+
+  config =
+    let
+      cfg = config.programs.cpu-energy-meter;
+    in
+    lib.mkIf cfg.enable {
+      hardware.cpu.x86.msr.enable = true;
+
+      security.wrappers.${cfg.package.meta.mainProgram} = {
+        owner = "nobody";
+        group = config.hardware.cpu.x86.msr.group;
+        source = lib.getExe cfg.package;
+        capabilities = "cap_sys_rawio=ep";
+      };
+    };
+
+  meta.maintainers = with lib.maintainers; [ lorenzleutgeb ];
+}
diff --git a/nixos/modules/programs/pqos-wrapper.nix b/nixos/modules/programs/pqos-wrapper.nix
new file mode 100644
index 0000000000000..82023e67a2ae2
--- /dev/null
+++ b/nixos/modules/programs/pqos-wrapper.nix
@@ -0,0 +1,27 @@
+{ config
+, lib
+, pkgs
+, ...
+}:
+let
+  cfg = config.programs.pqos-wrapper;
+in
+{
+  options.programs.pqos-wrapper = {
+    enable = lib.mkEnableOption "PQoS Wrapper for BenchExec";
+    package = lib.mkPackageOption pkgs "pqos-wrapper" { };
+  };
+
+  config = lib.mkIf cfg.enable {
+    hardware.cpu.x86.msr.enable = true;
+
+    security.wrappers.${cfg.package.meta.mainProgram} = {
+      owner = "nobody";
+      group = config.hardware.cpu.x86.msr.group;
+      source = lib.getExe cfg.package;
+      capabilities = "cap_sys_rawio=eip";
+    };
+  };
+
+  meta.maintainers = with lib.maintainers; [ lorenzleutgeb ];
+}
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index c6ec2474e6052..ccde1a9feb2ad 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -144,6 +144,7 @@ in {
   bcachefs = handleTestOn ["x86_64-linux" "aarch64-linux"] ./bcachefs.nix {};
   beanstalkd = handleTest ./beanstalkd.nix {};
   bees = handleTest ./bees.nix {};
+  benchexec = handleTest ./benchexec.nix {};
   binary-cache = handleTest ./binary-cache.nix {};
   bind = handleTest ./bind.nix {};
   bird = handleTest ./bird.nix {};
diff --git a/nixos/tests/benchexec.nix b/nixos/tests/benchexec.nix
new file mode 100644
index 0000000000000..3fc9ebc2c35f5
--- /dev/null
+++ b/nixos/tests/benchexec.nix
@@ -0,0 +1,54 @@
+import ./make-test-python.nix ({ pkgs, lib, ... }:
+let
+  user = "alice";
+in
+{
+  name = "benchexec";
+
+  nodes.benchexec = {
+    imports = [ ./common/user-account.nix ];
+
+    programs.benchexec = {
+      enable = true;
+      users = [ user ];
+    };
+  };
+
+  testScript = { ... }:
+    let
+      runexec = lib.getExe' pkgs.benchexec "runexec";
+      echo = builtins.toString pkgs.benchexec;
+      test = lib.getExe (pkgs.writeShellApplication rec {
+        name = "test";
+        meta.mainProgram = name;
+        text = "echo '${echo}'";
+      });
+      wd = "/tmp";
+      stdout = "${wd}/runexec.out";
+      stderr = "${wd}/runexec.err";
+    in
+    ''
+      start_all()
+      machine.wait_for_unit("multi-user.target")
+      benchexec.succeed(''''\
+          systemd-run \
+            --property='StandardOutput=file:${stdout}' \
+            --property='StandardError=file:${stderr}' \
+            --unit=runexec --wait --user --machine='${user}@' \
+            --working-directory ${wd} \
+          '${runexec}' \
+            --debug \
+            --read-only-dir / \
+            --hidden-dir /home \
+            '${test}' \
+      '''')
+      benchexec.succeed("grep -s '${echo}' ${wd}/output.log")
+      benchexec.succeed("test \"$(grep -Ec '((start|wall|cpu)time|memory)=' ${stdout})\" = 4")
+      benchexec.succeed("! grep -E '(WARNING|ERROR)' ${stderr}")
+    '';
+
+  interactive.nodes.benchexec.services.kmscon = {
+    enable = true;
+    fonts = [{ name = "Fira Code"; package = pkgs.fira-code; }];
+  };
+})
diff --git a/pkgs/by-name/be/benchexec/package.nix b/pkgs/by-name/be/benchexec/package.nix
new file mode 100644
index 0000000000000..abc04b97cb8de
--- /dev/null
+++ b/pkgs/by-name/be/benchexec/package.nix
@@ -0,0 +1,62 @@
+{ lib
+, fetchFromGitHub
+, python3
+, libseccomp
+, nixosTests
+, testers
+, benchexec
+}:
+python3.pkgs.buildPythonApplication rec {
+  pname = "benchexec";
+  version = "3.21";
+
+  src = fetchFromGitHub {
+    owner = "sosy-lab";
+    repo = "benchexec";
+    rev = version;
+    hash = "sha256-bE3brmmLHZQakDKvd47I1hm9Dcsu6DrSeJyjWWtEZWI=";
+  };
+
+  pyproject = true;
+
+  nativeBuildInputs = with python3.pkgs; [ setuptools ];
+
+  # NOTE: CPU Energy Meter is not added,
+  # because BenchExec should call the wrapper configured
+  # via `security.wrappers.cpu-energy-meter`
+  # in `programs.cpu-energy-meter`, which will have the required
+  # capabilities to access MSR.
+  # If we add `cpu-energy-meter` here, BenchExec will instead call an executable
+  # without `CAP_SYS_RAWIO` and fail.
+  propagatedBuildInputs = with python3.pkgs; [
+    coloredlogs
+    lxml
+    pystemd
+    pyyaml
+  ];
+
+  makeWrapperArgs = [ "--set-default LIBSECCOMP ${lib.getLib libseccomp}/lib/libseccomp.so" ];
+
+  passthru.tests =
+    let
+      testVersion = result: testers.testVersion {
+        command = "${result} --version";
+        package = benchexec;
+      };
+    in
+    {
+      nixos = nixosTests.benchexec;
+      benchexec-version = testVersion "benchexec";
+      runexec-version = testVersion "runexec";
+      table-generator-version = testVersion "table-generator";
+      containerexec-version = testVersion "containerexec";
+    };
+
+  meta = with lib; {
+    description = "A Framework for Reliable Benchmarking and Resource Measurement.";
+    homepage = "https://github.com/sosy-lab/benchexec";
+    maintainers = with maintainers; [ lorenzleutgeb ];
+    license = licenses.asl20;
+    mainProgram = "benchexec";
+  };
+}
diff --git a/pkgs/by-name/cp/cpu-energy-meter/package.nix b/pkgs/by-name/cp/cpu-energy-meter/package.nix
new file mode 100644
index 0000000000000..6d31da594645c
--- /dev/null
+++ b/pkgs/by-name/cp/cpu-energy-meter/package.nix
@@ -0,0 +1,40 @@
+{ lib
+, stdenv
+, fetchFromGitHub
+, libcap
+}:
+stdenv.mkDerivation rec {
+  pname = "cpu-energy-meter";
+  version = "1.2";
+
+  src = fetchFromGitHub {
+    owner = "sosy-lab";
+    repo = "cpu-energy-meter";
+    rev = version;
+    hash = "sha256-QW65Z8mRYLHcyLeOtNAHjwPNWAUP214wqIYclK+whFw=";
+  };
+
+  postPatch = ''
+    substituteInPlace Makefile \
+      --replace "DESTDIR :=" "DESTDIR := $out" \
+      --replace "PREFIX := /usr/local" "PREFIX :="
+  '';
+
+  buildInputs = [ libcap ];
+
+  env.NIX_CFLAGS_COMPILE = "-fcommon";
+
+  postInstall = ''
+    install -Dm444 -t $out/etc/udev/rules.d $src/debian/additional_files/59-msr.rules
+  '';
+
+  meta = with lib; {
+    description = "A tool for measuring energy consumption of Intel CPUs";
+    homepage = "https://github.com/sosy-lab/cpu-energy-meter";
+    changelog = "https://github.com/sosy-lab/cpu-energy-meter/blob/main/CHANGELOG.md";
+    maintainers = with maintainers; [ lorenzleutgeb ];
+    license = licenses.bsd3;
+    platforms = [ "x86_64-linux" ];
+    mainProgram = "cpu-energy-meter";
+  };
+}
diff --git a/pkgs/by-name/pq/pqos-wrapper/package.nix b/pkgs/by-name/pq/pqos-wrapper/package.nix
new file mode 100644
index 0000000000000..d0235fedc3a71
--- /dev/null
+++ b/pkgs/by-name/pq/pqos-wrapper/package.nix
@@ -0,0 +1,28 @@
+{ lib
+, intel-cmt-cat
+, fetchFromGitLab
+, python3
+}:
+python3.pkgs.buildPythonApplication rec {
+  pname = "pqos-wrapper";
+  version = "unstable-2022-01-31";
+
+  src = fetchFromGitLab {
+    group = "sosy-lab";
+    owner = "software";
+    repo = pname;
+    rev = "ce816497a07dcb4b931652b98359e4601a292b15";
+    hash = "sha256-SaYr6lVucpJjVtGgxRbDGYbOoBwdfEDVKtvD+M1L0o4=";
+  };
+
+  makeWrapperArgs = [ "--prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [ intel-cmt-cat ]}" ];
+
+  meta = with lib; {
+    description = "Wrapper for Intel PQoS for the purpose of using it in BenchExec";
+    homepage = "https://gitlab.com/sosy-lab/software/pqos-wrapper";
+    maintainers = with maintainers; [ lorenzleutgeb ];
+    license = licenses.asl20;
+    platforms = [ "x86_64-linux" ];
+    mainProgram = "pqos_wrapper";
+  };
+}