From 225140ed216d7395530b2e4597fb224305e6375b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 29 Nov 2018 15:02:06 -0800 Subject: [PATCH] Optimize local linkchecker program I noticed on a [recent build][1] that the linkchecker stage of CI took a whopping 15 minutes of CI time for something that should be near instantaneous. Some local profiling showed some very hot functions and clones which were pretty easy to remove, and now instead of running in minutes locally it runs in seconds. [1]: https://ci.appveyor.com/project/rust-lang/rust/build/job/kptifw1kb1nm4xuu --- src/tools/linkchecker/main.rs | 38 +++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index ca7e0224dc328..11c83819eaa93 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -24,12 +24,12 @@ //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc, //! but this should catch the majority of "broken link" cases. +use std::collections::hash_map::Entry; +use std::collections::{HashMap, HashSet}; use std::env; -use std::fs::File; -use std::io::prelude::*; +use std::fs; use std::path::{Path, PathBuf, Component}; -use std::collections::{HashMap, HashSet}; -use std::collections::hash_map::Entry; +use std::rc::Rc; use Redirect::*; @@ -63,7 +63,7 @@ enum Redirect { } struct FileEntry { - source: String, + source: Rc, ids: HashSet, } @@ -113,7 +113,7 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { let entry = cache.get_mut(&pretty_path).unwrap(); // we don't need the source anymore, // so drop to reduce memory-usage - entry.source = String::new(); + entry.source = Rc::new(String::new()); } } } @@ -287,24 +287,24 @@ fn load_file(cache: &mut Cache, root: &Path, file: &Path, redirect: Redirect) - -> Result<(PathBuf, String), LoadError> { - let mut contents = String::new(); + -> Result<(PathBuf, Rc), LoadError> { let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file)); - let maybe_redirect = match cache.entry(pretty_file.clone()) { + let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) { Entry::Occupied(entry) => { - contents = entry.get().source.clone(); - None + (None, entry.get().source.clone()) } Entry::Vacant(entry) => { - let mut fp = File::open(file).map_err(|err| { - if let FromRedirect(true) = redirect { - LoadError::BrokenRedirect(file.to_path_buf(), err) - } else { - LoadError::IOError(err) + let contents = match fs::read_to_string(file) { + Ok(s) => Rc::new(s), + Err(err) => { + return Err(if let FromRedirect(true) = redirect { + LoadError::BrokenRedirect(file.to_path_buf(), err) + } else { + LoadError::IOError(err) + }) } - })?; - fp.read_to_string(&mut contents).map_err(|err| LoadError::IOError(err))?; + }; let maybe = maybe_redirect(&contents); if maybe.is_some() { @@ -317,7 +317,7 @@ fn load_file(cache: &mut Cache, ids: HashSet::new(), }); } - maybe + (maybe, contents) } }; match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {