about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicholas Nethercote <nnethercote@mozilla.com>2018-11-20 11:06:45 +1100
committerNicholas Nethercote <nnethercote@mozilla.com>2018-12-12 10:36:15 +1100
commit2bfe32cc9301d404c98d896efbabe8f04361d5bf (patch)
tree667bba60d155cb2d2eca50df9e66165f34be7735 /src
parentf13006182c9df451e7703307467fc1717239cf6e (diff)
downloadrust-2bfe32cc9301d404c98d896efbabe8f04361d5bf.tar.gz
rust-2bfe32cc9301d404c98d896efbabe8f04361d5bf.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/session/filesearch.rs34
-rw-r--r--src/librustc/session/mod.rs19
-rw-r--r--src/librustc/session/search_paths.rs14
3 files changed, 42 insertions, 25 deletions
diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs
index 6f52d285353..6bfed4fbf5a 100644
--- a/src/librustc/session/filesearch.rs
+++ b/src/librustc/session/filesearch.rs
@@ -12,7 +12,6 @@
 
 pub use self::FileMatch::*;
 
-use rustc_data_structures::fx::FxHashSet;
 use std::borrow::Cow;
 use std::env;
 use std::fs;
@@ -31,8 +30,9 @@ pub enum FileMatch {
 
 pub struct FileSearch<'a> {
     pub sysroot: &'a Path,
-    pub search_paths: &'a [SearchPath],
     pub triple: &'a str,
+    pub search_paths: &'a [SearchPath],
+    pub tlib_path: &'a SearchPath,
     pub kind: PathKind,
 }
 
