@@ -11,9 +11,11 @@ use crate::clippy_project_root;
11
11
12
12
use std:: collections:: HashMap ;
13
13
use std:: process:: Command ;
14
+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
14
15
use std:: { env, fmt, fs:: write, path:: PathBuf } ;
15
16
16
17
use clap:: ArgMatches ;
18
+ use rayon:: prelude:: * ;
17
19
use serde:: { Deserialize , Serialize } ;
18
20
use serde_json:: Value ;
19
21
@@ -215,11 +217,20 @@ impl CrateSource {
215
217
impl Crate {
216
218
/// Run `cargo clippy` on the `Crate` and collect and return all the lint warnings that clippy
217
219
/// issued
218
- fn run_clippy_lints ( & self , cargo_clippy_path : & PathBuf ) -> Vec < ClippyWarning > {
219
- println ! ( "Linting {} {}..." , & self . name, & self . version) ;
220
+ fn run_clippy_lints (
221
+ & self ,
222
+ cargo_clippy_path : & PathBuf ,
223
+ target_dir_index : & AtomicUsize ,
224
+ thread_limit : usize ,
225
+ ) -> Vec < ClippyWarning > {
226
+ // advance the atomic index by one
227
+ let idx = target_dir_index. fetch_add ( 1 , Ordering :: SeqCst ) ;
228
+ // "loop" the index within 0..thread_limit
229
+ let idx = idx % thread_limit;
230
+ println ! ( "Linting {} {} in target dir {:?}" , & self . name, & self . version, idx) ;
220
231
let cargo_clippy_path = std:: fs:: canonicalize ( cargo_clippy_path) . unwrap ( ) ;
221
232
222
- let shared_target_dir = clippy_project_root ( ) . join ( "target/lintcheck/shared_target_dir/ " ) ;
233
+ let shared_target_dir = clippy_project_root ( ) . join ( "target/lintcheck/shared_target_dir" ) ;
223
234
224
235
let mut args = vec ! [ "--" , "--message-format=json" , "--" , "--cap-lints=warn" ] ;
225
236
@@ -232,7 +243,8 @@ impl Crate {
232
243
}
233
244
234
245
let all_output = std:: process:: Command :: new ( & cargo_clippy_path)
235
- . env ( "CARGO_TARGET_DIR" , shared_target_dir)
246
+ // use the looping index to create individual target dirs
247
+ . env ( "CARGO_TARGET_DIR" , shared_target_dir. join ( format ! ( "_{:?}" , idx) ) )
236
248
// lint warnings will look like this:
237
249
// src/cargo/ops/cargo_compile.rs:127:35: warning: usage of `FromIterator::from_iter`
238
250
. args ( & args)
@@ -454,15 +466,27 @@ pub fn run(clap_config: &ArgMatches) {
454
466
. into_iter ( )
455
467
. map ( |krate| krate. download_and_extract ( ) )
456
468
. filter ( |krate| krate. name == only_one_crate)
457
- . map ( |krate| krate. run_clippy_lints ( & cargo_clippy_path) )
469
+ . map ( |krate| krate. run_clippy_lints ( & cargo_clippy_path, & AtomicUsize :: new ( 0 ) , 1 ) )
458
470
. flatten ( )
459
471
. collect ( )
460
472
} else {
473
+ let counter = std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ;
474
+
475
+ // Ask rayon for cpu (actually thread)count.
476
+ // Use one target dir for each cpu so that we can run N clippys in parallel.
477
+ // We need to use different target dirs because cargo would lock them for a single build otherwise,
478
+ // killing the parallelism. However this also means that deps will only be reused half/a
479
+ // quarter of the time which might result in a longer wall clock runtime
480
+
481
+ // Rayon seems to return thread count so half that for core count
482
+
483
+ let num_threads: usize = rayon:: current_num_threads ( ) / 2 ;
484
+
461
485
// check all crates (default)
462
486
crates
463
- . into_iter ( )
487
+ . into_par_iter ( )
464
488
. map ( |krate| krate. download_and_extract ( ) )
465
- . map ( |krate| krate. run_clippy_lints ( & cargo_clippy_path) )
489
+ . map ( |krate| krate. run_clippy_lints ( & cargo_clippy_path, & counter , num_threads ) )
466
490
. flatten ( )
467
491
. collect ( )
468
492
} ;
0 commit comments