1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-25 06:31:14 +02:00

encode black holes as tApp values

checking for isBlackhole in the forceValue hot path is rather more
expensive than necessary, and with a little bit of trickery we can move
such handling into the isApp case. small performance benefit, but under
some circumstances we've seen 2% improvement as well.

〉 nix eval --raw --impure --expr 'with import <nixpkgs/nixos> {}; system'

before:

  Time (mean ± σ):      4.429 s ±  0.002 s    [User: 3.929 s, System: 0.500 s]
  Range (min … max):    4.427 s …  4.433 s    10 runs

after:

  Time (mean ± σ):      4.396 s ±  0.002 s    [User: 3.894 s, System: 0.501 s]
  Range (min … max):    4.393 s …  4.399 s    10 runs
This commit is contained in:
pennae 2023-12-10 08:24:45 +01:00
parent 0218e4e6c3
commit 78353deb02
7 changed files with 93 additions and 32 deletions

View file

@ -162,7 +162,17 @@ void Value::print(const SymbolTable &symbols, std::ostream &str,
break;
case tThunk:
case tApp:
str << "<CODE>";
if (!isBlackhole()) {
str << "<CODE>";
} else {
// Although we know for sure that it's going to be an infinite recursion
// when this value is accessed _in the current context_, it's likely
// that the user will misinterpret a simpler «infinite recursion» output
// as a definitive statement about the value, while in fact it may be
// a valid value after `builtins.trace` and perhaps some other steps
// have completed.
str << "«potential infinite recursion»";
}
break;
case tLambda:
str << "<LAMBDA>";
@ -179,15 +189,6 @@ void Value::print(const SymbolTable &symbols, std::ostream &str,
case tFloat:
str << fpoint;
break;
case tBlackhole:
// Although we know for sure that it's going to be an infinite recursion
// when this value is accessed _in the current context_, it's likely
// that the user will misinterpret a simpler «infinite recursion» output
// as a definitive statement about the value, while in fact it may be
// a valid value after `builtins.trace` and perhaps some other steps
// have completed.
str << "«potential infinite recursion»";
break;
default:
printError("Nix evaluator internal error: Value::print(): invalid value type %1%", internalType);
abort();
@ -256,8 +257,7 @@ std::string showType(const Value & v)
return fmt("the partially applied built-in function '%s'", std::string(getPrimOp(v)->primOp->name));
case tExternal: return v.external->showType();
case tThunk: return "a thunk";
case tApp: return "a function application";
case tBlackhole: return "a black hole";
case tApp: return v.isBlackhole() ? "a black hole" : "a function application";
default:
return std::string(showType(v.type()));
}
@ -1621,15 +1621,17 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
return;
} else {
/* We have all the arguments, so call the primop. */
auto name = vCur.primOp->name;
auto * fn = vCur.primOp;
nrPrimOpCalls++;
if (countCalls) primOpCalls[name]++;
// This will count black holes, but that's ok, because unrecoverable errors are rare.
if (countCalls) primOpCalls[fn->name]++;
try {
vCur.primOp->fun(*this, vCur.determinePos(noPos), args, vCur);
fn->fun(*this, vCur.determinePos(noPos), args, vCur);
} catch (Error & e) {
addErrorTrace(e, pos, "while calling the '%1%' builtin", name);
if (!fn->hideInDiagnostics)
addErrorTrace(e, pos, "while calling the '%1%' builtin", fn->name);
throw;
}
@ -1666,18 +1668,20 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
for (size_t i = 0; i < argsLeft; ++i)
vArgs[argsDone + i] = args[i];
auto name = primOp->primOp->name;
auto fn = primOp->primOp;
nrPrimOpCalls++;
if (countCalls) primOpCalls[name]++;
// This will count black holes, but that's ok, because unrecoverable errors are rare.
if (countCalls) primOpCalls[fn->name]++;
try {
// TODO:
// 1. Unify this and above code. Heavily redundant.
// 2. Create a fake env (arg1, arg2, etc.) and a fake expr (arg1: arg2: etc: builtins.name arg1 arg2 etc)
// so the debugger allows to inspect the wrong parameters passed to the builtin.
primOp->primOp->fun(*this, vCur.determinePos(noPos), vArgs, vCur);
fn->fun(*this, vCur.determinePos(noPos), vArgs, vCur);
} catch (Error & e) {
addErrorTrace(e, pos, "while calling the '%1%' builtin", name);
if (!fn->hideInDiagnostics)
addErrorTrace(e, pos, "while calling the '%1%' builtin", fn->name);
throw;
}