thunk values are shareable, and we can represent invalid/uninitialized
values with a special bit pattern that makes no sense otherwise. there
is no need to keep allocating values on the heap, instead we can treat
values like reference-counted smart pointers to heap objects, which in
turn lets us save a lot of allocations and, ultimately, gc heap space.
compared to our baseline (main of 2025-09-27) we save 15%+ memory on a
system rebuild and 17% on nix search. eval time regresses by ~3% for a
system rebuild, while nix search is 7% faster. further optimization is
probably possible (but for now this will just have to be good enough).
Change-Id: Ib6c47acdbe2fac4f76a83c2269f16f30ef66b2e1
with thunk state being shareable we no longer need to worry about value
uniqueness, only about value lifetime. this means we can liberally drop
indirections and allocations, passing references instead of pointers or
using stack memory instead of gc-managed memory for some intermediates.
Change-Id: I2d48a6fd57a376d544bd9bd2d05e5420611986d1
there's no measurable performance gain in real-world testing to abusing
our list value storage like this. we haven't tested how much storage we
actually need on the stack to offset most of the temporary storage cost
and used 128 as a "good enough" value instead, reserving 1 kiB of stack
space on 64 bit platforms in a leaf function. this should do for a bit.
Change-Id: Ie98519b1da3e6fe685da88d1c44ffb4580fb592a
Value is already tagged. Value::Acb blocks are allocated for lambdas (so
we can fit the value tag into the three bits we have available), but the
current layout is rather wasteful for this purpose. the type bits can be
stored together with parts of pointers, which in the lambda case will be
the scope the lambda captures. the expr could also be used, but Env is a
gc-allocated item and thus guaranteed to be aligned properly for tagging
Change-Id: Ia685875387c7795bc4a00d73d1ce3cfea84e7297
this is a strong prerequisite for making values themselves copyable
without duplicating evaluation side effects. with this we can treat
`Value` the way we treated `Value *` to date and drop indirections.
Change-Id: I08f30d12697614a3ae7149615f6f1da83b13f52b
preserve type information of wrapped exception when constructing a
ForeignException. this requires using `std::current_exception` for
construction in all cases as passing the exception by reference to
any function erases dynamic type information: `throw` may copy the
thrown exception from its source expression; this only works as we
need it to if static and dynamic type of the expression are equal.
fixes#1000
Change-Id: I7167f298540de7c43c2566592bdb8d7a93c34d31
same as for null: we have few of them, they're statically allocated,
and they're not the largest contributor to the value population. not
storing them in Value itself frees up resources we *will* use later.
Change-Id: I521f9f243f48f56a78f7bffdf1dc1f0bc40a5c2d
we only need the one object for it. there's no need to waste precious
bits of the value internal type enum for this simple singleton datum.
Change-Id: Ie314b5bf429015e518798d9d65ad8ab2bb84a38e
floats are used very rarely, and our float support is bad enough to
strongly discourage using them on reproducibility grounds alone. we
can thus move them to more expensive storage without hurting folks.
Change-Id: I1086f612f85e294dd3fae4a2d334e09f52bbe4a8
external values very rarely appear during eval "normal" eval, and
creating them is pretty expensive. does *anything* even use them?
Change-Id: Id50fa3f76b7e1f551d550d99996a1ed5880b2531
despite not using allocation caches this does not have a statistically
significant performance impact, with less than 1% extra memory needed.
Change-Id: Ibe51a55ba986e471f217f3724977af17880fafff
using the same nodes as tApp is possible, and thanks to multi-arg app
nodes it can even be a bit faster than the linked lists used to date.
Change-Id: Idccb7c0b54c808e62da85d1c42ee09e6e92c4f7b
these behave like the old chains of app nodes, but they can store more
than one argument per node. for tApp values themselves this is not all
that useful, but if we could share tApp and tPrimOpApp backing storage
we could avoid creating and traversing the linked lists of values that
are currently needed to represent partially applied builtin functions.
Change-Id: I5a2a02d9733e1e0be5443459e2998d62fd3b9a5b
paths already are just strings with slightly magic semantics. the type
can mirror that at no perf cost, letting us drop one internalType tag.
Change-Id: I98acaa4fe3bedd28fc0841e1b81184d8dcddacc5
memory overhead is minimal and performance impact not measurable. once
we've done something like this for all value types that don't fit in a
single machine word we can cut a word from Value, offsetting the cost.
Change-Id: I9813bacd7e851957ad3426aed8f74033179a4212
we now use a single cache set for a number of sizes from one to eight
words. this also matches small attrsets, but perf impact seems small.
Change-Id: Icf16b329b98a20fcc9fe75e6395e148f0852c798
on its own this is not very useful, but having accessors for every value
kind is a prerequisite for doing smart things with Value than the union.
the net effect for now is only to add a few parentheses across the tree.
Change-Id: I88688ac09eb08495dad1eb221034ca540f094950
using sleep(1) as a synchronization mechanism does not work. use fifos instead.
fixes#690 and ci constantly falling over in the same exact fucking source line
Change-Id: I51725f8e439b6753f3212d2897dbb0620ad77a37
libarchive is not async and cannot be used async without involving green
threads, which have already proven to be very problematic. unpacking tar
archives is rare enough that spawning a new thread for each shouldn't be
too much overhead, and the additional data copy probably also won't hurt
performance too much. we may even benefit from being able to extract not
just one archive per event loop but as many archives as we can keep fed.
Change-Id: Iece82bd566ada0a2a49de54c4e69caf6d93f6720
using a sink for this has long been a bit weird anyway. originally it
was necessary due to api limitations, but it hasn't been for a while.
Change-Id: I3dfa157944618349bfd6f398ee1667fc31519d86
printTaggedWarning already colorized its messages. we can do the same
for most other log messages.
Change-Id: Idcd31bbf4f8d0d703395b0d2b7b9bc33264d969f
luckily none of these a format strings vulnerabilities because
boost::format is smart enough to throw an exception when given
fewer format string arguments than are requested by specifiers
Change-Id: I5fa78f0d1396263271f6e1dbcee9c0b2e9e18c34
always use log macros, which also have the benefit of respecting the
verbosity setting without needing virtual function calls to read it.
Change-Id: I1c605562a53e54140724d5225e040abcf49ac996
we add two variants: one that just prints a message at the warning
level (mirroring the other printer macros), and one that also adds
the colored "warning: " prefix the function added. since there are
no overriders of this function in tree it looks safe to remove it.
Change-Id: I7008fd0f31d59fbc9259472e29359c8df19ff87d
mostly useful for nix-eval-jobs which currently has to call the logger
functions directly because its main code *isn't* in the nix namespace.
Change-Id: Ia8440d86a293d9006ffef2562b1859e9aaa79a62
it's broken, can write arbitrary file paths when run as root, and only
supports strings and recursive sets of strings. this was only used for
manpage generation in a build system that has not woken up since 1976.
fixes#974fixes#227
Change-Id: I4f18599685a3077c15ddc02c759558f986c8c6e4
this pretty much only impacts store verification via the nix3 cli. no
other thread pools are left, and the verification pool may *actually*
be important for throughput since verification involves much hashing.
Change-Id: I32152e6169a82a1268a790e333f21a0430ede7f4
signing is very cheap, it's only the store access that is expensive.
http binary caches parallelize async accesses extremely well though.
Change-Id: Ifdbf398bd328ba16ec4e8caba3f5f99a6cf3e046
this is used by nix-env and copyPaths, which in turn is used to upload
to binary caches. for a large path set we have seen 10x a improvement.
Change-Id: Ieadd0e66180e5ceecefaf944a5bb2f0523374954
notably this also includes the symbol table because it stores real
strings that are referenced by eval values, and an upcoming change
will make it impossible to share those strings with value strings.
Change-Id: I20a3644db8aa0850efe29630e0b73d424cb2aa56
use a thread pool and allow only buffered sources for performance. we
may want to use this code path unconditionally due to gc interactions
of fibers in circumstances we should not even be able to trigger, but
if that becomes important we will have a useful implementation ready.
Change-Id: Ib4e1531fe920847d8e30a42e8df393ace549f52e
this means both the worker protocol and the serve protocol, i.e.
ssh-ng/local connections and legacy ssh connections. now we have
no blocking reads left anywhere in our client store connections.
Change-Id: I2f628d4d2e71ef0a7006918f175192f3f58eea95
shoving a nar dump directly into a framed sink created a bunch of tiny
frames, each of which requires at least two syscalls to read. this can
lead to immense performance loss when using a daemon; we have seen 15%
in benchmarks on main and even more with async code involved ... oops.
Change-Id: I8529506e3de74d92834d1f4ee228dcaf32eb756c
this lets us avoid a bunch of fcntl calls to unset and re-set O_NONBLOCK
on remote store connections. the overhead of these isn't high, but doing
it is still wasteful and a maintenance burden when we have async readers
Change-Id: I900cdca2a16202380c8b6f9b86da7d9b0f1e34ac
the former isn't even int, it's unsigned. the latter is uint64. both
should be explicit about this to avoid problems that we have already
had, such as the FramedSource wire protocol writing using 64 bits to
write frame sizes, but 32 bits to read them. large frames will cause
the reading end to crash with an unnecessary serialization exception
Change-Id: I3c15e911f649eec719d4b1c135dde1b6ba020271
they will not work well with async deserialization and are not used
consistently anyway. just like the serializing operator<< these are
protocol stability hazards: changing the type of a field influences
the wire protocol layout and type constraints, which is not amazing
Change-Id: I54b20a133048f4ca15a9fb0f4d8b94dc78f62d89
this is an equivalent of the regular kj read interface which also takes
a min/max pair. we do not need this very often though, so we'll keep it
as a separate method for now. if we do find we use it more than read we
can still rename read to readSingle and readRange to read. we will see.
Change-Id: Ib04ca146911adae7081cf4b2df097217ea5fe9f8
this should've been a filter from the start. since filter support in the
old IO model is very bad we just move it into the only use of it instead
Change-Id: Ifb9cfecf07587ae1d2d55072ddf505c86c79cc1b
we should not encourage this kind of framing. in the future we will have
to do this on async streams, which we *absolutely* should not encourage.
Change-Id: Ib89e144afb564284db64fc7367cba7fffc18fdaf
the exception no longer actually matters, only that the download stream
is destroyed before the download finishes does. exceptions during drain
calls on the returned stream will cause the stream to be destroyed, but
draining this stream is just a remnant of the old download-to-sink API.
Change-Id: Ic6de40deb2ccff09d77180148afe746f29f55d23
we don't need to report progress for every read call. that's way too
much. batching like this greatly reduces CPU usage for copies out of
or into remote buidlers due to likewise greatly reduced log traffic.
Change-Id: I3db2b2ab113fbaadefc69cfde6f977fb0c6cd5ad
PushActivity does not work with async code since we have no such thing
as promise-local storage. it will be confusing at best, and completely
wrong at worst, with the current thread-local linking state. if we can
find a way to get promise-local storage we may want to bring this back
though, explicit context passing is rather error-prone. luckily we are
not using parent links for anything important, just to keep the multi-
line activity display from filling up with stuff we're already showing
Change-Id: Ie373d713080a3db811b2d5abd681f78137735e45
checking that the remote build actually succeeded only implied-trusted
remotes or CA derivations makes *absolutely* no sense. we should check
that builds have succeeded before trying to copy them from the remote.
Change-Id: Ib2cf216c580f4c577dd9fef8849acc033ae082b9
capnp does not handle fd passing correctly in all circumstances. we hit
such cirumstances when passing large closures path lists to build-hook.
since capnp seems to ignore fds passed in non-final segments of any rpc
message we just ensure that the capability including the log fd will be
small enough to not be fragmented on the receiving side of the channel.
cf https://github.com/capnproto/capnproto/issues/2359
Change-Id: Id22309264936b3a57bcc68a0753c3bfb3c9a43d2
remote builds failures used to be signaled via exit status 1 of the
build hook, which in turn only happened because the build errors we
got from remote stores was thrown and bubbled up to main which then
logged the error and exited with code 1. with rpc we cannot do this
any more. barring a rewrite of the worker infra to allow for errors
being reported with something other than process exit codes this is
the best can do. ideally we would wrap remote builds in a new goal.
(and then remove all exit code shenanigans from DerivationGoal too)
fixes#928
Change-Id: Idc3ede3cbaca34c8c8e40247da52794f2a5013b9
drop our reimplementation of splice for non-linux in favor of using kj
pumpTo. this avoids select() for its O(maxfd) behavior, and if kj ever
uses something more efficient than read/write loops we'll benefit too.
Change-Id: Id01ba84bf8831455af2d9755bf1a3039d215bb47
libarchive *should* not break with 0710 on the tmpdir root on darwin,
just like it doesn't break on linux, but for some reason it does. the
restriction to 0710 can be weakened to 0750 with causing any trouble.
fixes#921
Change-Id: Ia9fc2f8eb9695fc19cefae9857368d5a4e58c8b9
previously we only had one build hook in waiting at most because build
hook rpc was synchronous. now that it no longer is we attempt to start
one hook per derivation, which depending on scheduling can be a *very*
large number. restrict the waiting hook count to 4 to some concurrency
without collecting a large number of hooks that may never do anything.
Change-Id: Ic0b1125cec4acd69e8a0d4639c232e71b825e01d
although we only chown if the build was requested by a local daemon
user. daemonless invocations will not chown as they do not have to.
remote builds *can* chown to the remote builder user, but that does
not seem to happen (for some reason keep-failed is not propagated).
Change-Id: Ic0ead406b38b4ca0556fec42d84888efa25123bf
this makes the actual build directories used by builders invisible and
inaccessible to other processes on the system, avoiding another vector
for outside processes to interfere with builds or pass credentials the
build sandbox should not have access to into the build sandbox anyway.
fixes#919
Change-Id: Ifaa4d8e3940cfde1406e925f75c1375d2e86d81a
this touches both libutil and libstore because with no rpc users it
doesn't make that much sense to separate the two. note that all our
strings are represented as Data (ie, blobs) because capnp Text must
be nul-terminated. while it's technically possible to use Text with
strings containing non-terminating NULs it is a bit of a hassle and
could lead to rpc users erroneously stopping at the first NUL byte.
Change-Id: I4c75e03b79a226ffa8d7cd985e3ac632a0cd7c1c
we need this to generate dependency information, and it'll be the entry
point for custom codegen once we need it. a wrapper also makes it a lot
easier to generate a whole namespace's worth of rpc definitions at once
Change-Id: Iba7a1c92a8a40bede9ed71aa3ab455477ff5e568
if the hook accepts the build request we can handle the entire request
in tryBuildHook. there is no need to punt a partially handled build to
the caller (we only did this to minimize churn during asyncification).
Change-Id: Iec3e35a8103da4fc5fbef394cc28a134ee62a198
mapping the result of an await operation before unpacking it lets us
inject rpc type conversion functions without duplicating all that is
needed for proper exception wrapping and async error traces support.
Change-Id: Ibcba1cc6d2b275757e3475881ef20f95dd4d684f