Skip to content

Commit

Permalink
cli: Tweak default thread count logic
Browse files Browse the repository at this point in the history
  • Loading branch information
tavianator committed Nov 29, 2023
1 parent 84f032e commit f63f1df
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 21 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@
- Breaking: `.git/` is now ignored by default when using `--hidden` / `-H`, use `--no-ignore` / `-I` or
`--no-ignore-vcs` to override, see #1387 and #1396 (@skoriop)


## Bugfixes

- Fix `NO_COLOR` support, see #1421 (@acuteenvy)

## Changes

- The default number of threads is now constrained to be at most 16. This should improve startup time on
systems with many CPU cores. (#1203)
- Performance has been significanly improved, both due to optimizations in the underlying `ignore`
crate (#1429), and in `fd` itself (#1422)

- The default number of threads is now more constrained. We use all available cores and hyperthreads up
to a maximum of 8. Past that, we use only one thread per physical core, up to a limit of 64. This
should improve performance and startup time on systems with many CPU cores. (#1203, #1412, #1430)

## Other

Expand Down
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ normpath = "1.1.1"
crossbeam-channel = "0.5.8"
clap_complete = {version = "4.4.4", optional = true}
faccess = "0.2.4"
num_cpus = "1.16.0"

[dependencies.clap]
version = "4.4.7"
Expand Down
37 changes: 19 additions & 18 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,24 +715,25 @@ impl Opts {
fn default_num_threads() -> NonZeroUsize {
// If we can't get the amount of parallelism for some reason, then
// default to a single thread, because that is safe.
// Note that the minimum value for a NonZeroUsize is 1.
// Unfortunately, we can't do `NonZeroUsize::new(1).unwrap()`
// in a const context.
const FALLBACK_PARALLELISM: NonZeroUsize = NonZeroUsize::MIN;
// As the number of threads increases, the startup time suffers from
// initializing the threads, and we get diminishing returns from additional
// parallelism. So set a maximum number of threads to use by default.
//
// This value is based on some empirical observations, but the ideal value
// probably depends on the exact hardware in use.
//
// Safety: The literal "20" is known not to be zero.
const MAX_DEFAULT_THREADS: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(20) };

std::cmp::min(
std::thread::available_parallelism().unwrap_or(FALLBACK_PARALLELISM),
MAX_DEFAULT_THREADS,
)
let fallback = NonZeroUsize::MIN;
// fd generally scales well up to 8 threads. Past that, it's better to limit
// ourselves to the number of physical cores, ignoring hyperthreads.
let threshold = NonZeroUsize::new(8).unwrap();
// To limit startup overhead on massively parallel machines, don't use more
// than 64 threads.
let limit = NonZeroUsize::new(64).unwrap();

// Get the total number of CPUs available, including hyperthreads
let threads = std::thread::available_parallelism().unwrap_or(fallback);
if threads <= threshold {
return threads;
}

// Compute min(threads, max(cores, threshold), limit). Avoid calling
// num_cpus::get_physical() if we don't have to, since it costs a bit of
// startup time to parse /proc/cpuinfo.
let cores = NonZeroUsize::new(num_cpus::get_physical()).unwrap();
threads.min(cores.clamp(threshold, limit))
}

#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
Expand Down

0 comments on commit f63f1df

Please sign in to comment.