aboutsummaryrefslogtreecommitdiff
path: root/src/libexpr/attr-set.hh
AgeCommit message (Collapse)Author
2022-04-26Don't pass Symbol by referenceEelco Dolstra
Since Symbol is just an integer, passing it by const reference is never advantageous.
2022-04-25rename SymbolIdx -> Symbol, Symbol -> SymbolStrpennae
after #6218 `Symbol` no longer confers a uniqueness invariant on the string it wraps, it is now possible to create multiple symbols that compare equal but whose string contents have different addresses. this guarantee is now only provided by `SymbolIdx`, leaving `Symbol` only as a string wrapper that knows about the intricacies of how symbols need to be formatted for output. this change renames `SymbolIdx` to `Symbol` to restore the previous semantics of `Symbol` to that name. we also keep the wrapper type and rename it to `SymbolStr` instead of returning plain strings from lookups into the symbol table because symbols are formatted for output in many places. theoretically we do not need `SymbolStr`, only a function that formats a string for output as a symbol, but having to wrap every symbol that appears in a message into eg `formatSymbol()` is error-prone and inconvient.
2022-04-21shrink Attr by 8 bytes on 64bit machinespennae
with position and symbol tables in place we can now shrink Attr by a full pointer with some simple field reordering. since Attr is a very hot struct this has substantial impact on memory use, decreasing GC allocations and heap size by 10-15% each. we also get a ~15% performance improvement due to reduced GC loading. pure parsing has taken a hit over the branch base because positions are now slightly more expensive to create, but overall we get a noticeable improvement. before (on memory-friendliness): Benchmark 1: nix search --no-eval-cache --offline ../nixpkgs hello Time (mean ± σ): 6.960 s ± 0.028 s [User: 5.832 s, System: 0.897 s] Range (min … max): 6.886 s … 7.005 s 20 runs Benchmark 2: nix eval -f ../nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix Time (mean ± σ): 328.1 ms ± 1.7 ms [User: 295.8 ms, System: 32.2 ms] Range (min … max): 324.9 ms … 331.2 ms 20 runs Benchmark 3: nix eval --raw --impure --expr 'with import <nixpkgs/nixos> {}; system' Time (mean ± σ): 2.688 s ± 0.029 s [User: 2.365 s, System: 0.238 s] Range (min … max): 2.642 s … 2.742 s 20 runs after: Benchmark 1: nix search --no-eval-cache --offline ../nixpkgs hello Time (mean ± σ): 6.902 s ± 0.039 s [User: 5.844 s, System: 0.783 s] Range (min … max): 6.820 s … 6.956 s 20 runs Benchmark 2: nix eval -f ../nixpkgs/pkgs/development/haskell-modules/hackage-packages.nix Time (mean ± σ): 330.7 ms ± 2.2 ms [User: 300.6 ms, System: 30.0 ms] Range (min … max): 327.5 ms … 334.5 ms 20 runs Benchmark 3: nix eval --raw --impure --expr 'with import <nixpkgs/nixos> {}; system' Time (mean ± σ): 2.330 s ± 0.027 s [User: 2.040 s, System: 0.234 s] Range (min … max): 2.272 s … 2.383 s 20 runs
2022-04-21store Symbols in a table as well, like positionspennae
this slightly increases the amount of memory used for any given symbol, but this increase is more than made up for if the symbol is referenced more than once in the EvalState that holds it. on average every symbol should be referenced at least twice (once to introduce a binding, once to use it), so we expect no increase in memory on average. symbol tables are limited to 2³² entries like position tables, and similar arguments apply to why overflow is not likely: 2³² symbols would require as many string instances (at 24 bytes each) and map entries (at 24 bytes or more each, assuming that the map holds on average at most one item per bucket as the docs say). a full symbol table would require at least 192GB of memory just for symbols, which is well out of reach. (an ofborg eval of nixpks today creates less than a million symbols!)
2022-04-21replace most Pos objects/ptrs with indexes into a position tablepennae
Pos objects are somewhat wasteful as they duplicate the origin file name and input type for each object. on files that produce more than one Pos when parsed this a sizeable waste of memory (one pointer per Pos). the same goes for ptr<Pos> on 64 bit machines: parsing enough source to require 8 bytes to locate a position would need at least 8GB of input and 64GB of expression memory. it's not likely that we'll hit that any time soon, so we can use a uint32_t index to locate positions instead.
2022-04-21remove Bindings::needpennae
a future commit will remove the ability to convert the symbol type used in bindings to strings. since we only have two users we can inline the error check.
2022-02-25Remove std::string alias (for real this time)Eelco Dolstra
Also use std::string_view in a few more places.
2022-01-14optimize removeAttrs builtinpennae
use a sorted array of symbols to be removed instead of a set. this saves a lot of memory allocations and slightly speeds up removal.
2022-01-04Remove EvalState::mkAttrs()Eelco Dolstra
2022-01-04Ensure that attrsets are sortedEelco Dolstra
Previously you had to remember to call value->attrs->sort() after populating value->attrs. Now there is a BindingsBuilder helper that wraps Bindings and ensures that sort() is called before you can use it.
2021-08-29Force all Pos* to be non-nullRobert Hensing
This fixes a class of crashes and introduces ptr<T> to make the code robust against this failure mode going forward. Thanks regnat for the idea of a ref<T> without overhead! Closes #4895 Closes #4893 Closes #5127 Closes #5113
2021-04-13libexpr: misc improvements for proper error positionMaximilian Bosch
When working on some more complex Nix code, there are sometimes rather unhelpful or misleading error messages, especially if coerce-errors are thrown. This patch is a first steps towards improving that. I'm happy to file more changes after that, but I'd like to gather some feedback first. To summarize, this patch does the following things: * Attrsets (a.k.a. `Bindings` in `libexpr`) now have a `Pos`. This is helpful e.g. to identify which attribute-set in `listToAttrs` is invalid. * The `Value`-struct has a new method named `determinePos` which tries to guess the position of a value and falls back to a default if that's not possible. This can be used to provide better messages if a coercion fails. * The new `determinePos`-API is used by `builtins.concatMap` now. With that change, Nix shows the exact position in the error where a wrong value was returned by the lambda. To make sure it's still obvious that `concatMap` is the problem, another stack-frame was added. * The changes described above can be added to every other `primop`, but first I'd like to get some feedback about the overall approach.
2021-01-21Improve error formattingEelco Dolstra
Changes: * The divider lines are gone. These were in practice a bit confusing, in particular with --show-trace or --keep-going, since then there were multiple lines, suggesting a start/end which wasn't the case. * Instead, multi-line error messages are now indented to align with the prefix (e.g. "error: "). * The 'description' field is gone since we weren't really using it. * 'hint' is renamed to 'msg' since it really wasn't a hint. * The error is now printed *before* the location info. * The 'name' field is no longer printed since most of the time it wasn't very useful since it was just the name of the exception (like EvalError). Ideally in the future this would be a unique, easily googleable error ID (like rustc). * "trace:" is now just "…". This assumes error contexts start with something like "while doing X". Example before: error: --- AssertionError ---------------------------------------------------------------------------------------- nix at: (7:7) in file: /home/eelco/Dev/nixpkgs/pkgs/applications/misc/hello/default.nix 6| 7| x = assert false; 1; | ^ 8| assertion 'false' failed ----------------------------------------------------- show-trace ----------------------------------------------------- trace: while evaluating the attribute 'x' of the derivation 'hello-2.10' at: (192:11) in file: /home/eelco/Dev/nixpkgs/pkgs/stdenv/generic/make-derivation.nix 191| // (lib.optionalAttrs (!(attrs ? name) && attrs ? pname && attrs ? version)) { 192| name = "${attrs.pname}-${attrs.version}"; | ^ 193| } // (lib.optionalAttrs (stdenv.hostPlatform != stdenv.buildPlatform && !dontAddHostSuffix && (attrs ? name || (attrs ? pname && attrs ? version)))) { Example after: error: assertion 'false' failed at: (7:7) in file: /home/eelco/Dev/nixpkgs/pkgs/applications/misc/hello/default.nix 6| 7| x = assert false; 1; | ^ 8| … while evaluating the attribute 'x' of the derivation 'hello-2.10' at: (192:11) in file: /home/eelco/Dev/nixpkgs/pkgs/stdenv/generic/make-derivation.nix 191| // (lib.optionalAttrs (!(attrs ? name) && attrs ? pname && attrs ? version)) { 192| name = "${attrs.pname}-${attrs.version}"; | ^ 193| } // (lib.optionalAttrs (stdenv.hostPlatform != stdenv.buildPlatform && !dontAddHostSuffix && (attrs ? name || (attrs ? pname && attrs ? version)))) {
2020-06-23use plain errPos instead of nixCode; fix testsBen Burdette
2020-06-15Get rid of explicit ErrorInfo constructorsEelco Dolstra
2020-05-08add pos to errorinfo, remove from hintsBen Burdette
2020-02-13Bindings::get(): std::optional<Attr *> -> Attr *Eelco Dolstra
Returning a nullable type in an optional is silly.
2019-12-05Bindings: Add convenience method for requiring an attributeEelco Dolstra
(cherry picked from commit fb692e5f7b34def8cf590298036ab63e40747062)
2019-12-05Bindings::get(): Add convenience methodEelco Dolstra
This allows writing attribute lookups as if (auto name = value.attrs->get(state.sName)) ... (cherry picked from commit f216c76c56cdffb5214d074a7d44812843dd174f)
2018-02-19libexpr: Don't create lots of temporary strings in Bindings::lexicographicOrderTuomas Tynkkynen
Avoids ~180,000 string temporaries created when evaluating a headless NixOS system.
2017-01-26Bindings: Add a method for iterating in lexicographically sorted orderEelco Dolstra
2015-07-14Move attribute set data structures into their own header file.Nicolas B. Pierron
This modification moves Attr and Bindings structures into their own header file which is dedicated to the attribute set representation. The goal of to isolate pieces of code which are related to the attribute set representation. Thus future modifications of the attribute set representation will only have to modify these files, and not every other file across the evaluator.