diff options
Diffstat (limited to '')
-rw-r--r-- | benches/benchsuite/src/lib.rs | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/benches/benchsuite/src/lib.rs b/benches/benchsuite/src/lib.rs new file mode 100644 index 0000000..42e0f51 --- /dev/null +++ b/benches/benchsuite/src/lib.rs @@ -0,0 +1,197 @@ +use cargo::Config; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; +use url::Url; + +#[macro_export] +macro_rules! fixtures { + () => { + $crate::Fixtures::new(env!("CARGO_TARGET_TMPDIR")) + }; +} + +// This is an arbitrary commit that existed when I started. This helps +// ensure consistent results. It can be updated if needed, but that can +// make it harder to compare results with older versions of cargo. +const CRATES_IO_COMMIT: &str = "85f7bfd61ea4fee08ec68c468762e886b2aebec6"; + +pub struct Fixtures { + cargo_target_tmpdir: PathBuf, +} + +impl Fixtures { + pub fn new(cargo_target_tmpdir: &str) -> Self { + let bench = Self { + cargo_target_tmpdir: PathBuf::from(cargo_target_tmpdir), + }; + bench.create_home(); + bench.create_target_dir(); + bench.clone_index(); + bench.unpack_workspaces(); + bench + } + + fn root(&self) -> PathBuf { + self.cargo_target_tmpdir.join("bench") + } + + fn target_dir(&self) -> PathBuf { + let mut p = self.root(); + p.push("target"); + p + } + + fn cargo_home(&self) -> PathBuf { + let mut p = self.root(); + p.push("chome"); + p + } + + fn index(&self) -> PathBuf { + let mut p = self.root(); + p.push("index"); + p + } + + fn workspaces_path(&self) -> PathBuf { + let mut p = self.root(); + p.push("workspaces"); + p + } + + fn registry_url(&self) -> Url { + Url::from_file_path(self.index()).unwrap() + } + + fn create_home(&self) { + let home = self.cargo_home(); + if !home.exists() { + fs::create_dir_all(&home).unwrap(); + } + fs::write( + home.join("config.toml"), + format!( + r#" + [source.crates-io] + replace-with = 'local-snapshot' + + [source.local-snapshot] + registry = '{}' + "#, + self.registry_url() + ), + ) + .unwrap(); + } + + fn create_target_dir(&self) { + // This is necessary to ensure the .rustc_info.json file is written. + // Otherwise it won't be written, and it is very expensive to create. + if !self.target_dir().exists() { + fs::create_dir_all(self.target_dir()).unwrap(); + } + } + + /// This clones crates.io at a specific point in time into tmp/index. + fn clone_index(&self) { + let index = self.index(); + let maybe_git = |command: &str| { + let status = Command::new("git") + .current_dir(&index) + .args(command.split_whitespace().collect::<Vec<_>>()) + .status() + .expect("git should be installed"); + status.success() + }; + let git = |command: &str| { + if !maybe_git(command) { + panic!("failed to run git command: {}", command); + } + }; + if index.exists() { + if maybe_git(&format!( + "rev-parse -q --verify {}^{{commit}}", + CRATES_IO_COMMIT + )) { + // Already fetched. + return; + } + } else { + fs::create_dir_all(&index).unwrap(); + git("init --bare"); + git("remote add origin https://github.com/rust-lang/crates.io-index"); + } + git(&format!("fetch origin {}", CRATES_IO_COMMIT)); + git("branch -f master FETCH_HEAD"); + } + + /// This unpacks the compressed workspace skeletons into tmp/workspaces. + fn unpack_workspaces(&self) { + let ws_dir = Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .join("workspaces"); + let archives = fs::read_dir(ws_dir) + .unwrap() + .map(|e| e.unwrap().path()) + .filter(|p| p.extension() == Some(std::ffi::OsStr::new("tgz"))); + for archive in archives { + let name = archive.file_stem().unwrap(); + let f = fs::File::open(&archive).unwrap(); + let f = flate2::read::GzDecoder::new(f); + let dest = self.workspaces_path().join(&name); + if dest.exists() { + fs::remove_dir_all(&dest).unwrap(); + } + let mut archive = tar::Archive::new(f); + archive.unpack(self.workspaces_path()).unwrap(); + } + } + + /// Vec of `(ws_name, ws_root)`. + pub fn workspaces(&self) -> Vec<(String, PathBuf)> { + // CARGO_BENCH_WORKSPACES can be used to override, otherwise it just uses + // the workspaces in the workspaces directory. + let mut ps: Vec<_> = match std::env::var_os("CARGO_BENCH_WORKSPACES") { + Some(s) => std::env::split_paths(&s).collect(), + None => fs::read_dir(self.workspaces_path()) + .unwrap() + .map(|e| e.unwrap().path()) + // These currently fail in most cases on Windows due to long + // filenames in the git checkouts. + .filter(|p| { + !(cfg!(windows) + && matches!(p.file_name().unwrap().to_str().unwrap(), "servo" | "tikv")) + }) + .collect(), + }; + // Sort so it is consistent. + ps.sort(); + ps.into_iter() + .map(|p| (p.file_name().unwrap().to_str().unwrap().to_owned(), p)) + .collect() + } + + /// Creates a new Config. + pub fn make_config(&self, ws_root: &Path) -> Config { + let shell = cargo::core::Shell::new(); + let mut config = Config::new(shell, ws_root.to_path_buf(), self.cargo_home()); + // Configure is needed to set the target_dir which is needed to write + // the .rustc_info.json file which is very expensive. + config + .configure( + 0, + false, + None, + false, + false, + false, + &Some(self.target_dir()), + &[], + &[], + ) + .unwrap(); + config + } +} |