Skip to content

Commit b77fe07

Browse files
committed
Avoid regenerating the Vec<PathBuf> in FileSearch::search().
`FileSearch::search()` traverses one or more directories. For each directory it generates a `Vec<PathBuf>` containing one element per file in that directory. In some benchmarks this occurs enough that the allocations done for the `PathBuf`s are significant, and in practice a small number of directories are being traversed over and over again. For example, when compiling the `tokio-webpush-simple` benchmark, two directories are traversed 58 times each. Each of these directories have more than 100 files. This commit changes things so that all the `Vec<PathBuf>`s that will be needed by a `Session` are precomputed when that `Session` is created; they are stored in `SearchPath`. `FileSearch` gets a reference to the necessary `SearchPath`s. This reduces instruction counts on several benchmarks by 1--5%. The commit also removes the barely-used `visited_dirs` hash in `for_each_lib_searchPath`. It only detects if `tlib_path` is the same as one of the previously seen paths, which is unlikely.
1 parent c435605 commit b77fe07

File tree

3 files changed

+42
-25
lines changed

3 files changed

+42
-25
lines changed

src/librustc/session/filesearch.rs

+11-23
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
pub use self::FileMatch::*;
1414

15-
use rustc_data_structures::fx::FxHashSet;
1615
use std::borrow::Cow;
1716
use std::env;
1817
use std::fs;
@@ -31,29 +30,22 @@ pub enum FileMatch {
3130

3231
pub struct FileSearch<'a> {
3332
pub sysroot: &'a Path,
34-
pub search_paths: &'a [SearchPath],
3533
pub triple: &'a str,
34+
pub search_paths: &'a [SearchPath],
35+
pub tlib_path: &'a SearchPath,
3636
pub kind: PathKind,
3737
}
3838

