Skip to content

Commit

Permalink
worker protocol: serialise cgroup stats in BuildResult (NixOS#9598)
Browse files Browse the repository at this point in the history
By doing so, they get reported when building through the daemon via either `unix://` or `ssh-ng://`.
  • Loading branch information
r-vdp authored Dec 13, 2023
1 parent e6515bd commit 1e3d811
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 8 deletions.
8 changes: 8 additions & 0 deletions doc/manual/rl-next/cgroup-stats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
synopsis: Include cgroup stats when building through the daemon
prs: 9598
---

Nix now also reports cgroup statistics when building through the nix daemon and when doing remote builds using ssh-ng,
if both sides of the connection are this version of Nix or newer.

34 changes: 34 additions & 0 deletions src/libstore/worker-protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "archive.hh"
#include "path-info.hh"

#include <chrono>
#include <nlohmann/json.hpp>

namespace nix {
Expand Down Expand Up @@ -47,6 +48,31 @@ void WorkerProto::Serialise<std::optional<TrustedFlag>>::write(const StoreDirCon
}


std::optional<std::chrono::microseconds> WorkerProto::Serialise<std::optional<std::chrono::microseconds>>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn)
{
auto tag = readNum<uint8_t>(conn.from);
switch (tag) {
case 0:
return std::nullopt;
case 1:
return std::optional<std::chrono::microseconds>{std::chrono::microseconds(readNum<int64_t>(conn.from))};
default:
throw Error("Invalid optional tag from remote");
}
}

void WorkerProto::Serialise<std::optional<std::chrono::microseconds>>::write(const StoreDirConfig & store, WorkerProto::WriteConn conn, const std::optional<std::chrono::microseconds> & optDuration)
{
if (!optDuration.has_value()) {
conn.to << uint8_t{0};
} else {
conn.to
<< uint8_t{1}
<< optDuration.value().count();
}
}


DerivedPath WorkerProto::Serialise<DerivedPath>::read(const StoreDirConfig & store, WorkerProto::ReadConn conn)
{
auto s = readString(conn.from);
Expand Down Expand Up @@ -110,6 +136,10 @@ BuildResult WorkerProto::Serialise<BuildResult>::read(const StoreDirConfig & sto
>> res.startTime
>> res.stopTime;
}
if (GET_PROTOCOL_MINOR(conn.version) >= 37) {
res.cpuUser = WorkerProto::Serialise<std::optional<std::chrono::microseconds>>::read(store, conn);
res.cpuSystem = WorkerProto::Serialise<std::optional<std::chrono::microseconds>>::read(store, conn);
}
if (GET_PROTOCOL_MINOR(conn.version) >= 28) {
auto builtOutputs = WorkerProto::Serialise<DrvOutputs>::read(store, conn);
for (auto && [output, realisation] : builtOutputs)
Expand All @@ -132,6 +162,10 @@ void WorkerProto::Serialise<BuildResult>::write(const StoreDirConfig & store, Wo
<< res.startTime
<< res.stopTime;
}
if (GET_PROTOCOL_MINOR(conn.version) >= 37) {
WorkerProto::write(store, conn, res.cpuUser);
WorkerProto::write(store, conn, res.cpuSystem);
}
if (GET_PROTOCOL_MINOR(conn.version) >= 28) {
DrvOutputs builtOutputs;
for (auto & [output, realisation] : res.builtOutputs)
Expand Down
6 changes: 5 additions & 1 deletion src/libstore/worker-protocol.hh
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
///@file

#include <chrono>

#include "common-protocol.hh"

namespace nix {
Expand All @@ -9,7 +11,7 @@ namespace nix {
#define WORKER_MAGIC_1 0x6e697863
#define WORKER_MAGIC_2 0x6478696f

#define PROTOCOL_VERSION (1 << 8 | 36)
#define PROTOCOL_VERSION (1 << 8 | 37)
#define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)

Expand Down Expand Up @@ -214,6 +216,8 @@ template<>
DECLARE_WORKER_SERIALISER(UnkeyedValidPathInfo);
template<>
DECLARE_WORKER_SERIALISER(std::optional<TrustedFlag>);
template<>
DECLARE_WORKER_SERIALISER(std::optional<std::chrono::microseconds>);

template<typename T>
DECLARE_WORKER_SERIALISER(std::vector<T>);
Expand Down
Binary file not shown.
61 changes: 54 additions & 7 deletions tests/unit/libstore/worker-protocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -280,13 +280,60 @@ VERSIONED_CHARACTERIZATION_TEST(
},
.startTime = 30,
.stopTime = 50,
#if 0
// These fields are not yet serialized.
// FIXME Include in next version of protocol or document
// why they are skipped.
.cpuUser = std::chrono::milliseconds(500s),
.cpuSystem = std::chrono::milliseconds(604s),
#endif
},
};
t;
}))

VERSIONED_CHARACTERIZATION_TEST(
WorkerProtoTest,
buildResult_1_37,
"build-result-1.37",
1 << 8 | 37,
({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t {
BuildResult {
.status = BuildResult::OutputRejected,
.errorMsg = "no idea why",
},
BuildResult {
.status = BuildResult::NotDeterministic,
.errorMsg = "no idea why",
.timesBuilt = 3,
.isNonDeterministic = true,
.startTime = 30,
.stopTime = 50,
},
BuildResult {
.status = BuildResult::Built,
.timesBuilt = 1,
.builtOutputs = {
{
"foo",
{
.id = DrvOutput {
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "foo",
},
.outPath = StorePath { "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo" },
},
},
{
"bar",
{
.id = DrvOutput {
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "bar",
},
.outPath = StorePath { "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar" },
},
},
},
.startTime = 30,
.stopTime = 50,
.cpuUser = std::chrono::microseconds(500s),
.cpuSystem = std::chrono::microseconds(604s),
},
};
t;
Expand Down

0 comments on commit 1e3d811

Please sign in to comment.