diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2022-12-02 12:57:41 +0100 |
---|---|---|
committer | Eelco Dolstra <edolstra@gmail.com> | 2022-12-02 12:59:13 +0100 |
commit | 1e6a5d1ff6e8ef5bf340502f74c4d5039cedc67a (patch) | |
tree | 59899facd4e1989db3f0370aa2e75d0748577d66 | |
parent | 1211e59a038379026496bbee4b203bbd66833b01 (diff) |
Clean up cgroup handling in getMaxCPU()
Also, don't assume in LocalDerivationGoal that cgroups are mounted on
/sys/fs/cgroup.
-rw-r--r-- | src/libstore/build/local-derivation-goal.cc | 6 | ||||
-rw-r--r-- | src/libutil/cgroup.cc | 17 | ||||
-rw-r--r-- | src/libutil/cgroup.hh | 2 | ||||
-rw-r--r-- | src/libutil/util.cc | 49 |
4 files changed, 39 insertions, 35 deletions
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index c9b7b24f3..d2798888b 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -409,12 +409,16 @@ void LocalDerivationGoal::startBuilder() #if __linux__ settings.requireExperimentalFeature(Xp::Cgroups); + auto cgroupFS = getCgroupFS(); + if (!cgroupFS) + throw Error("cannot determine the cgroups file system"); + auto ourCgroups = getCgroups("/proc/self/cgroup"); auto ourCgroup = ourCgroups[""]; if (ourCgroup == "") throw Error("cannot determine cgroup name from /proc/self/cgroup"); - auto ourCgroupPath = canonPath("/sys/fs/cgroup/" + ourCgroup); + auto ourCgroupPath = canonPath(*cgroupFS + "/" + ourCgroup); if (!pathExists(ourCgroupPath)) throw Error("expected cgroup directory '%s'", ourCgroupPath); diff --git a/src/libutil/cgroup.cc b/src/libutil/cgroup.cc index f693d77be..a008481ca 100644 --- a/src/libutil/cgroup.cc +++ b/src/libutil/cgroup.cc @@ -2,6 +2,7 @@ #include "cgroup.hh" #include "util.hh" +#include "finally.hh" #include <chrono> #include <cmath> @@ -10,9 +11,25 @@ #include <thread> #include <dirent.h> +#include <mntent.h> namespace nix { +std::optional<Path> getCgroupFS() +{ + static auto res = [&]() -> std::optional<Path> { + auto fp = fopen("/proc/mounts", "r"); + if (!fp) return std::nullopt; + Finally delFP = [&]() { fclose(fp); }; + while (auto ent = getmntent(fp)) + if (std::string_view(ent->mnt_type) == "cgroup2") + return ent->mnt_dir; + + return std::nullopt; + }(); + return res; +} + // FIXME: obsolete, check for cgroup2 std::map<std::string, std::string> getCgroups(const Path & cgroupFile) { diff --git a/src/libutil/cgroup.hh b/src/libutil/cgroup.hh index 3ead4735f..d08c8ad29 100644 --- a/src/libutil/cgroup.hh +++ b/src/libutil/cgroup.hh @@ -9,6 +9,8 @@ namespace nix { +std::optional<Path> getCgroupFS(); + std::map<std::string, std::string> getCgroups(const Path & cgroupFile); struct CgroupStats diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 623b74bdd..2c2aae82e 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -2,6 +2,7 @@ #include "sync.hh" #include "finally.hh" #include "serialise.hh" +#include "cgroup.hh" #include <array> #include <cctype> @@ -36,7 +37,6 @@ #include <sys/prctl.h> #include <sys/resource.h> -#include <mntent.h> #include <cmath> #endif @@ -727,43 +727,24 @@ unsigned int getMaxCPU() { #if __linux__ try { - FILE *fp = fopen("/proc/mounts", "r"); - if (!fp) - return 0; + auto cgroupFS = getCgroupFS(); + if (!cgroupFS) return 0; - Strings cgPathParts; + if (!pathExists("/proc/self/cgroup")) return 0; - struct mntent *ent; - while ((ent = getmntent(fp))) { - std::string mountType, mountPath; + auto cgroups = getCgroups("/proc/self/cgroup"); + auto cgroup = cgroups[""]; + if (cgroup == "") return 0; - mountType = ent->mnt_type; - mountPath = ent->mnt_dir; + auto cpuFile = *cgroupFS + "/" + cgroup + "/cpu.max"; - if (mountType == "cgroup2") { - cgPathParts.push_back(mountPath); - break; - } - } - - fclose(fp); - - if (cgPathParts.size() > 0 && pathExists("/proc/self/cgroup")) { - std::string currentCgroup = readFile("/proc/self/cgroup"); - Strings cgValues = tokenizeString<Strings>(currentCgroup, ":"); - cgPathParts.push_back(trim(cgValues.back(), "\n")); - cgPathParts.push_back("cpu.max"); - std::string fullCgPath = canonPath(concatStringsSep("/", cgPathParts)); - - if (pathExists(fullCgPath)) { - std::string cpuMax = readFile(fullCgPath); - std::vector<std::string> cpuMaxParts = tokenizeString<std::vector<std::string>>(cpuMax, " "); - std::string quota = cpuMaxParts[0]; - std::string period = trim(cpuMaxParts[1], "\n"); - - if (quota != "max") - return std::ceil(std::stoi(quota) / std::stof(period)); - } + if (pathExists(cpuFile)) { + auto cpuMax = readFile(cpuFile); + auto cpuMaxParts = tokenizeString<std::vector<std::string>>(cpuMax, " \n"); + auto quota = cpuMaxParts[0]; + auto period = cpuMaxParts[1]; + if (quota != "max") + return std::ceil(std::stoi(quota) / std::stof(period)); } } catch (Error &) { ignoreException(); } #endif |