@@ -40,20 +40,12 @@ impl<'a> FileSearch<'a> {
     pub fn for_each_lib_search_path<F>(&self, mut f: F) where
         F: FnMut(&SearchPath)
     {
-        let mut visited_dirs = FxHashSet::default();
-        visited_dirs.reserve(self.search_paths.len() + 1);
         let iter = self.search_paths.iter().filter(|sp| sp.kind.matches(self.kind));
         for search_path in iter {
             f(search_path);
-            visited_dirs.insert(search_path.dir.to_path_buf());
         }
 
-        debug!("filesearch: searching lib path");
-        let tlib_path = make_target_lib_path(self.sysroot,
-                                             self.triple);
-        if !visited_dirs.contains(&tlib_path) {
-            f(&SearchPath { kind: PathKind::All, dir: tlib_path });
-        }
+        f(self.tlib_path);
     }
 
     pub fn get_lib_path(&self) -> PathBuf {
@@ -65,12 +57,6 @@ impl<'a> FileSearch<'a> {
     {
         self.for_each_lib_search_path(|search_path| {
             debug!("searching {}", search_path.dir.display());
-            let files = match fs::read_dir(&search_path.dir) {
-                Ok(files) => files,
-                Err(..) => return,
-            };
-            let files = files.filter_map(|p| p.ok().map(|s| s.path()))
-                             .collect::<Vec<_>>();
             fn is_rlib(p: &Path) -> bool {
                 p.extension() == Some("rlib".as_ref())
             }
@@ -78,8 +64,8 @@ impl<'a> FileSearch<'a> {
             // an rlib and a dylib we only read one of the files of
             // metadata, so in the name of speed, bring all rlib files to
             // the front of the search list.
-            let files1 = files.iter().filter(|p| is_rlib(p));
-            let files2 = files.iter().filter(|p| !is_rlib(p));
+            let files1 = search_path.files.iter().filter(|p| is_rlib(p));
+            let files2 = search_path.files.iter().filter(|p| !is_rlib(p));
             for path in files1.chain(files2) {
                 debug!("testing {}", path.display());
                 let maybe_picked = pick(path, search_path.kind);
@@ -98,12 +84,15 @@ impl<'a> FileSearch<'a> {
     pub fn new(sysroot: &'a Path,
                triple: &'a str,
                search_paths: &'a Vec<SearchPath>,
-               kind: PathKind) -> FileSearch<'a> {
+               tlib_path: &'a SearchPath,
+               kind: PathKind)
+               -> FileSearch<'a> {
         debug!("using sysroot = {}, triple = {}", sysroot.display(), triple);
         FileSearch {
             sysroot,
-            search_paths,
             triple,
+            search_paths,
+            tlib_path,
             kind,
         }
     }
@@ -137,8 +126,7 @@ pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf
     p
 }
 
-pub fn make_target_lib_path(sysroot: &Path,
-                        target_triple: &str) -> PathBuf {
+pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
     sysroot.join(&relative_target_lib_path(sysroot, target_triple))
 }
 
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 56a57b5375f..12b5646e7f1 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -19,8 +19,8 @@ use lint;
 use lint::builtin::BuiltinLintDiagnostics;
 use middle::allocator::AllocatorKind;
 use middle::dependency_format;
-use session::search_paths::PathKind;
 use session::config::{OutputType, Lto};
+use session::search_paths::{PathKind, SearchPath};
 use util::nodemap::{FxHashMap, FxHashSet};
 use util::common::{duration_to_secs_str, ErrorReported};
 use util::common::ProfileQueriesMsg;
@@ -64,6 +64,9 @@ pub struct Session {
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
+    pub host_tlib_path: SearchPath,
+    /// This is `None` if the host and target are the same.
+    pub target_tlib_path: Option<SearchPath>,
     pub parse_sess: ParseSess,
     /// For a library crate, this is always none
     pub entry_fn: Once<Option<(NodeId, Span, config::EntryFnType)>>,
@@ -699,6 +702,8 @@ impl Session {
             &self.sysroot,
             self.opts.target_triple.triple(),
             &self.opts.search_paths,
+            // target_tlib_path==None means it's the same as host_tlib_path.
+            self.target_tlib_path.as_ref().unwrap_or(&self.host_tlib_path),
             kind,
         )
     }
@@ -707,6 +712,7 @@ impl Session {
             &self.sysroot,
             config::host_triple(),
             &self.opts.search_paths,
+            &self.host_tlib_path,
             kind,
         )
     }
@@ -1106,6 +1112,15 @@ pub fn build_session_(
         None => filesearch::get_or_default_sysroot(),
     };
 
+    let host_triple = config::host_triple();
+    let target_triple = sopts.target_triple.triple();
+    let host_tlib_path = SearchPath::from_sysroot_and_triple(&sysroot, host_triple);
+    let target_tlib_path = if host_triple == target_triple {
+        None
+    } else {
+        Some(SearchPath::from_sysroot_and_triple(&sysroot, target_triple))
+    };
+
     let file_path_mapping = sopts.file_path_mapping();
 
     let local_crate_source_file =
@@ -1134,6 +1149,8 @@ pub fn build_session_(
         target: target_cfg,
         host,
         opts: sopts,
+        host_tlib_path,
+        target_tlib_path,
         parse_sess: p_s,
         // For a library crate, this is always none
         entry_fn: Once::new(),
diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs
index 7a0bd2ed439..5c44a07f843 100644
--- a/src/librustc/session/search_paths.rs
+++ b/src/librustc/session/search_paths.rs
@@ -16,6 +16,7 @@ use session::filesearch::make_target_lib_path;
 pub struct SearchPath {
     pub kind: PathKind,
     pub dir: PathBuf,
+    pub files: Vec<PathBuf>,
 }
 
 #[derive(Eq, PartialEq, Clone, Copy, Debug, PartialOrd, Ord, Hash)]
@@ -65,7 +66,18 @@ impl SearchPath {
     }
 
     fn new(kind: PathKind, dir: PathBuf) -> Self {
-        SearchPath { kind, dir }
+        // Get the files within the directory.
+        let files = match std::fs::read_dir(&dir) {
+            Ok(files) => {
+                files.filter_map(|p| {
+                    p.ok().map(|s| s.path())
+                })
+                .collect::<Vec<_>>()
+            }
+            Err(..) => vec![],
+        };
+
+        SearchPath { kind, dir, files }
     }
 }