diff --git a/src/libstore/build-result.hh b/src/libstore/build-result.hh index a5749cf33ca..dd326c07f8a 100644 --- a/src/libstore/build-result.hh +++ b/src/libstore/build-result.hh @@ -80,6 +80,7 @@ struct BuildResult /* User and system CPU time the build took. */ std::optional cpuUser, cpuSystem; + std::optional memoryHigh; bool success() { diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index c9b7b24f344..01a4ff11fa0 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -154,6 +154,7 @@ void LocalDerivationGoal::killSandbox(bool getStats) if (getStats) { buildResult.cpuUser = stats.cpuUser; buildResult.cpuSystem = stats.cpuSystem; + buildResult.memoryHigh = stats.memoryHigh; } #else abort(); @@ -415,6 +416,7 @@ void LocalDerivationGoal::startBuilder() throw Error("cannot determine cgroup name from /proc/self/cgroup"); auto ourCgroupPath = canonPath("/sys/fs/cgroup/" + ourCgroup); + ourCgroupPath = dirOf(ourCgroupPath); if (!pathExists(ourCgroupPath)) throw Error("expected cgroup directory '%s'", ourCgroupPath); @@ -720,6 +722,15 @@ void LocalDerivationGoal::startBuilder() chownToBuilder(*cgroup); chownToBuilder(*cgroup + "/cgroup.procs"); chownToBuilder(*cgroup + "/cgroup.threads"); + auto parentCgroup = dirOf(*cgroup); + writeFile(parentCgroup + "/cgroup.subtree_control", "+memory"); + writeFile(*cgroup + "/memory.oom.group", "1"); + if (settings.memoryHigh) { + writeFile(*cgroup + "/memory.high", fmt("%d", settings.memoryHigh)); + } + if (settings.memoryMax) { + writeFile(*cgroup + "/memory.max", fmt("%d", settings.memoryMax)); + } //chownToBuilder(*cgroup + "/cgroup.subtree_control"); } @@ -751,7 +762,14 @@ void LocalDerivationGoal::startBuilder() stExtraChrootDirs }; auto state = stBegin; - auto lines = runProgram(settings.preBuildHook, false, args); + auto hookEnv = getEnv(); + if (cgroup) hookEnv["NIX_CGROUP"] = *cgroup; + auto res = runProgram(RunOptions {.program = settings.preBuildHook, .searchPath = false, .args = args, .environment = hookEnv, .input = {} }); + + if (!statusOk(res.first)) + throw ExecError(res.first, "program '%1%' %2%", settings.preBuildHook, statusToString(res.first)); + + auto lines = res.second; auto lastPos = std::string::size_type{0}; for (auto nlPos = lines.find('\n'); nlPos != std::string::npos; nlPos = lines.find('\n', lastPos)) diff --git a/src/libstore/cgroup.cc b/src/libstore/cgroup.cc index f693d77bee4..80b94a67e8c 100644 --- a/src/libstore/cgroup.cc +++ b/src/libstore/cgroup.cc @@ -113,6 +113,11 @@ static CgroupStats destroyCgroup(const Path & cgroup, bool returnStats) } } + auto memoryhighPath = cgroup + "/memory.high"; + if (pathExists(memoryhighPath)) { + stats.memoryHigh = string2Int(trim(readFile(memoryhighPath))); + } + debug("memory events %s", readFile(cgroup + "/memory.events")); } if (rmdir(cgroup.c_str()) == -1) diff --git a/src/libstore/cgroup.hh b/src/libstore/cgroup.hh index 3ead4735f52..05a38742af5 100644 --- a/src/libstore/cgroup.hh +++ b/src/libstore/cgroup.hh @@ -14,6 +14,7 @@ std::map getCgroups(const Path & cgroupFile); struct CgroupStats { std::optional cpuUser, cpuSystem; + std::optional memoryHigh; }; /* Destroy the cgroup denoted by 'path'. The postcondition is that diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh index b40dcfa77da..ee859ae5bbe 100644 --- a/src/libstore/globals.hh +++ b/src/libstore/globals.hh @@ -313,6 +313,22 @@ public: `uid-range` system feature. )" }; + + Setting memoryHigh{ + this, 0, "memory-high", + R"( + sets the cgroup memory.high limit, causing the build to throttle if exceeded + depends on use-cgroups=true + )" + }; + + Setting memoryMax{ + this, 0, "memory-max", + R"( + sets the cgroup memory.max limit, causing the build to be killed if exceeded + depends on use-cgroups=true + )" + }; #endif Setting impersonateLinux26{this, false, "impersonate-linux-26", diff --git a/src/nix/build.cc b/src/nix/build.cc index 94b169167e6..4f6e0234ec1 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -34,6 +34,7 @@ nlohmann::json builtPathsWithResultToJSON(const std::vector j["cpuUser"] = ((double) b.result->cpuUser->count()) / 1000000; if (b.result->cpuSystem) j["cpuSystem"] = ((double) b.result->cpuSystem->count()) / 1000000; + if (b.result->memoryHigh) j["memoryHigh"] = *b.result->memoryHigh; } res.push_back(j); }, b.path.raw());