3939
impl<'a> FileSearch<'a> {
4040
pub fn for_each_lib_search_path<F>(&self, mut f: F) where
4141
F: FnMut(&SearchPath)
4242
{
43-
let mut visited_dirs = FxHashSet::default();
44-
visited_dirs.reserve(self.search_paths.len() + 1);
4543
let iter = self.search_paths.iter().filter(|sp| sp.kind.matches(self.kind));
4644
for search_path in iter {
4745
f(search_path);
48-
visited_dirs.insert(search_path.dir.to_path_buf());
4946
}
5047

51-
debug!("filesearch: searching lib path");
52-
let tlib_path = make_target_lib_path(self.sysroot,
53-
self.triple);
54-
if !visited_dirs.contains(&tlib_path) {
55-
f(&SearchPath { kind: PathKind::All, dir: tlib_path });
56-
}
48+
f(self.tlib_path);
5749
}
5850

5951
pub fn get_lib_path(&self) -> PathBuf {
@@ -65,21 +57,15 @@ impl<'a> FileSearch<'a> {
6557
{
6658
self.for_each_lib_search_path(|search_path| {
6759
debug!("searching {}", search_path.dir.display());
68-
let files = match fs::read_dir(&search_path.dir) {
69-
Ok(files) => files,
70-
Err(..) => return,
71-
};
72-
let files = files.filter_map(|p| p.ok().map(|s| s.path()))
73-
.collect::<Vec<_>>();
7460
fn is_rlib(p: &Path) -> bool {
7561
p.extension() == Some("rlib".as_ref())
7662
}
7763
// Reading metadata out of rlibs is faster, and if we find both
7864
// an rlib and a dylib we only read one of the files of
7965
// metadata, so in the name of speed, bring all rlib files to
8066
// the front of the search list.
81-
let files1 = files.iter().filter(|p| is_rlib(p));
82-
let files2 = files.iter().filter(|p| !is_rlib(p));
67+
let files1 = search_path.files.iter().filter(|p| is_rlib(p));
68+
let files2 = search_path.files.iter().filter(|p| !is_rlib(p));
8369
for path in files1.chain(files2) {
8470
debug!("testing {}", path.display());
8571
let maybe_picked = pick(path, search_path.kind);
@@ -98,12 +84,15 @@ impl<'a> FileSearch<'a> {
9884
pub fn new(sysroot: &'a Path,
9985
triple: &'a str,
10086
search_paths: &'a Vec<SearchPath>,
101-
kind: PathKind) -> FileSearch<'a> {
87+
tlib_path: &'a SearchPath,
88+
kind: PathKind)
89+
-> FileSearch<'a> {
10290
debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
10391
FileSearch {
10492
sysroot,
105-
search_paths,
10693
triple,
94+
search_paths,
95+
tlib_path,
10796
kind,
10897
}
10998
}
@@ -137,8 +126,7 @@ pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf
137126
p
138127
}
139128

140-
pub fn make_target_lib_path(sysroot: &Path,
141-
target_triple: &str) -> PathBuf {
129+
pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
142130
sysroot.join(&relative_target_lib_path(sysroot, target_triple))
143131
}
144132

src/librustc/session/mod.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use lint;
1919
use lint::builtin::BuiltinLintDiagnostics;
2020
use middle::allocator::AllocatorKind;
2121
use middle::dependency_format;
22-
use session::search_paths::PathKind;
2322
use session::config::{OutputType, Lto};
23+
use session::search_paths::{PathKind, SearchPath};
2424
use util::nodemap::{FxHashMap, FxHashSet};
2525
use util::common::{duration_to_secs_str, ErrorReported};
2626
use util::common::ProfileQueriesMsg;
@@ -64,6 +64,9 @@ pub struct Session {
6464
pub target: config::Config,
6565
pub host: Target,
6666
pub opts: config::Options,
67+
pub host_tlib_path: SearchPath,
68+
/// This is `None` if the host and target are the same.
69+
pub target_tlib_path: Option<SearchPath>,
6770
pub parse_sess: ParseSess,
6871
/// For a library crate, this is always none
6972
pub entry_fn: Once<Option<(NodeId, Span, config::EntryFnType)>>,
@@ -699,6 +702,8 @@ impl Session {
699702
&self.sysroot,
700703
self.opts.target_triple.triple(),
701704
&self.opts.search_paths,
705+
// target_tlib_path==None means it's the same as host_tlib_path.
706+
self.target_tlib_path.as_ref().unwrap_or(&self.host_tlib_path),
702707
kind,
703708
)
704709
}
@@ -707,6 +712,7 @@ impl Session {
707712
&self.sysroot,
708713
config::host_triple(),
709714
&self.opts.search_paths,
715+
&self.host_tlib_path,
710716
kind,
711717
)
712718
}
@@ -1106,6 +1112,15 @@ pub fn build_session_(
11061112
None => filesearch::get_or_default_sysroot(),
11071113
};
11081114

1115+
let host_triple = config::host_triple();
1116+
let target_triple = sopts.target_triple.triple();
1117+
let host_tlib_path = SearchPath::from_sysroot_and_triple(&sysroot, host_triple);
1118+
let target_tlib_path = if host_triple == target_triple {
1119+
None
1120+
} else {
1121+
Some(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
1122+
};
1123+
11091124
let file_path_mapping = sopts.file_path_mapping();
11101125

11111126
let local_crate_source_file =
@@ -1134,6 +1149,8 @@ pub fn build_session_(
11341149
target: target_cfg,
11351150
host,
11361151
opts: sopts,
1152+
host_tlib_path,
1153+
target_tlib_path,
11371154
parse_sess: p_s,
11381155
// For a library crate, this is always none
11391156
entry_fn: Once::new(),

src/librustc/session/search_paths.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use session::filesearch::make_target_lib_path;
1616
pub struct SearchPath {
1717
pub kind: PathKind,
1818
pub dir: PathBuf,
19+
pub files: Vec<PathBuf>,
1920
}
2021

2122
#[derive(Eq, PartialEq, Clone, Copy, Debug, PartialOrd, Ord, Hash)]
@@ -65,7 +66,18 @@ impl SearchPath {
6566
}
6667

6768
fn new(kind: PathKind, dir: PathBuf) -> Self {
68-
SearchPath { kind, dir }
69+
// Get the files within the directory.
70+
let files = match std::fs::read_dir(&dir) {
71+
Ok(files) => {
72+
files.filter_map(|p| {
73+
p.ok().map(|s| s.path())
74+
})
75+
.collect::<Vec<_>>()
76+
}
77+
Err(..) => vec![],
78+
};
79+
80+
SearchPath { kind, dir, files }
6981
}
7082
}
7183

0 commit comments

Comments
 (0)