Tracing primops

Tracing the primops with Tracy as well. Not sure it really worth the
overhead, but we still can revisit this decision later if we realize
primops are not that important perf-wise.
This commit is contained in:
Félix Baylac Jacqué 2024-02-07 11:27:36 +01:00
parent b35cc131af
commit 376d9dd520
3 changed files with 107 additions and 3 deletions

View File

@ -57,12 +57,12 @@
#define TRACY_TRACE(evalstate, expr) \
std::ostringstream tracyss; \
tracyss << evalstate.positions[(expr)->getPos()] << " " << (expr)->showExprType(); \
tracyss << (evalstate).positions[(expr)->getPos()] << " " << (expr)->showExprType(); \
ZoneTransientN(nix, tracyss.str().c_str(), true);
#define TRACY_TRACE_TYPE_STR(evalstate, expr, typestr) \
std::ostringstream tracyss; \
tracyss << (evalstate).positions[(expr)->getPos()] << " " << typestr; \
tracyss << (evalstate).positions[(expr)->getPos()] << " " << typestr; \
ZoneTransientN(nix, tracyss.str().c_str(), true);
using json = nlohmann::json;
@ -81,7 +81,6 @@ static char * allocString(size_t size)
return t;
}
static char * dupString(const char * s)
{
char * t;

View File

@ -21,6 +21,12 @@ libexpr_LDFLAGS += -lboost_context $(THREAD_LDFLAGS)
ifdef HOST_LINUX
libexpr_LDFLAGS += -ldl
endif
ifneq ($(TRACY_PROFILER), no)
libexpr_LDFLAGS += -ltracy
# We have to set TRACY_ENABLE to have tracy actually send the trace
# events, it's no-op without them.
libexpr_CXXFLAGS += -DTRACY_ENABLE=1
endif
# The dependency on libgc must be propagated (i.e. meaning that
# programs/libraries that use libexpr must explicitly pass -lgc),

View File

@ -32,6 +32,13 @@
#include <cmath>
#include <tracy/Tracy.hpp>
#define TRACY_TRACE_PRIMOP(es, posidx, typestr) \
std::ostringstream tracyss; \
tracyss << es.positions[posidx] << " " << typestr; \
ZoneTransientN(nix, tracyss.str().c_str(), true);
namespace nix {
@ -120,6 +127,7 @@ StringMap EvalState::realiseContext(const NixStringContext & context)
static SourcePath realisePath(EvalState & state, const PosIdx pos, Value & v, bool resolveSymlinks = true)
{
TRACY_TRACE_PRIMOP(state, pos, "realizePath");
NixStringContext context;
auto path = state.coerceToPath(noPos, v, context, "while realising the context of a path");
@ -170,6 +178,7 @@ static void mkOutputString(
argument. */
static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * vScope, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.import");
auto path = realisePath(state, pos, vPath, false);
auto path2 = path.path.abs();
@ -334,6 +343,7 @@ extern "C" typedef void (*ValueInitializer)(EvalState & state, Value & v);
/* Load a ValueInitializer from a DSO and return whatever it initializes */
void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.importNative");
auto path = realisePath(state, pos, *args[0]);
std::string sym(state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.importNative"));
@ -361,6 +371,7 @@ void prim_importNative(EvalState & state, const PosIdx pos, Value * * args, Valu
/* Execute a program and parse its output */
void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.exec");
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.exec");
auto elems = args[0]->listElems();
auto count = args[0]->listSize();
@ -402,6 +413,7 @@ void prim_exec(EvalState & state, const PosIdx pos, Value * * args, Value & v)
/* Return a string representing the type of the expression. */
static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.typeOf");
state.forceValue(*args[0], pos);
std::string t;
switch (args[0]->type()) {
@ -436,6 +448,7 @@ static RegisterPrimOp primop_typeOf({
/* Determine whether the argument is the null value. */
static void prim_isNull(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isNull");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nNull);
}
@ -454,6 +467,7 @@ static RegisterPrimOp primop_isNull({
/* Determine whether the argument is a function. */
static void prim_isFunction(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isFunction");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nFunction);
}
@ -470,6 +484,7 @@ static RegisterPrimOp primop_isFunction({
/* Determine whether the argument is an integer. */
static void prim_isInt(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isInt");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nInt);
}
@ -486,6 +501,7 @@ static RegisterPrimOp primop_isInt({
/* Determine whether the argument is a float. */
static void prim_isFloat(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isFloat");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nFloat);
}
@ -502,6 +518,7 @@ static RegisterPrimOp primop_isFloat({
/* Determine whether the argument is a string. */
static void prim_isString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isString");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nString);
}
@ -518,6 +535,7 @@ static RegisterPrimOp primop_isString({
/* Determine whether the argument is a Boolean. */
static void prim_isBool(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isBool");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nBool);
}
@ -534,6 +552,7 @@ static RegisterPrimOp primop_isBool({
/* Determine whether the argument is a path. */
static void prim_isPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isPath");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nPath);
}
@ -644,6 +663,7 @@ static Bindings::iterator getAttr(
static void prim_genericClosure(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.genericClosure");
state.forceAttrs(*args[0], noPos, "while evaluating the first argument passed to builtins.genericClosure");
/* Get the start set. */
@ -754,6 +774,7 @@ static RegisterPrimOp primop_break({
)",
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.break");
if (state.debugRepl && !state.debugTraces.empty()) {
auto error = Error(ErrorInfo {
.level = lvlInfo,
@ -787,6 +808,7 @@ static RegisterPrimOp primop_abort({
)",
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.abort");
NixStringContext context;
auto s = state.coerceToString(pos, *args[0], context,
"while evaluating the error message passed to builtins.abort").toOwned();
@ -806,6 +828,7 @@ static RegisterPrimOp primop_throw({
)",
.fun = [](EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.throw");
NixStringContext context;
auto s = state.coerceToString(pos, *args[0], context,
"while evaluating the error message passed to builtin.throw").toOwned();
@ -815,6 +838,7 @@ static RegisterPrimOp primop_throw({
static void prim_addErrorContext(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.addErrorContext");
try {
state.forceValue(*args[1], pos);
v = *args[1];
@ -836,6 +860,7 @@ static RegisterPrimOp primop_addErrorContext(PrimOp {
static void prim_ceil(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.ceil");
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos),
"while evaluating the first argument passed to builtins.ceil");
v.mkInt(ceil(value));
@ -856,6 +881,7 @@ static RegisterPrimOp primop_ceil({
static void prim_floor(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.floor");
auto value = state.forceFloat(*args[0], args[0]->determinePos(pos), "while evaluating the first argument passed to builtins.floor");
v.mkInt(floor(value));
}
@ -877,6 +903,7 @@ static RegisterPrimOp primop_floor({
* else => {success=false; value=false;} */
static void prim_tryEval(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.tryEval");
auto attrs = state.buildBindings(2);
/* increment state.trylevel, and decrement it when this function returns. */
@ -930,6 +957,7 @@ static RegisterPrimOp primop_tryEval({
/* Return an environment variable. Use with care. */
static void prim_getEnv(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.getEnv");
std::string name(state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getEnv"));
v.mkString(evalSettings.restrictEval || evalSettings.pureEval ? "" : getEnv(name).value_or(""));
}
@ -954,6 +982,7 @@ static RegisterPrimOp primop_getEnv({
/* Evaluate the first argument, then return the second argument. */
static void prim_seq(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.seq");
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
v = *args[1];
@ -973,6 +1002,7 @@ static RegisterPrimOp primop_seq({
attrsets), then return the second argument. */
static void prim_deepSeq(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.deepSeq");
state.forceValueDeep(*args[0]);
state.forceValue(*args[1], pos);
v = *args[1];
@ -993,6 +1023,7 @@ static RegisterPrimOp primop_deepSeq({
return the second expression. Useful for debugging. */
static void prim_trace(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.trace");
state.forceValue(*args[0], pos);
if (args[0]->type() == nString)
printError("trace: %1%", args[0]->string_view());
@ -1019,6 +1050,7 @@ static RegisterPrimOp primop_trace({
*/
static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.second");
state.forceValue(*args[1], pos);
v = *args[1];
}
@ -1038,6 +1070,7 @@ static void derivationStrictInternal(EvalState & state, const std::string & name
derivation. */
static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.derivationStrict");
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.derivationStrict");
Bindings * attrs = args[0]->attrs;
@ -1436,6 +1469,7 @@ static RegisterPrimOp primop_derivationStrict(PrimOp {
out. */
static void prim_placeholder(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.placeholder");
v.mkString(hashPlaceholder(state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.placeholder")));
}
@ -1459,6 +1493,7 @@ static RegisterPrimOp primop_placeholder({
/* Convert the argument to a path. !!! obsolete? */
static void prim_toPath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.toPath");
NixStringContext context;
auto path = state.coerceToPath(pos, *args[0], context, "while evaluating the first argument passed to builtins.toPath");
v.mkString(path.path.abs(), context);
@ -1484,6 +1519,7 @@ static RegisterPrimOp primop_toPath({
corner cases. */
static void prim_storePath(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.storePath");
if (evalSettings.pureEval)
state.debugThrowLastTrace(EvalError({
.msg = hintfmt("'%s' is not allowed in pure evaluation mode", "builtins.storePath"),
@ -1531,6 +1567,7 @@ static RegisterPrimOp primop_storePath({
static void prim_pathExists(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.pathExists");
try {
auto & arg = *args[0];
@ -1563,6 +1600,7 @@ static RegisterPrimOp primop_pathExists({
following the last slash. */
static void prim_baseNameOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.baseNameOf");
NixStringContext context;
v.mkString(baseNameOf(*state.coerceToString(pos, *args[0], context,
"while evaluating the first argument passed to builtins.baseNameOf",
@ -1585,6 +1623,7 @@ static RegisterPrimOp primop_baseNameOf({
of the argument. */
static void prim_dirOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.dirOf");
state.forceValue(*args[0], pos);
if (args[0]->type() == nPath) {
auto path = args[0]->path();
@ -1613,6 +1652,7 @@ static RegisterPrimOp primop_dirOf({
/* Return the contents of a file as a string. */
static void prim_readFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.readFile");
auto path = realisePath(state, pos, *args[0]);
auto s = path.readFile();
if (s.find((char) 0) != std::string::npos)
@ -1650,6 +1690,7 @@ static RegisterPrimOp primop_readFile({
which are desugared to 'findFile __nixPath "x"'. */
static void prim_findFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.findFile");
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.findFile");
SearchPath searchPath;
@ -1742,6 +1783,7 @@ static RegisterPrimOp primop_findFile(PrimOp {
/* Return the cryptographic hash of a file in base-16. */
static void prim_hashFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.hashFile");
auto algo = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hashFile");
std::optional<HashAlgorithm> ha = parseHashAlgo(algo);
if (!ha)
@ -1777,6 +1819,7 @@ static std::string_view fileTypeToString(InputAccessor::Type type)
static void prim_readFileType(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.readFileType");
auto path = realisePath(state, pos, *args[0], false);
/* Retrieve the directory entry type and stringize it. */
v.mkString(fileTypeToString(path.lstat().type));
@ -1795,6 +1838,7 @@ static RegisterPrimOp primop_readFileType({
/* Read a directory (without . or ..) */
static void prim_readDir(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.readDir");
auto path = realisePath(state, pos, *args[0]);
// Retrieve directory entries for all nodes in a directory.
@ -1852,6 +1896,7 @@ static RegisterPrimOp primop_readDir({
/* Extend single element string context with another output. */
static void prim_outputOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.outputOf");
SingleDerivedPath drvPath = state.coerceToSingleDerivedPath(pos, *args[0], "while evaluating the first argument to builtins.outputOf");
OutputNameView outputName = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument to builtins.outputOf");
@ -1899,6 +1944,7 @@ static RegisterPrimOp primop_outputOf({
be sensibly or completely represented (e.g., functions). */
static void prim_toXML(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.toXML");
std::ostringstream out;
NixStringContext context;
printValueAsXML(state, true, false, *args[0], out, context, pos);
@ -2007,6 +2053,7 @@ static RegisterPrimOp primop_toXML({
represented (e.g., functions). */
static void prim_toJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.toJSON");
std::ostringstream out;
NixStringContext context;
printValueAsJSON(state, true, *args[0], pos, out, context);
@ -2030,6 +2077,7 @@ static RegisterPrimOp primop_toJSON({
/* Parse a JSON string to a value. */
static void prim_fromJSON(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.fromJSON");
auto s = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.fromJSON");
try {
parseJSON(state, s, v);
@ -2058,6 +2106,7 @@ static RegisterPrimOp primop_fromJSON({
as an input by derivations. */
static void prim_toFile(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.toFile");
NixStringContext context;
std::string name(state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.toFile"));
std::string contents(state.forceString(*args[1], context, pos, "while evaluating the second argument passed to builtins.toFile"));
@ -2207,6 +2256,7 @@ static void addPath(
Value & v,
const NixStringContext & context)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.addPath");
try {
StorePathSet refs;
@ -2256,6 +2306,7 @@ static void addPath(
static void prim_filterSource(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.filterSource");
NixStringContext context;
auto path = state.coerceToPath(pos, *args[1], context,
"while evaluating the second argument (the path to filter) passed to 'builtins.filterSource'");
@ -2321,6 +2372,7 @@ static RegisterPrimOp primop_filterSource({
static void prim_path(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.path");
std::optional<SourcePath> path;
std::string name;
Value * filterFun = nullptr;
@ -2404,6 +2456,7 @@ static RegisterPrimOp primop_path({
strings. */
static void prim_attrNames(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.attrNames");
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrNames");
state.mkList(v, args[0]->attrs->size());
@ -2431,6 +2484,7 @@ static RegisterPrimOp primop_attrNames({
order as attrNames. */
static void prim_attrValues(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.attrValues");
state.forceAttrs(*args[0], pos, "while evaluating the argument passed to builtins.attrValues");
state.mkList(v, args[0]->attrs->size());
@ -2463,6 +2517,7 @@ static RegisterPrimOp primop_attrValues({
/* Dynamic version of the `.' operator. */
void prim_getAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.getAttr");
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.getAttr");
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.getAttr");
Bindings::iterator i = getAttr(
@ -2492,6 +2547,7 @@ static RegisterPrimOp primop_getAttr({
/* Return position information of the specified attribute. */
static void prim_unsafeGetAttrPos(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.unsafeGetAttrPos");
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.unsafeGetAttrPos");
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.unsafeGetAttrPos");
Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
@ -2510,6 +2566,7 @@ static RegisterPrimOp primop_unsafeGetAttrPos(PrimOp {
/* Dynamic version of the `?' operator. */
static void prim_hasAttr(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.hasAttr");
auto attr = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hasAttr");
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.hasAttr");
v.mkBool(args[1]->attrs->find(state.symbols.create(attr)) != args[1]->attrs->end());
@ -2544,6 +2601,7 @@ static RegisterPrimOp primop_isAttrs({
static void prim_removeAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.removeAttrs");
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.removeAttrs");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.removeAttrs");
@ -2593,6 +2651,7 @@ static RegisterPrimOp primop_removeAttrs({
name, the first takes precedence. */
static void prim_listToAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.listToAttrs");
state.forceList(*args[0], pos, "while evaluating the argument passed to builtins.listToAttrs");
auto attrs = state.buildBindings(args[0]->listSize());
@ -2649,6 +2708,7 @@ static RegisterPrimOp primop_listToAttrs({
static void prim_intersectAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.intersectAttrs");
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.intersectAttrs");
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.intersectAttrs");
@ -2727,6 +2787,7 @@ static RegisterPrimOp primop_intersectAttrs({
static void prim_catAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.catAttrs");
auto attrName = state.symbols.create(state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.catAttrs"));
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.catAttrs");
@ -2764,6 +2825,7 @@ static RegisterPrimOp primop_catAttrs({
static void prim_functionArgs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.functionArgs");
state.forceValue(*args[0], pos);
if (args[0]->isPrimOpApp() || args[0]->isPrimOp()) {
v.mkAttrs(&state.emptyBindings);
@ -2807,6 +2869,7 @@ static RegisterPrimOp primop_functionArgs({
/* */
static void prim_mapAttrs(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.mapAttrs");
state.forceAttrs(*args[1], pos, "while evaluating the second argument passed to builtins.mapAttrs");
auto attrs = state.buildBindings(args[1]->attrs->size());
@ -2839,6 +2902,7 @@ static RegisterPrimOp primop_mapAttrs({
static void prim_zipAttrsWith(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.zipAttrsWith");
// we will first count how many values are present for each given key.
// we then allocate a single attrset and pre-populate it with lists of
// appropriate sizes, stash the pointers to the list elements of each,
@ -2926,6 +2990,7 @@ static RegisterPrimOp primop_zipAttrsWith({
/* Determine whether the argument is a list. */
static void prim_isList(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.isList");
state.forceValue(*args[0], pos);
v.mkBool(args[0]->type() == nList);
}
@ -2954,6 +3019,7 @@ static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Val
/* Return the n-1'th element of a list. */
static void prim_elemAt(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.elemAt");
elemAt(state, pos, *args[0], state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.elemAt"), v);
}
@ -2970,6 +3036,7 @@ static RegisterPrimOp primop_elemAt({
/* Return the first element of a list. */
static void prim_head(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.head");
elemAt(state, pos, *args[0], 0, v);
}
@ -2989,6 +3056,7 @@ static RegisterPrimOp primop_head({
don't want to use it! */
static void prim_tail(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.tail");
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.tail");
if (args[0]->listSize() == 0)
state.debugThrowLastTrace(Error({
@ -3020,6 +3088,7 @@ static RegisterPrimOp primop_tail({
/* Apply a function to every element of a list. */
static void prim_map(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.map");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.map");
if (args[1]->listSize() == 0) {
@ -3056,6 +3125,7 @@ static RegisterPrimOp primop_map({
returns true. */
static void prim_filter(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.filter");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.filter");
if (args[1]->listSize() == 0) {
@ -3099,6 +3169,7 @@ static RegisterPrimOp primop_filter({
/* Return true if a list contains a given element. */
static void prim_elem(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.elem");
bool res = false;
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.elem");
for (auto elem : args[1]->listItems())
@ -3122,6 +3193,7 @@ static RegisterPrimOp primop_elem({
/* Concatenate a list of lists. */
static void prim_concatLists(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.concatLists");
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.concatLists");
state.concatLists(v, args[0]->listSize(), args[0]->listElems(), pos, "while evaluating a value of the list passed to builtins.concatLists");
}
@ -3138,6 +3210,7 @@ static RegisterPrimOp primop_concatLists({
/* Return the length of a list. This is an O(1) time operation. */
static void prim_length(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.length");
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.length");
v.mkInt(args[0]->listSize());
}
@ -3155,6 +3228,7 @@ static RegisterPrimOp primop_length({
right. The operator is applied strictly. */
static void prim_foldlStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.foldStrict");
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.foldlStrict");
state.forceList(*args[2], pos, "while evaluating the third argument passed to builtins.foldlStrict");
@ -3218,6 +3292,7 @@ static void anyOrAll(bool any, EvalState & state, const PosIdx pos, Value * * ar
static void prim_any(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.any");
anyOrAll(true, state, pos, args, v);
}
@ -3233,6 +3308,7 @@ static RegisterPrimOp primop_any({
static void prim_all(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.all");
anyOrAll(false, state, pos, args, v);
}
@ -3248,6 +3324,7 @@ static RegisterPrimOp primop_all({
static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.genList");
auto len = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.genList");
if (len < 0)
@ -3286,6 +3363,7 @@ static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, V
static void prim_sort(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.sort");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.sort");
auto len = args[1]->listSize();
@ -3345,6 +3423,7 @@ static RegisterPrimOp primop_sort({
static void prim_partition(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.partition");
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.partition");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.partition");
@ -3405,6 +3484,7 @@ static RegisterPrimOp primop_partition({
static void prim_groupBy(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.groupBy");
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.groupBy");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.groupBy");
@ -3457,6 +3537,7 @@ static RegisterPrimOp primop_groupBy({
static void prim_concatMap(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.concatMap");
state.forceFunction(*args[0], pos, "while evaluating the first argument passed to builtins.concatMap");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.concatMap");
auto nrLists = args[1]->listSize();
@ -3500,6 +3581,7 @@ static RegisterPrimOp primop_concatMap({
static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.add");
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
@ -3521,6 +3603,7 @@ static RegisterPrimOp primop_add({
static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.sub");
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
@ -3542,6 +3625,7 @@ static RegisterPrimOp primop_sub({
static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.mul");
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
@ -3563,6 +3647,7 @@ static RegisterPrimOp primop_mul({
static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.div");
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
@ -3600,6 +3685,7 @@ static RegisterPrimOp primop_div({
static void prim_bitAnd(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.bitAnd");
v.mkInt(state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitAnd")
& state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitAnd"));
}
@ -3645,6 +3731,7 @@ static RegisterPrimOp primop_bitXor({
static void prim_lessThan(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.lessThan");
state.forceValue(*args[0], pos);
state.forceValue(*args[1], pos);
// pos is exact here, no need for a message.
@ -3674,6 +3761,7 @@ static RegisterPrimOp primop_lessThan({
`"/nix/store/whatever..."'. */
static void prim_toString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.toString");
NixStringContext context;
auto s = state.coerceToString(pos, *args[0], context,
"while evaluating the first argument passed to builtins.toString",
@ -3711,6 +3799,7 @@ static RegisterPrimOp primop_toString({
non-negative. */
static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.substring");
int start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring");
if (start < 0)
@ -3761,6 +3850,7 @@ static RegisterPrimOp primop_substring({
static void prim_stringLength(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.stringLength");
NixStringContext context;
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.stringLength");
v.mkInt(s->size());
@ -3779,6 +3869,7 @@ static RegisterPrimOp primop_stringLength({
/* Return the cryptographic hash of a string in base-16. */
static void prim_hashString(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.hashString");
auto algo = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.hashString");
std::optional<HashAlgorithm> ha = parseHashAlgo(algo);
if (!ha)
@ -3806,6 +3897,7 @@ static RegisterPrimOp primop_hashString({
static void prim_convertHash(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.convertHash");
state.forceAttrs(*args[0], pos, "while evaluating the first argument passed to builtins.convertHash");
auto &inputAttrs = args[0]->attrs;
@ -3923,6 +4015,7 @@ std::shared_ptr<RegexCache> makeRegexCache()
void prim_match(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.match");
auto re = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.match");
try {
@ -4003,6 +4096,7 @@ static RegisterPrimOp primop_match({
non-matching parts interleaved by the lists of the matching groups. */
void prim_split(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.split");
auto re = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.split");
try {
@ -4106,6 +4200,7 @@ static RegisterPrimOp primop_split({
static void prim_concatStringsSep(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.concatStringsSep");
NixStringContext context;
auto sep = state.forceString(*args[0], context, pos, "while evaluating the first argument (the separator string) passed to builtins.concatStringsSep");
@ -4136,6 +4231,7 @@ static RegisterPrimOp primop_concatStringsSep({
static void prim_replaceStrings(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.replaceStrings");
state.forceList(*args[0], pos, "while evaluating the first argument passed to builtins.replaceStrings");
state.forceList(*args[1], pos, "while evaluating the second argument passed to builtins.replaceStrings");
if (args[0]->listSize() != args[1]->listSize())
@ -4218,6 +4314,7 @@ static RegisterPrimOp primop_replaceStrings({
static void prim_parseDrvName(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.parseDrvName");
auto name = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.parseDrvName");
DrvName parsed(name);
auto attrs = state.buildBindings(2);
@ -4242,6 +4339,7 @@ static RegisterPrimOp primop_parseDrvName({
static void prim_compareVersions(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.compareVersions");
auto version1 = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.compareVersions");
auto version2 = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.compareVersions");
v.mkInt(compareVersions(version1, version2));
@ -4262,6 +4360,7 @@ static RegisterPrimOp primop_compareVersions({
static void prim_splitVersion(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
TRACY_TRACE_PRIMOP(state, pos, "primop.splitVersion");
auto version = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.splitVersion");
auto iter = version.cbegin();
Strings components;