Skip to content

Commit e95130a

Browse files
authored
Introduce TY_MAX_PARALLELISM environment variable (#17830)
1 parent 68e32c1 commit e95130a

4 files changed

Lines changed: 77 additions & 35 deletions

File tree

crates/ruff_db/src/lib.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use std::hash::BuildHasherDefault;
2-
3-
use ruff_python_ast::PythonVersion;
4-
use rustc_hash::FxHasher;
5-
61
use crate::files::Files;
72
use crate::system::System;
83
use crate::vendored::VendoredFileSystem;
4+
use ruff_python_ast::PythonVersion;
5+
use rustc_hash::FxHasher;
6+
use std::hash::BuildHasherDefault;
7+
use std::num::NonZeroUsize;
98

109
pub mod diagnostic;
1110
pub mod display;
@@ -37,6 +36,29 @@ pub trait Upcast<T: ?Sized> {
3736
fn upcast_mut(&mut self) -> &mut T;
3837
}
3938

39+
/// Returns the maximum number of tasks that ty is allowed
40+
/// to process in parallel.
41+
///
42+
/// Returns [`std::thread::available_parallelism`], unless the environment
43+
/// variable `TY_MAX_PARALLELISM` or `RAYON_NUM_THREADS` is set. `TY_MAX_PARALLELISM` takes
44+
/// precedence over `RAYON_NUM_THREADS`.
45+
///
46+
/// Falls back to `1` if `available_parallelism` is not available.
47+
///
48+
/// Setting `TY_MAX_PARALLELISM` to `2` only restricts the number of threads that ty spawns
49+
/// to process work in parallel. For example, to index a directory or checking the files of a project.
50+
/// ty can still spawn more threads for other tasks, e.g. to wait for a Ctrl+C signal or
51+
/// watching the files for changes.
52+
pub fn max_parallelism() -> NonZeroUsize {
53+
std::env::var("TY_MAX_PARALLELISM")
54+
.or_else(|_| std::env::var("RAYON_NUM_THREADS"))
55+
.ok()
56+
.and_then(|s| s.parse().ok())
57+
.unwrap_or_else(|| {
58+
std::thread::available_parallelism().unwrap_or_else(|_| NonZeroUsize::new(1).unwrap())
59+
})
60+
}
61+
4062
#[cfg(test)]
4163
mod tests {
4264
use std::sync::Arc;

crates/ruff_db/src/system/os.rs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1+
use super::walk_directory::{
2+
self, DirectoryWalker, WalkDirectoryBuilder, WalkDirectoryConfiguration,
3+
WalkDirectoryVisitorBuilder, WalkState,
4+
};
5+
use crate::max_parallelism;
6+
use crate::system::{
7+
CaseSensitivity, DirectoryEntry, FileType, GlobError, GlobErrorKind, Metadata, Result, System,
8+
SystemPath, SystemPathBuf, SystemVirtualPath, WritableSystem,
9+
};
110
use filetime::FileTime;
211
use ruff_notebook::{Notebook, NotebookError};
312
use rustc_hash::FxHashSet;
13+
use std::num::NonZeroUsize;
414
use std::panic::RefUnwindSafe;
515
use std::sync::Arc;
616
use std::{any::Any, path::PathBuf};
717

8-
use crate::system::{
9-
CaseSensitivity, DirectoryEntry, FileType, GlobError, GlobErrorKind, Metadata, Result, System,
10-
SystemPath, SystemPathBuf, SystemVirtualPath, WritableSystem,
11-
};
12-
13-
use super::walk_directory::{
14-
self, DirectoryWalker, WalkDirectoryBuilder, WalkDirectoryConfiguration,
15-
WalkDirectoryVisitorBuilder, WalkState,
16-
};
17-
1818
/// A system implementation that uses the OS file system.
1919
#[derive(Debug, Clone)]
2020
pub struct OsSystem {
@@ -426,11 +426,7 @@ impl DirectoryWalker for OsDirectoryWalker {
426426
builder.add(additional_path.as_std_path());
427427
}
428428

429-
builder.threads(
430-
std::thread::available_parallelism()
431-
.map_or(1, std::num::NonZeroUsize::get)
432-
.min(12),
433-
);
429+
builder.threads(max_parallelism().min(NonZeroUsize::new(12).unwrap()).get());
434430

435431
builder.build_parallel().run(|| {
436432
let mut visitor = visitor_builder.build();

crates/ty/docs/tracing.md

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Tracing
22

3-
Traces are a useful tool to narrow down the location of a bug or, at least, to understand why the compiler is doing a particular thing.
3+
Traces are a useful tool to narrow down the location of a bug or, at least, to understand why the compiler is doing a
4+
particular thing.
45
Note, tracing messages with severity `debug` or greater are user-facing. They should be phrased accordingly.
56
Tracing spans are only shown when using `-vvv`.
67

@@ -9,20 +10,28 @@ Tracing spans are only shown when using `-vvv`.
910
The CLI supports different verbosity levels.
1011

1112
- default: Only show errors and warnings.
12-
- `-v` activates `info!`: Show generally useful information such as paths of configuration files, detected platform, etc., but it's not a lot of messages, it's something you'll activate in CI by default. cargo build e.g. shows you which packages are fresh.
13-
- `-vv` activates `debug!` and timestamps: This should be enough information to get to the bottom of bug reports. When you're processing many packages or files, you'll get pages and pages of output, but each line is link to a specific action or state change.
14-
- `-vvv` activates `trace!` (only in debug builds) and shows tracing-spans: At this level, you're logging everything. Most of this is wasted, it's really slow, we dump e.g. the entire resolution graph. Only useful to developers, and you almost certainly want to use `TY_LOG` to filter it down to the area your investigating.
15-
16-
## Better logging with `TY_LOG` and `RAYON_NUM_THREADS`
13+
- `-v` activates `info!`: Show generally useful information such as paths of configuration files, detected platform,
14+
etc., but it's not a lot of messages, it's something you'll activate in CI by default. cargo build e.g. shows you
15+
which packages are fresh.
16+
- `-vv` activates `debug!` and timestamps: This should be enough information to get to the bottom of bug reports. When
17+
you're processing many packages or files, you'll get pages and pages of output, but each line is link to a specific
18+
action or state change.
19+
- `-vvv` activates `trace!` (only in debug builds) and shows tracing-spans: At this level, you're logging everything.
20+
Most of this is wasted, it's really slow, we dump e.g. the entire resolution graph. Only useful to developers, and you
21+
almost certainly want to use `TY_LOG` to filter it down to the area your investigating.
22+
23+
## Better logging with `TY_LOG` and `TY_MAX_PARALLELISM`
1724

1825
By default, the CLI shows messages from the `ruff` and `ty` crates. Tracing messages from other crates are not shown.
1926
The `TY_LOG` environment variable allows you to customize which messages are shown by specifying one
20-
or more [filter directives](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives).
27+
or
28+
more [filter directives](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives).
2129

22-
The `RAYON_NUM_THREADS` environment variable, meanwhile, can be used to control the level of concurrency ty uses.
30+
The `TY_MAX_PARALLELISM` environment variable, meanwhile, can be used to control the level of parallelism ty uses.
2331
By default, ty will attempt to parallelize its work so that multiple files are checked simultaneously,
24-
but this can result in a confused logging output where messages from different threads are intertwined.
25-
To switch off concurrency entirely and have more readable logs, use `RAYON_NUM_THREADS=1`.
32+
but this can result in a confused logging output where messages from different threads are intertwined and non
33+
determinism.
34+
To switch off parallelism entirely and have more readable logs, use `TY_MAX_PARALLELSIM=1` (or `RAYON_NUM_THREADS=1`).
2635

2736
### Examples
2837

@@ -79,22 +88,24 @@ query to return the failure as part of the query's result or use a Salsa accumul
7988

8089
## Tracing in tests
8190

82-
You can use `ruff_db::testing::setup_logging` or `ruff_db::testing::setup_logging_with_filter` to set up logging in tests.
91+
You can use `ruff_db::testing::setup_logging` or `ruff_db::testing::setup_logging_with_filter` to set up logging in
92+
tests.
8393

8494
```rust
8595
use ruff_db::testing::setup_logging;
8696

8797
#[test]
8898
fn test() {
89-
let _logging = setup_logging();
99+
let _logging = setup_logging();
90100

91-
tracing::info!("This message will be printed to stderr");
101+
tracing::info!("This message will be printed to stderr");
92102
}
93103
```
94104

95105
Note: Most test runners capture stderr and only show its output when a test fails.
96106

97-
Note also that `setup_logging` only sets up logging for the current thread because [`set_global_default`](https://docs.rs/tracing/latest/tracing/subscriber/fn.set_global_default.html) can only be
107+
Note also that `setup_logging` only sets up logging for the current thread because
108+
[`set_global_default`](https://docs.rs/tracing/latest/tracing/subscriber/fn.set_global_default.html) can only be
98109
called **once**.
99110

100111
## Release builds
@@ -103,7 +114,8 @@ called **once**.
103114

104115
## Profiling
105116

106-
ty generates a folded stack trace to the current directory named `tracing.folded` when setting the environment variable `TY_LOG_PROFILE` to `1` or `true`.
117+
ty generates a folded stack trace to the current directory named `tracing.folded` when setting the environment variable
118+
`TY_LOG_PROFILE` to `1` or `true`.
107119

108120
```bash
109121
TY_LOG_PROFILE=1 ty -- --current-directory=../test -vvv

crates/ty/src/main.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use anyhow::{anyhow, Context};
1010
use clap::Parser;
1111
use colored::Colorize;
1212
use crossbeam::channel as crossbeam_channel;
13+
use rayon::ThreadPoolBuilder;
1314
use ruff_db::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity};
15+
use ruff_db::max_parallelism;
1416
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
1517
use salsa::plumbing::ZalsaDatabase;
1618
use ty_project::metadata::options::Options;
@@ -25,6 +27,8 @@ mod python_version;
2527
mod version;
2628

2729
pub fn main() -> ExitStatus {
30+
setup_rayon();
31+
2832
run().unwrap_or_else(|error| {
2933
use std::io::Write;
3034

@@ -392,3 +396,11 @@ fn set_colored_override(color: Option<TerminalColor>) {
392396
}
393397
}
394398
}
399+
400+
/// Initializes the global rayon thread pool to never use more than `TY_MAX_PARALLELISM` threads.
401+
fn setup_rayon() {
402+
ThreadPoolBuilder::default()
403+
.num_threads(max_parallelism().get())
404+
.build_global()
405+
.unwrap();
406+
}

0 commit comments

Comments
 (0)