Merge pull request #5769 from NixOS/ca/get-build-stats

Add a crude tracing mechansim for the build results
This commit is contained in:
Eelco Dolstra 2021-12-14 10:53:51 +01:00 committed by GitHub
commit 18e4851752
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 12 deletions

View file

@ -17,6 +17,7 @@
#include <regex> #include <regex>
#include <queue> #include <queue>
#include <fstream>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
@ -464,7 +465,6 @@ void DerivationGoal::inputsRealised()
Derivation drvResolved { *std::move(attempt) }; Derivation drvResolved { *std::move(attempt) };
auto pathResolved = writeDerivation(worker.store, drvResolved); auto pathResolved = writeDerivation(worker.store, drvResolved);
resolvedDrv = drvResolved;
auto msg = fmt("Resolved derivation: '%s' -> '%s'", auto msg = fmt("Resolved derivation: '%s' -> '%s'",
worker.store.printStorePath(drvPath), worker.store.printStorePath(drvPath),
@ -475,9 +475,9 @@ void DerivationGoal::inputsRealised()
worker.store.printStorePath(pathResolved), worker.store.printStorePath(pathResolved),
}); });
auto resolvedGoal = worker.makeDerivationGoal( resolvedDrvGoal = worker.makeDerivationGoal(
pathResolved, wantedOutputs, buildMode); pathResolved, wantedOutputs, buildMode);
addWaitee(resolvedGoal); addWaitee(resolvedDrvGoal);
state = &DerivationGoal::resolvedFinished; state = &DerivationGoal::resolvedFinished;
return; return;
@ -938,16 +938,17 @@ void DerivationGoal::buildDone()
} }
void DerivationGoal::resolvedFinished() { void DerivationGoal::resolvedFinished() {
assert(resolvedDrv); assert(resolvedDrvGoal);
auto resolvedDrv = *resolvedDrvGoal->drv;
auto resolvedHashes = staticOutputHashes(worker.store, *resolvedDrv); auto resolvedHashes = staticOutputHashes(worker.store, resolvedDrv);
StorePathSet outputPaths; StorePathSet outputPaths;
// `wantedOutputs` might be empty, which means “all the outputs” // `wantedOutputs` might be empty, which means “all the outputs”
auto realWantedOutputs = wantedOutputs; auto realWantedOutputs = wantedOutputs;
if (realWantedOutputs.empty()) if (realWantedOutputs.empty())
realWantedOutputs = resolvedDrv->outputNames(); realWantedOutputs = resolvedDrv.outputNames();
for (auto & wantedOutput : realWantedOutputs) { for (auto & wantedOutput : realWantedOutputs) {
assert(initialOutputs.count(wantedOutput) != 0); assert(initialOutputs.count(wantedOutput) != 0);
@ -979,9 +980,17 @@ void DerivationGoal::resolvedFinished() {
outputPaths outputPaths
); );
// This is potentially a bit fishy in terms of error reporting. Not sure auto status = [&]() {
// how to do it in a cleaner way auto resolvedResult = resolvedDrvGoal->getResult();
amDone(nrFailed == 0 ? ecSuccess : ecFailed, ex); switch (resolvedResult.status) {
case BuildResult::AlreadyValid:
return BuildResult::ResolvesToAlreadyValid;
default:
return resolvedResult.status;
}
}();
done(status);
} }
HookReply DerivationGoal::tryBuildHook() HookReply DerivationGoal::tryBuildHook()
@ -1329,6 +1338,13 @@ void DerivationGoal::done(BuildResult::Status status, std::optional<Error> ex)
} }
worker.updateProgress(); worker.updateProgress();
auto traceBuiltOutputsFile = getEnv("_NIX_TRACE_BUILT_OUTPUTS").value_or("");
if (traceBuiltOutputsFile != "") {
std::fstream fs;
fs.open(traceBuiltOutputsFile, std::fstream::out);
fs << worker.store.printStorePath(drvPath) << "\t" << result.toString() << std::endl;
}
} }

View file

@ -50,8 +50,8 @@ struct DerivationGoal : public Goal
/* The path of the derivation. */ /* The path of the derivation. */
StorePath drvPath; StorePath drvPath;
/* The path of the corresponding resolved derivation */ /* The goal for the corresponding resolved derivation */
std::optional<BasicDerivation> resolvedDrv; std::shared_ptr<DerivationGoal> resolvedDrvGoal;
/* The specific outputs that we need to build. Empty means all of /* The specific outputs that we need to build. Empty means all of
them. */ them. */

View file

@ -151,9 +151,33 @@ struct BuildResult
DependencyFailed, DependencyFailed,
LogLimitExceeded, LogLimitExceeded,
NotDeterministic, NotDeterministic,
ResolvesToAlreadyValid,
} status = MiscFailure; } status = MiscFailure;
std::string errorMsg; std::string errorMsg;
std::string toString() const {
auto strStatus = [&]() {
switch (status) {
case Built: return "Built";
case Substituted: return "Substituted";
case AlreadyValid: return "AlreadyValid";
case PermanentFailure: return "PermanentFailure";
case InputRejected: return "InputRejected";
case OutputRejected: return "OutputRejected";
case TransientFailure: return "TransientFailure";
case CachedFailure: return "CachedFailure";
case TimedOut: return "TimedOut";
case MiscFailure: return "MiscFailure";
case DependencyFailed: return "DependencyFailed";
case LogLimitExceeded: return "LogLimitExceeded";
case NotDeterministic: return "NotDeterministic";
case ResolvesToAlreadyValid: return "ResolvesToAlreadyValid";
default: return "Unknown";
};
}();
return strStatus + ((errorMsg == "") ? "" : " : " + errorMsg);
}
/* How many times this build was performed. */ /* How many times this build was performed. */
unsigned int timesBuilt = 0; unsigned int timesBuilt = 0;
@ -170,7 +194,7 @@ struct BuildResult
time_t startTime = 0, stopTime = 0; time_t startTime = 0, stopTime = 0;
bool success() { bool success() {
return status == Built || status == Substituted || status == AlreadyValid; return status == Built || status == Substituted || status == AlreadyValid || status == ResolvesToAlreadyValid;
} }
}; };