Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/libexpr/parallel-eval.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,15 @@ std::vector<std::future<void>> Executor::spawn(WorkItems && items)
for (auto & item : items) {
std::promise<void> promise;
futures.push_back(promise.get_future());
[[gnu::tls_model("initial-exec")]] static thread_local std::random_device rd;
/* Note: this uses a cheap PRNG rather than std::random_device,
since the latter costs hundreds of cycles per call (RDRAND or
/dev/urandom), which adds up when spawning many work items. The
key only needs to spread items of the same priority around the
queue, not be cryptographically random. */
[[gnu::tls_model("initial-exec")]] static thread_local std::mt19937_64 rng{std::random_device{}()};
[[gnu::tls_model("initial-exec")]] static thread_local std::uniform_int_distribution<uint64_t> dist(
0, 1ULL << 48);
auto key = (uint64_t(item.second) << 48) | dist(rd);
auto key = (uint64_t(item.second) << 48) | dist(rng);
Comment on lines +137 to +145

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

! rg -n '0,\s*1ULL << 48\)' src/libexpr/parallel-eval.cc

Repository: DeterminateSystems/nix-src

Length of output: 200


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Show the relevant section with line numbers.
sed -n '120,160p' src/libexpr/parallel-eval.cc

printf '\n---\n'

# Find the type/usage of the queued item and key comparisons.
rg -n 'item\.second|key =|priority|uniform_int_distribution|mt19937_64|queue' src/libexpr/parallel-eval.cc

Repository: DeterminateSystems/nix-src

Length of output: 2531


🌐 Web query:

std::uniform_int_distribution inclusive upper bound cppreference

💡 Result:

In C++, the std::uniform_int_distribution template produces random integers that are uniformly distributed on the closed interval [a, b] [1][2]. This means that both the minimum value (a) and the maximum value (b) are inclusive [1][3]. When constructing the distribution, the second parameter b defaults to the maximum representable value of the integer type (std::numeric_limits::max), which is also included in the potential output range [4][2].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate the relevant type definitions and queue ordering.
rg -n 'WorkItems|Priority|queue|std::priority_queue|std::map|emplace\(key|item\.second' src/libexpr/parallel-eval.cc

printf '\n---\n'

# Show the top of the file where types and state are declared.
sed -n '1,120p' src/libexpr/parallel-eval.cc

Repository: DeterminateSystems/nix-src

Length of output: 4664


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Find the declarations used by Executor::spawn and the queue type.
rg -n 'using WorkItems|struct Item|queue|priority|enum class|enum ' src/libexpr/parallel-eval.hh src/libexpr/parallel-eval.cc

printf '\n--- parallel-eval.hh ---\n'
sed -n '1,220p' src/libexpr/parallel-eval.hh

Repository: DeterminateSystems/nix-src

Length of output: 1103


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate the parallel-eval headers and the WorkItems / queue declarations.
fd -a 'parallel-eval.hh' src
printf '\n---\n'
fd -a 'parallel-eval.cc' src
printf '\n---\n'
rg -n 'using WorkItems|struct Item|priority|queue|std::map|std::priority_queue|enum class' src/libexpr src -g '!**/build/**' || true

Repository: DeterminateSystems/nix-src

Length of output: 50382


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Find the actual location of the parallel-eval header and inspect declarations.
fd -a 'parallel-eval.hh' .
printf '\n---\n'
fd -a 'parallel-eval.cc' .
printf '\n---\n'
rg -n 'using WorkItems|struct Item|priority|queue|std::map|std::priority_queue|enum class' src lib -g '!**/build/**' || true

Repository: DeterminateSystems/nix-src

Length of output: 50382


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate the Executor/State declaration and the queue container type.
rg -n 'struct State|class Executor|queue' src -g '*parallel*' -g '*eval*' -g '!**/build/**'

printf '\n---\n'
sed -n '1,220p' $(rg -l 'struct State|class Executor' src -g '*parallel*' -g '*eval*' | head -n 1)

Repository: DeterminateSystems/nix-src

Length of output: 7519


Keep the random suffix within bits 0–47. std::uniform_int_distribution is inclusive, so 1ULL << 48 can be returned and set bit 48, overlapping the priority field. Use (1ULL << 48) - 1 instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/libexpr/parallel-eval.cc` around lines 137 - 145, Update the thread-local
std::uniform_int_distribution<uint64_t> dist in the key-generation code to use
(1ULL << 48) - 1 as its inclusive upper bound, keeping the random suffix
confined to bits 0–47 and preventing overlap with the priority field shifted by
48.

state->queue.emplace(key, Item{.promise = std::move(promise), .work = std::move(item.first)});
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/nix/search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ struct CmdSearch : InstallableValueCommand, MixJSON
work,
std::string_view(state->symbols[attr]).find("Packages") != std::string_view::npos ? 0 : 2,
[cursor2, attrPath2, visit]() { visit(*cursor2, attrPath2, false); });
/* Spawn incrementally rather than after the whole
enumeration, so that idle worker threads can start
on the first attributes while we're still
enumerating the rest. */
if (work.size() >= 256)
futures.spawn(std::exchange(work, {}));
}
futures.spawn(std::move(work));
};
Expand Down
Loading