hydra-eval-jobs: Parallelize

[?]
Feb 19, 2020, 8:10 PM
XJISJGZLGWLCTN6EZWVVHKQFCDVCSXTNYL7YE2UB74AOA2XGYOCAC

Dependencies

  • [2] GPZYBCJC accidentally committed an = too little, which caused all unknown values to result in 'not building', which was not the intention
  • [3] CYVWW32Q Revert "Fix broken build.x86_64-linux job (#573)"
  • [4] A6POFA3H hydra-eval-jobs: Filter ANSI escape sequences
  • [5] VMZDEQQ5 Increase maxHeapSize more gradually
  • [6] CXKN2W4B hydra-eval-jobs: Reinitialize Boehm GC in the child
  • [7] JSBIUNY6 hydra-eval-jobs: fix maintainer resolution
  • [8] YRXR3WDP hydra-eval-jobs: Warn and resets maxHeapSize on bad values
  • [9] WV4SSAIY Build against nix-master
  • [10] OC4Q4PXC Sync with nixUnstable
  • [11] KD5237CU * eval-jobs now efficiently evaluates all Hydra jobs from a
  • [12] 7GKAIP3V Fix build and handling of string inputs starting with a dash
  • [13] AYMPPH7G Don't write one character at a time, it's inefficient
  • [14] HP5WJLQU hydra-eval-{jobs,jobset}: Pass file name as <...>
  • [15] HJYRK37A * Revert r27114, it seems to break stuff.
  • [16] VTMBJVIS hydra-eval-jobs: Disable the build hook.
  • [17] 4N5APGRG * Start of a helper tool to evaluate job expressions efficiently.
  • [18] FHXU6346 hydra-eval-jobs: Pass all inputs as 'inputs' arg.
  • [19] ZVSHXE3K Allow setting GC_INITIAL_HEAP_SIZE for hydra-eval-jobs
  • [20] 52JSLNC6 * Build fix.
  • [21] 4XR2A7QD * Fix building hydra_eval_jobs against the sqlite branch.
  • [22] WUMCRXFX Don't ignore assertion failures in getDerivation()
  • [23] IZ2AHLM3 * Export all relevant info about the derivation.
  • [24] 5MNUNZWR * Store meta.maintainers.
  • [25] FGLKIVYS Fix build against Nix master
  • [26] M3A5PZIH hydra: Clarify the dependency on BDW-GC.
  • [27] 4LWGZL33
  • [28] YGRLM2SK * Export all relevant info about the derivation.
  • [29] 7YCFGMZB * Report evaluation errors per job, and don't bail out if a job fails
  • [30] FGUL3HAZ hydra-eval-jobs: Don't go into an infinite recursion
  • [31] MIC2O6ZF Use evalFile() instead of parseExprFromFile()
  • [32] YNGIYQRF hydra-eval-jobs: Don't keep track of used inputs
  • [33] ZTQEU5QS Hydra: Add support for maxSilent meta attribute (also already added timeout, but not implemented the actual timeout for the build yet)
  • [34] I2HYJBML Debug tweak
  • [35] DPYJFBXU hydra-eval-jobs: Support meta.license being a list
  • [36] WJTP6VZI Fix building against the latest Nix
  • [37] 7D6RFSAA Fix build for new nixUnstable
  • [38] JTHWA6AM Rename aggregate members to constituents
  • [39] STZE4KKR Fix build against Nix master
  • [40] L4LBF7UF Handle derivations without a system attribute
  • [41] HVXL2XUZ
  • [42] D6VR5FYG * Fix hydra_eval_jobs.
  • [43] RLXDJAG2 hydra-eval-jobs: Add --dry-run option
  • [44] 77VF5TC6 * For ease of use during debugging, don't require --gc-roots-dir.
  • [45] M5BEPXTE Tweak debug output
  • [46] 5DYPEBSI hydra-eval-jobs: Use function argument default values
  • [47] IMQRX4MP hydra-eval-jobs: Use JSON instead of XML
  • [48] 5MP35ORV hydra-eval-jobs: Ugly hackery to reduce memory usage
  • [49] FTPCV25M Store aggregate members in the database
  • [50] AEFNBIIW * Merge the GC branch.
  • [51] DKJFD6JN Process Nix API changes
  • [52] 5X6FHW3S hydra-eval-jobs: Fix building against the latest unstable Nix
  • [53] HNGPGVBT Fix build
  • [54] BGMBEXS6 Gradually increase maxHeapSize
  • [55] L4GM4MA6 Call initGC()
  • [56] AEKIREIH * Updated hydra_eval_jobs for the new evaluator.
  • [57] EBG4P4SY Doh - clear $NIX_PATH properly
  • [58] POPU2ATH * hydra_scheduler: use eval-jobs.
  • [59] SYN2GC3O allow null values for jobs, meaning it should build
  • [60] ALU52WZJ Handle attrsets in meta.license (i.e. lib.licenses)
  • [61] 4GTOWRFW hydra-eval-jobs: Fix build
  • [62] VTNP5KDO * Don't catch all errors. Some errors mess up the connection with the
  • [63] A63IHCMX * Register GC roots properly.
  • [64] JQ5VHWRB Fix broken build.x86_64-linux job (#573)
  • [65] SM5M2J3A Pass inputs to release expressions using -I
  • [66] 3PNG7NIB Remove trailing whitespace
  • [67] P45ANG5B Fix build
  • [68] PMNWRTGJ Add multiple output support
  • [69] FUB37KFU Use Nix's restricted evaluation mode

Change contents

  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 3
    [10.339][10.354:355](),[10.355][6.0:27](),[6.27][10.355:384](),[10.355][10.355:384]()
    #define GC_LINUX_THREADS 1
    #include <gc/gc_allocator.h>
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 9
    [10.45][10.0:19]()
    #include "json.hh"
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 12
    [10.31]
    [10.57]
    #include "attr-path.hh"
    #include "derivations.hh"
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 19
    [10.45]
    [10.45]
    #include <sys/resource.h>
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 21
    [10.46][10.452:473](),[10.452][10.452:473]()
    using namespace nix;
    [10.46]
    [10.473]
    #include <nlohmann/json.hpp>
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 23
    [10.474]
    [10.474]
    using namespace nix;
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 26
    [10.26]
    [10.159]
    static size_t maxMemorySize;
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 28
    [10.160]
    [10.160]
    struct MyArgs : MixEvalArgs, MixCommonArgs
    {
    Path releaseExpr;
    bool dryRun = false;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 33
    [10.161][10.29:87](),[10.87][10.32:94]()
    static void findJobs(EvalState & state, JSONObject & top,
    Bindings & autoArgs, Value & v, const string & attrPath);
    [10.161]
    [10.143]
    MyArgs() : MixCommonArgs("hydra-eval-jobs")
    {
    mkFlag()
    .longName("help")
    .description("show usage information")
    .handler([&]() {
    printHelp(programName, std::cout);
    throw Exit();
    });
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 43
    [10.144]
    [10.0]
    mkFlag()
    .longName("gc-roots-dir")
    .description("garbage collector roots directory")
    .labels({"path"})
    .dest(&gcRootsDir);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 49
    [10.1][7.0:115]()
    static string queryMetaStrings(EvalState & state, DrvInfo & drv, const string & name, const string & subAttribute)
    [10.1]
    [10.294]
    mkFlag()
    .longName("dry-run")
    .description("don't create store derivations")
    .set(&dryRun, true);
    expectArg("expr", &releaseExpr);
    }
    };
    static MyArgs myArgs;
    static std::string queryMetaStrings(EvalState & state, DrvInfo & drv, const string & name, const string & subAttribute)
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 84
    [10.1407][10.47:137]()
    static std::string lastAttrPath;
    static bool comma = false;
    static size_t maxHeapSize;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 85
    [10.138][10.138:158]()
    struct BailOut { };
    [10.138]
    [10.1407]
    static void worker(
    EvalState & state,
    Bindings & autoArgs,
    AutoCloseFD & to,
    AutoCloseFD & from)
    {
    Value vTop;
    state.evalFile(lookupFileArg(state, myArgs.releaseExpr), vTop);
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 94
    [10.1408]
    [10.1573]
    auto vRoot = state.allocValue();
    state.autoCallFunction(autoArgs, vTop, *vRoot);
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 97
    [10.1574][10.159:246]()
    bool lte(const std::string & s1, const std::string & s2)
    {
    size_t p1 = 0, p2 = 0;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 98
    [10.265][10.265:360]()
    if (p1 == s1.size()) return p2 == s2.size();
    if (p2 == s2.size()) return true;
    [10.265]
    [10.360]
    /* Wait for the master to send us a job name. */
    writeLine(to.get(), "next");
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 101
    [10.361][10.361:433]()
    auto d1 = s1.find('.', p1);
    auto d2 = s2.find('.', p2);
    [10.361]
    [10.433]
    auto s = readLine(from.get());
    if (s == "exit") break;
    if (!hasPrefix(s, "do ")) abort();
    std::string attrPath(s, 3);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 106
    [10.434][10.434:493]()
    auto c = s1.compare(p1, d1 - p1, s2, p2, d2 - p2);
    [10.434]
    [10.493]
    debug("worker process %d at '%s'", getpid(), attrPath);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 108
    [10.494][10.494:559]()
    if (c < 0) return true;
    if (c > 0) return false;
    [10.494]
    [10.559]
    /* Evaluate it and send info back to the master. */
    nlohmann::json reply;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 111
    [10.560][10.560:686]()
    p1 = d1 == std::string::npos ? s1.size() : d1 + 1;
    p2 = d2 == std::string::npos ? s2.size() : d2 + 1;
    }
    }
    [10.560]
    [10.686]
    try {
    auto v = findAlongAttrPath(state, attrPath, autoArgs, *vRoot).first;
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 114
    [10.687]
    [10.687]
    state.forceValue(*v);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 116
    [10.688][10.369:434](),[10.1574][10.369:434](),[10.434][10.95:158](),[10.158][10.255:257](),[10.426][10.255:257](),[10.1673][10.255:257](),[10.255][10.255:257](),[10.257][10.689:756]()
    static void findJobsWrapped(EvalState & state, JSONObject & top,
    Bindings & autoArgs, Value & vIn, const string & attrPath)
    {
    if (lastAttrPath != "" && lte(attrPath, lastAttrPath)) return;
    [10.688]
    [10.756]
    if (auto drv = getDerivation(state, *v, false)) {
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 118
    [10.757][10.1529:1576](),[10.257][10.1529:1576]()
    debug(format("at path `%1%'") % attrPath);
    [10.757]
    [10.54]
    DrvInfo::Outputs outputs = drv->queryOutputs();
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 120
    [10.55][10.55:77]()
    checkInterrupt();
    [10.55]
    [10.979]
    if (drv->querySystem() == "unknown")
    throw EvalError("derivation must have a 'system' attribute");
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 123
    [10.980][10.159:218]()
    Value v;
    state.autoCallFunction(autoArgs, vIn, v);
    [10.980]
    [10.336]
    auto drvPath = drv->queryDrvPath();
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 125
    [10.337][10.1700:1728]()
    if (v.type == tAttrs) {
    [10.337]
    [10.511]
    nlohmann::json job;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 127
    [10.512][10.0:51]()
    auto drv = getDerivation(state, v, false);
    [10.512]
    [10.802]
    job["nixName"] = drv->queryName();
    job["system"] =drv->querySystem();
    job["drvPath"] = drvPath;
    job["description"] = drv->queryMetaString("description");
    job["license"] = queryMetaStrings(state, *drv, "license", "shortName");
    job["homepage"] = drv->queryMetaString("homepage");
    job["maintainers"] = queryMetaStrings(state, *drv, "maintainers", "email");
    job["schedulingPriority"] = drv->queryMetaInt("schedulingPriority", 100);
    job["timeout"] = drv->queryMetaInt("timeout", 36000);
    job["maxSilent"] = drv->queryMetaInt("maxSilent", 7200);
    job["isChannel"] = drv->queryMetaBool("isHydraChannel", false);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 139
    [10.803][10.52:71](),[10.71][10.29:55](),[10.712][10.29:55]()
    if (drv) {
    Path drvPath;
    [10.803]
    [10.0]
    /* If this is an aggregate, then get its constituents. */
    auto a = v->attrs->get(state.symbols.create("_hydraAggregate"));
    if (a && state.forceBool(*a->value, *a->pos)) {
    auto a = v->attrs->get(state.symbols.create("constituents"));
    if (!a)
    throw EvalError("derivation must have a ‘constituents’ attribute");
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 146
    [10.1][10.72:132]()
    DrvInfo::Outputs outputs = drv->queryOutputs();
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 147
    [10.748][10.133:182](),[10.182][10.41:123](),[10.41][10.41:123](),[10.123][10.758:819](),[10.819][10.123:124](),[10.123][10.123:124](),[10.124][10.0:14](),[10.14][10.20:65](),[10.65][10.183:424](),[10.424][7.189:277](),[7.277][10.499:567](),[10.499][10.499:567](),[10.567][7.278:370](),[7.370][10.650:963](),[10.650][10.650:963]()
    if (drv->querySystem() == "unknown")
    throw EvalError("derivation must have a ‘system’ attribute");
    if (comma) { std::cout << ","; comma = false; }
    {
    auto res = top.object(attrPath);
    res.attr("nixName", drv->queryName());
    res.attr("system", drv->querySystem());
    res.attr("drvPath", drvPath = drv->queryDrvPath());
    res.attr("description", drv->queryMetaString("description"));
    res.attr("license", queryMetaStrings(state, *drv, "license", "shortName"));
    res.attr("homepage", drv->queryMetaString("homepage"));
    res.attr("maintainers", queryMetaStrings(state, *drv, "maintainers", "email"));
    res.attr("schedulingPriority", drv->queryMetaInt("schedulingPriority", 100));
    res.attr("timeout", drv->queryMetaInt("timeout", 36000));
    res.attr("maxSilent", drv->queryMetaInt("maxSilent", 7200));
    res.attr("isChannel", drv->queryMetaBool("isHydraChannel", false));
    [10.748]
    [10.259]
    PathSet context;
    state.coerceToString(*a->pos, *a->value, context, true, false);
    for (auto & i : context)
    if (i.at(0) == '!') {
    size_t index = i.find("!", 1);
    job["constituents"].push_back(string(i, index + 1));
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 155
    [10.1270][10.0:70](),[10.70][10.65:156](),[10.65][10.65:156](),[10.156][10.66:144](),[10.144][10.71:163](),[10.225][10.71:163](),[10.163][10.312:353](),[10.312][10.312:353](),[10.353][10.164:256](),[10.256][10.440:473](),[10.440][10.440:473](),[10.473][10.26:106](),[10.106][10.544:574](),[10.544][10.544:574](),[10.574][10.304:501]()
    /* If this is an aggregate, then get its constituents. */
    Bindings::iterator a = v.attrs->find(state.symbols.create("_hydraAggregate"));
    if (a != v.attrs->end() && state.forceBool(*a->value, *a->pos)) {
    Bindings::iterator a = v.attrs->find(state.symbols.create("constituents"));
    if (a == v.attrs->end())
    throw EvalError("derivation must have a ‘constituents’ attribute");
    PathSet context;
    state.coerceToString(*a->pos, *a->value, context, true, false);
    PathSet drvs;
    for (auto & i : context)
    if (i.at(0) == '!') {
    size_t index = i.find("!", 1);
    drvs.insert(string(i, index + 1));
    [10.260]
    [10.789]
    state.forceList(*a->value, *a->pos);
    for (unsigned int n = 0; n < a->value->listSize(); ++n) {
    auto v = a->value->listElems()[n];
    state.forceValue(*v);
    if (v->type == tString)
    job["namedConstituents"].push_back(state.forceStringNoCtx(*v));
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 162
    [10.811][10.1262:1333](),[10.329][10.878:892](),[10.1333][10.878:892](),[10.878][10.878:892]()
    res.attr("constituents", concatStringsSep(" ", drvs));
    }
    [10.811]
    [10.892]
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 164
    [10.893][10.126:278](),[10.1270][10.126:278](),[10.953][10.126:278](),[10.278][10.145:275](),[10.275][9.47:262](),[10.82][10.178:192](),[10.87][10.178:192](),[9.262][10.178:192](),[10.362][10.178:192](),[10.178][10.178:192](),[10.192][10.804:805](),[10.805][10.363:410](),[10.410][10.1405:1488](),[10.1405][10.1405:1488](),[10.1488][10.15:16](),[10.16][10.820:834]()
    /* Register the derivation as a GC root. !!! This
    registers roots for jobs that we may have already
    done. */
    auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>();
    if (gcRootsDir != "" && localStore) {
    Path root = gcRootsDir + "/" + std::string(baseNameOf(drvPath));
    if (!pathExists(root))
    localStore->addPermRoot(localStore->parseStorePath(drvPath), root, false);
    }
    auto res2 = res.object("outputs");
    for (auto & j : outputs)
    res2.attr(j.first, j.second);
    }
    [10.893]
    [10.834]
    /* Register the derivation as a GC root. !!! This
    registers roots for jobs that we may have already
    done. */
    auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>();
    if (gcRootsDir != "" && localStore) {
    Path root = gcRootsDir + "/" + std::string(baseNameOf(drvPath));
    if (!pathExists(root))
    localStore->addPermRoot(localStore->parseStorePath(drvPath), root, false);
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 174
    [10.835][10.835:915]()
    GC_prof_stats_s gc;
    GC_get_prof_stats(&gc, sizeof(gc));
    [10.835]
    [10.915]
    nlohmann::json out;
    for (auto & j : outputs)
    out[j.first] = j.second;
    job["outputs"] = std::move(out);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 179
    [10.916][10.916:1173]()
    if (gc.heapsize_full > maxHeapSize) {
    printInfo("restarting hydra-eval-jobs after job '%s' because heap size is at %d bytes", attrPath, gc.heapsize_full);
    lastAttrPath = attrPath;
    throw BailOut();
    [10.916]
    [10.16]
    reply["job"] = std::move(job);
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 181
    [10.64][10.1148:1158](),[10.419][10.1148:1158](),[10.1488][10.1148:1158](),[10.1863][10.1148:1158](),[10.1148][10.1148:1158]()
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 182
    [10.1159][10.1159:1174](),[10.1174][10.78:120](),[10.120][10.1174:1239]()
    else {
    if (!state.isDerivation(v)) {
    for (auto & i : v.attrs->lexicographicOrder()) {
    [10.1159]
    [10.1239]
    else if (v->type == tAttrs) {
    auto attrs = nlohmann::json::array();
    StringSet ss;
    for (auto & i : v->attrs->lexicographicOrder()) {
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 187
    [10.1286][10.1286:1409]()
    /* Skip jobs with dots in the name. */
    if (name.find('.') != std::string::npos) {
    [10.1286]
    [10.1409]
    if (name.find('.') != std::string::npos || name.find(' ') != std::string::npos) {
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 191
    [10.1546][10.1546:1683]()
    findJobs(state, top, autoArgs, *i->value,
    (attrPath.empty() ? "" : attrPath + ".") + name);
    [10.1546]
    [10.1683]
    attrs.push_back(name);
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 193
    [10.1701]
    [10.336]
    reply["attrs"] = std::move(attrs);
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 195
    [10.350]
    [10.1402]
    } catch (EvalError & e) {
    reply["error"] = filterANSIEscapes(e.msg(), true);
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 199
    [10.1412][10.1412:1418]()
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 200
    [10.7][2.0:32](),[2.32][10.38:89](),[10.38][10.38:89]()
    else if (v.type == tNull) {
    // allow null values, meaning 'do nothing'
    [10.1419]
    [10.1503]
    writeLine(to.get(), reply.dump());
    /* If our RSS exceeds the maximum, exit. The master will
    start a new process. */
    struct rusage r;
    getrusage(RUSAGE_SELF, &r);
    if ((size_t) r.ru_maxrss > maxMemorySize * 1024) break;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 209
    [10.2020][10.2020:2029](),[10.2029][10.2240:2303]()
    else
    throw TypeError(format("unsupported value: %1%") % v);
    [10.2020]
    [10.490]
    writeLine(to.get(), "restart");
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 211
    [10.492][10.492:494](),[10.494][10.1607:1665](),[10.1665][10.281:342](),[10.342][10.646:658](),[10.612][10.646:658](),[10.2402][10.646:658](),[10.646][10.646:658](),[10.658][10.343:403](),[10.403][10.0:30](),[10.673][10.0:30](),[10.1726][10.0:30](),[10.2473][10.0:30](),[10.728][10.0:30](),[10.30][10.1702:1758](),[10.1758][10.411:452](),[10.10][10.411:452](),[10.452][4.0:61](),[4.61][10.944:950](),[10.95][10.944:950](),[10.1849][10.944:950](),[10.944][10.944:950](),[10.950][10.541:544](),[10.1571][10.541:544](),[10.2102][10.541:544](),[10.541][10.541:544]()
    static void findJobs(EvalState & state, JSONObject & top,
    Bindings & autoArgs, Value & v, const string & attrPath)
    {
    try {
    findJobsWrapped(state, top, autoArgs, v, attrPath);
    } catch (EvalError & e) {
    if (comma) { std::cout << ","; comma = false; }
    auto res = top.object(attrPath);
    res.attr("error", filterANSIEscapes(e.msg(), true));
    }
    }
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 214
    [10.570][10.1759:2154]()
    assert(lte("abc", "def"));
    assert(lte("abc", "def.foo"));
    assert(!lte("def", "abc"));
    assert(lte("nixpkgs.hello", "nixpkgs"));
    assert(lte("nixpkgs.hello", "nixpkgs.hellooo"));
    assert(lte("gitAndTools.git-annex.x86_64-darwin", "gitAndTools.git-annex.x86_64-linux"));
    assert(lte("gitAndTools.git-annex.x86_64-linux", "gitAndTools.git-annex-remote-b2.aarch64-linux"));
  • edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 221
    [10.139][10.139:335]()
    auto initialHeapSize = config->getStrOption("evaluator_initial_heap_size", "");
    if (initialHeapSize != "")
    setenv("GC_INITIAL_HEAP_SIZE", initialHeapSize.c_str(), 1);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 222
    [10.336][10.2155:2237]()
    maxHeapSize = config->getIntOption("evaluator_max_heap_size", 1UL << 30);
    [10.336]
    [10.2237]
    auto nrWorkers = config->getIntOption("evaluator_workers", 1);
    maxMemorySize = config->getIntOption("evaluator_max_memory_size", 4096);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 228
    [8.1][8.1:199]()
    /* Read the current heap size, which is the initial heap size. */
    GC_prof_stats_s gc;
    GC_get_prof_stats(&gc, sizeof(gc));
    auto initialHeapSizeInt = gc.heapsize_full;
    [8.1]
    [8.199]
    myArgs.parseCmdline(argvToStrings(argc, argv));
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 230
    [8.200][8.200:634]()
    /* Then make sure the maximum heap size will be bigger than the initial heap size. */
    if (initialHeapSizeInt > maxHeapSize) {
    printInfo("warning: evaluator_initial_heap_size (%d) bigger than evaluator_max_heap_size (%d).", initialHeapSizeInt, maxHeapSize);
    maxHeapSize = initialHeapSizeInt * 1.1;
    printInfo(" evaluator_max_heap_size now set to %d.", maxHeapSize);
    }
    [8.200]
    [10.27]
    /* FIXME: The build hook in conjunction with import-from-derivation is causing "unexpected EOF" during eval */
    settings.builders = "";
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 233
    [10.128][10.128:154]()
    Path releaseExpr;
    [10.28]
    [10.199]
    /* Prevent access to paths outside of the Nix search path and
    to the environment. */
    evalSettings.restrictEval = true;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 237
    [10.200][10.404:452]()
    struct MyArgs : LegacyArgs, MixEvalArgs
    [10.200]
    [10.452]
    if (myArgs.dryRun) settings.readOnlyMode = true;
    if (myArgs.releaseExpr == "") throw UsageError("no expression specified");
    if (gcRootsDir == "") printMsg(lvlError, "warning: `--gc-roots-dir' not specified");
    struct State
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 245
    [10.462][10.462:504]()
    using LegacyArgs::LegacyArgs;
    [10.462]
    [10.504]
    std::set<std::string> todo{""};
    std::set<std::string> active;
    nlohmann::json jobs;
    std::exception_ptr exc;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 251
    [10.516][10.516:663](),[10.663][10.975:1028](),[10.975][10.975:1028](),[10.1028][10.23:111](),[10.111][10.1028:1112](),[10.1028][10.1028:1112](),[10.80][10.2631:2648](),[10.1112][10.2631:2648](),[10.1258][10.2631:2648](),[10.2631][10.2631:2648](),[10.2648][10.0:36](),[10.36][10.1158:1195](),[10.1158][10.1158:1195]()
    MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) {
    if (*arg == "--gc-roots-dir")
    gcRootsDir = getArg(*arg, arg, end);
    else if (*arg == "--dry-run")
    settings.readOnlyMode = true;
    else if (*arg != "" && arg->at(0) == '-')
    return false;
    else
    releaseExpr = *arg;
    return true;
    });
    [10.516]
    [10.664]
    std::condition_variable wakeup;
    Sync<State> state_;
    /* Start a handler thread per worker process. */
    auto handler = [&]()
    {
    try {
    pid_t pid = -1;
    AutoCloseFD from, to;
    while (true) {
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 264
    [10.665][10.665:721]()
    myArgs.parseCmdline(argvToStrings(argc, argv));
    [10.665]
    [10.0]
    /* Start a new worker process if necessary. */
    if (pid == -1) {
    Pipe toPipe, fromPipe;
    toPipe.create();
    fromPipe.create();
    pid = startProcess(
    [&,
    to{std::make_shared<AutoCloseFD>(std::move(fromPipe.writeSide))},
    from{std::make_shared<AutoCloseFD>(std::move(toPipe.readSide))}
    ]()
    {
    try {
    EvalState state(myArgs.searchPath, openStore());
    Bindings & autoArgs = *myArgs.getAutoArgs(state);
    worker(state, autoArgs, *to, *from);
    } catch (std::exception & e) {
    nlohmann::json err;
    err["error"] = e.what();
    writeLine(to->get(), err.dump());
    }
    },
    ProcessOptions { .allowVfork = false });
    from = std::move(fromPipe.readSide);
    to = std::move(toPipe.writeSide);
    debug("created worker process %d", pid);
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 291
    [10.1][10.2239:2308]()
    JSONObject json(std::cout, true);
    std::cout.flush();
    [10.1]
    [10.158]
    /* Check whether the existing worker process is still there. */
    auto s = readLine(from.get());
    if (s == "restart") {
    pid = -1;
    continue;
    } else if (s != "next") {
    auto json = nlohmann::json::parse(s);
    throw Error("worker error: %s", (std::string) json["error"]);
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 301
    [10.159][10.2309:2322]()
    do {
    [10.159]
    [10.2322]
    /* Wait for a job name to become available. */
    std::string attrPath;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 304
    [10.2323][10.2323:2373]()
    Pipe pipe;
    pipe.create();
    [10.2323]
    [10.854]
    while (true) {
    checkInterrupt();
    auto state(state_.lock());
    if ((state->todo.empty() && state->active.empty()) || state->exc) {
    writeLine(to.get(), "exit");
    return;
    }
    if (!state->todo.empty()) {
    attrPath = *state->todo.begin();
    state->todo.erase(state->todo.begin());
    state->active.insert(attrPath);
    break;
    } else
    state.wait(wakeup);
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 320
    [10.855][10.2374:2450]()
    ProcessOptions options;
    options.allowVfork = false;
    [10.855]
    [6.28]
    /* Tell the worker to evaluate it. */
    writeLine(to.get(), "do " + attrPath);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 323
    [6.29][6.29:62]()
    GC_atfork_prepare();
    [6.29]
    [10.808]
    /* Wait for the response. */
    auto response = nlohmann::json::parse(readLine(from.get()));
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 326
    [10.809][10.2451:2531]()
    auto pid = startProcess([&]() {
    pipe.readSide = -1;
    [10.809]
    [6.63]
    /* Handle the response. */
    StringSet newAttrs;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 329
    [6.64][6.64:140]()
    GC_atfork_child();
    GC_start_mark_threads();
    [6.64]
    [10.810]
    if (response.find("job") != response.end()) {
    auto state(state_.lock());
    state->jobs[attrPath] = response["job"];
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 334
    [10.811][10.2532:2615]()
    if (lastAttrPath != "") debug("resuming from '%s'", lastAttrPath);
    [10.811]
    [10.880]
    if (response.find("attrs") != response.end()) {
    for (auto & i : response["attrs"]) {
    auto s = (attrPath.empty() ? "" : attrPath + ".") + (std::string) i;
    newAttrs.insert(s);
    }
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 341
    [10.881][10.2616:2783]()
    /* FIXME: The build hook in conjunction with import-from-derivation is causing "unexpected EOF" during eval */
    settings.builders = "";
    [10.881]
    [10.1624]
    if (response.find("error") != response.end()) {
    auto state(state_.lock());
    state->jobs[attrPath]["error"] = response["error"];
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 346
    [10.1625][10.2784:2904](),[10.2904][3.0:50]()
    /* Prevent access to paths outside of the Nix search path and
    to the environment. */
    evalSettings.restrictEval = true;
    [10.1625]
    [10.1021]
    /* Add newly discovered job names to the queue. */
    {
    auto state(state_.lock());
    state->active.erase(attrPath);
    for (auto & s : newAttrs)
    state->todo.insert(s);
    wakeup.notify_all();
    }
    }
    } catch (...) {
    auto state(state_.lock());
    state->exc = std::current_exception();
    wakeup.notify_all();
    }
    };
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 362
    [10.1022][10.2955:3039]()
    if (releaseExpr == "") throw UsageError("no expression specified");
    [10.1022]
    [10.1022]
    std::vector<std::thread> threads;
    for (size_t i = 0; i < nrWorkers; i++)
    threads.emplace_back(std::thread(handler));
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 366
    [10.1023][10.3040:3141]()
    if (gcRootsDir == "") printMsg(lvlError, "warning: `--gc-roots-dir' not specified");
    [10.1023]
    [10.3141]
    for (auto & thread : threads)
    thread.join();
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 369
    [10.3142][10.3142:3207]()
    EvalState state(myArgs.searchPath, openStore());
    [10.3142]
    [10.3207]
    auto state(state_.lock());
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 371
    [10.3208][10.3208:3274]()
    Bindings & autoArgs = *myArgs.getAutoArgs(state);
    [10.3208]
    [10.3274]
    if (state->exc)
    std::rethrow_exception(state->exc);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 374
    [10.3275][10.3275:3370]()
    Value v;
    state.evalFile(lookupFileArg(state, releaseExpr), v);
    [10.3275]
    [10.3370]
    /* For aggregate jobs that have named consistuents
    (i.e. constituents that are a job name rather than a
    derivation), look up the referenced job and add it to the
    dependencies of the aggregate derivation. */
    auto store = openStore();
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 380
    [10.3371][10.3371:3415]()
    comma = lastAttrPath != "";
    [10.3371]
    [10.3415]
    for (auto i = state->jobs.begin(); i != state->jobs.end(); ++i) {
    auto jobName = i.key();
    auto & job = i.value();
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 384
    [10.3416][10.3416:3577]()
    try {
    findJobs(state, json, autoArgs, v, "");
    lastAttrPath = "";
    } catch (BailOut &) { }
    [10.3416]
    [10.3577]
    auto named = job.find("namedConstituents");
    if (named == job.end()) continue;
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 387
    [10.3578][10.3578:3641]()
    writeFull(pipe.writeSide.get(), lastAttrPath);
    [10.3578]
    [10.3641]
    if (myArgs.dryRun) {
    for (std::string jobName2 : *named) {
    auto job2 = state->jobs.find(jobName2);
    if (job2 == state->jobs.end())
    throw Error("aggregate job '%s' references non-existent job '%s'", jobName, jobName2);
    std::string drvPath2 = (*job2)["drvPath"];
    job["constituents"].push_back(drvPath2);
    }
    } else {
    std::string drvPath = job["drvPath"];
    auto drv = readDerivation(*store, drvPath);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 399
    [10.3642][10.3642:3692]()
    exit(0);
    }, options);
    [10.3642]
    [6.141]
    for (std::string jobName2 : *named) {
    auto job2 = state->jobs.find(jobName2);
    if (job2 == state->jobs.end())
    throw Error("aggregate job '%s' references non-existent job '%s'", jobName, jobName2);
    std::string drvPath2 = (*job2)["drvPath"];
    auto drv2 = readDerivation(*store, drvPath2);
    job["constituents"].push_back(drvPath2);
    drv.inputDrvs[store->parseStorePath(drvPath2)] = {drv2.outputs.begin()->first};
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 409
    [6.142][6.142:174]()
    GC_atfork_parent();
    [6.142]
    [10.3692]
    std::string drvName(store->parseStorePath(drvPath).name());
    assert(hasSuffix(drvName, drvExtension));
    drvName.resize(drvName.size() - drvExtension.size());
    auto h = hashDerivationModulo(*store, drv, true);
    auto outPath = store->makeOutputPath("out", h, drvName);
    drv.env["out"] = store->printStorePath(outPath);
    drv.outputs.insert_or_assign("out", DerivationOutput(outPath.clone(), "", ""));
    auto newDrvPath = store->printStorePath(writeDerivation(store, drv, drvName));
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 418
    [10.3693][10.3693:3726]()
    pipe.writeSide = -1;
    [10.3693]
    [10.3726]
    debug("rewrote aggregate derivation %s -> %s", drvPath, newDrvPath);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 420
    [10.3727][10.3727:3918]()
    int status;
    while (true) {
    checkInterrupt();
    if (waitpid(pid, &status, 0) == pid) break;
    if (errno != EINTR) continue;
    [10.3727]
    [10.3918]
    job["drvPath"] = newDrvPath;
    job["outputs"]["out"] = store->printStorePath(outPath);
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 424
    [10.3933][10.3933:4036]()
    if (status != 0)
    throw Exit(WIFEXITED(status) ? WEXITSTATUS(status) : 99);
    [10.3933]
    [10.115]
    job.erase("namedConstituents");
    }
  • replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 427
    [10.116][5.0:45](),[5.45][10.4036:4132](),[10.161][10.4036:4132](),[10.4036][10.4036:4132]()
    maxHeapSize += 64 * 1024 * 1024;
    lastAttrPath = drainFD(pipe.readSide.get());
    } while (lastAttrPath != "");
    [10.116]
    [10.2155]
    std::cout << state->jobs.dump(2) << "\n";