Skip to content

Commit

Permalink
feat(testclient): immediately compile a test index and clean after th…
Browse files Browse the repository at this point in the history
…e test finishes.
  • Loading branch information
dnbln committed Feb 4, 2024
1 parent f70b7dc commit 1949308
Show file tree
Hide file tree
Showing 7 changed files with 388 additions and 6 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Unreleased

## Create an index right after a test finishes

With the `compile-index-and-clean` feature of the testclient,
it can invoke `cargo-difftests` to create an index immediately
after writing the profile, and then cleaning the intermediate
profiling data. This only happens if the testclient is configured
to do so (see `DifftestsEnv::and_compile_index_and_clean_on_exit`).

This, together with the tiny indexes feature released in `0.5.0`,
have the effect of a huge reduction in the on-disk space required
to store profiling data, only a couple KBs/test (depending on project
of course; on the sample project, the average is somewhere around 700
bytes / test).

# 0.5.0

Released: 2023-02-03
Expand Down
1 change: 1 addition & 0 deletions cargo-difftests-testclient/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ default = ["enforce-single-running-test", "groups", "parallel-groups"]
enforce-single-running-test = []
groups = ["enforce-single-running-test", "cargo-difftests-core/groups"]
parallel-groups = ["groups"]
compile-index-and-clean = []

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand Down
208 changes: 208 additions & 0 deletions cargo-difftests-testclient/src/compile_index_and_clean_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
use std::path::PathBuf;

pub struct CompileIndexAndCleanConfig {
difftests_dir: PathBuf,
index_resolver: IndexResolver,
other_bins: Vec<PathBuf>,
flatten_files_to: Option<FlattenFilesToTarget>,
remove_bin_path: bool,
full_index: bool,
#[cfg(windows)]
path_slash_replace: bool,
}

pub enum FlattenFilesToTarget {
RepoRoot,
}

enum IndexResolver {
FromRoots {
index_root: PathBuf,
difftests_root: PathBuf,
},
Path {
index_path: PathBuf,
},
}

pub struct CompileIndexAndCleanConfigBuilder {
difftests_dir: PathBuf,
index_resolver: Option<IndexResolver>,
other_bins: Vec<PathBuf>,
flatten_files_to: Option<FlattenFilesToTarget>,
remove_bin_path: bool,
full_index: bool,
#[cfg(windows)]
path_slash_replace: bool,
}

impl CompileIndexAndCleanConfigBuilder {
pub fn new(difftests_dir: PathBuf) -> Self {
Self {
difftests_dir,
index_resolver: None,
other_bins: Vec::new(),
flatten_files_to: None,
remove_bin_path: true,
full_index: false,
#[cfg(windows)]
path_slash_replace: true,
}
}

pub fn index_path(mut self, index_path: impl Into<PathBuf>) -> Self {
match &mut self.index_resolver {
Some(_) => panic!("index_path or roots already set"),
None => {
self.index_resolver = Some(IndexResolver::Path {
index_path: index_path.into(),
});
}
}
self
}

pub fn roots(mut self, index_root: impl Into<PathBuf>, difftests_root: impl Into<PathBuf>) -> Self {
match &mut self.index_resolver {
Some(_) => panic!("index_path or roots already set"),
None => {
self.index_resolver = Some(IndexResolver::FromRoots {
index_root: index_root.into(),
difftests_root: difftests_root.into(),
});
}
}
self
}

pub fn other_bins(mut self, other_bins: impl IntoIterator<Item = PathBuf>) -> Self {
self.other_bins.extend(other_bins);
self
}

pub fn flatten_files_to(
mut self,
flatten_files_to: impl Into<Option<FlattenFilesToTarget>>,
) -> Self {
self.flatten_files_to = flatten_files_to.into();
self
}

pub fn remove_bin_path(mut self, remove_bin_path: bool) -> Self {
self.remove_bin_path = remove_bin_path;
self
}

pub fn full_index(mut self, full_index: bool) -> Self {
self.full_index = full_index;
self
}

#[cfg(windows)]
pub fn path_slash_replace(mut self, path_slash_replace: bool) -> Self {
self.path_slash_replace = path_slash_replace;
self
}

#[track_caller]
pub fn build(self) -> CompileIndexAndCleanConfig {
CompileIndexAndCleanConfig {
difftests_dir: self.difftests_dir,
index_resolver: self.index_resolver.unwrap(),
other_bins: self.other_bins,
flatten_files_to: self.flatten_files_to,
remove_bin_path: self.remove_bin_path,
full_index: self.full_index,
#[cfg(windows)]
path_slash_replace: self.path_slash_replace,
}
}
}

pub fn do_build_index_and_clean(config: &CompileIndexAndCleanConfig) -> std::io::Result<()> {
let mut cmd = std::process::Command::new(env!("CARGO"));

cmd.args(&[
"difftests",
"low-level",
"test-client-compile-test-index-and-clean",
]);

cmd.arg("--dir").arg(&config.difftests_dir);

match &config.index_resolver {
IndexResolver::FromRoots {
index_root,
difftests_root,
} => {
cmd.arg("--index-root").arg(index_root);
cmd.arg("--root").arg(difftests_root);
cmd.arg("--output").arg("resolve");
}
IndexResolver::Path { index_path } => {
cmd.arg("--output").arg(index_path);
}
}

if let Some(flatten_files_to) = &config.flatten_files_to {
match flatten_files_to {
FlattenFilesToTarget::RepoRoot => {
cmd.arg("--flatten-files-to=repo-root");
}
}
}

if !config.remove_bin_path {
cmd.arg("--no-remove-bin-path");
}

if config.full_index {
cmd.arg("--full-index");
}

#[cfg(windows)]
{
if !config.path_slash_replace {
cmd.arg("--no-path-slash-replace");
}
}

for bin in &config.other_bins {
cmd.arg("--bin").arg(bin);
}

cmd.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped());

let output = cmd.output()?;

if !output.status.success() {
use std::io::Write;

println!("cargo-difftests test-client-compile-test-index-and-clean stdout:");
std::io::stdout().write_all(&output.stdout)?;
eprintln!("cargo-difftests test-client-compile-test-index-and-clean stderr:");
std::io::stderr().write_all(&output.stderr)?;

return Err(std::io::Error::new(
std::io::ErrorKind::Other,
"cargo difftests low-level compile-test-index failed",
));
}

Ok(())
}

pub struct RunOnDrop(CompileIndexAndCleanConfig);

impl RunOnDrop {
pub fn new(config: CompileIndexAndCleanConfig) -> Self {
Self(config)
}
}

impl Drop for RunOnDrop {
fn drop(&mut self) {
do_build_index_and_clean(&self.0).unwrap();
}
}
46 changes: 45 additions & 1 deletion cargo-difftests-testclient/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ impl Drop for SelfProfileWriter {
}
}

#[cfg(feature = "compile-index-and-clean")]
pub mod compile_index_and_clean_config;

enum DifftestsEnvInner {
Test {
#[allow(dead_code)]
Expand All @@ -70,9 +73,15 @@ enum DifftestsEnvInner {
not(feature = "parallel-groups")
))]
_t_lock: std::sync::MutexGuard<'static, ()>,

#[cfg(feature = "compile-index-and-clean")]
compile_index_and_clean: Option<compile_index_and_clean_config::RunOnDrop>,

#[cfg(feature = "compile-index-and-clean")]
self_dir: PathBuf,
},
#[cfg(feature = "groups")]
Group(groups::GroupDifftestsEnv),
Group(#[allow(dead_code)] groups::GroupDifftestsEnv),
}

#[cfg(feature = "parallel-groups")]
Expand Down Expand Up @@ -118,6 +127,35 @@ impl DifftestsEnv {
self.llvm_profile_file_value.as_os_str(),
))
}

#[cfg(feature = "compile-index-and-clean")]
pub fn and_compile_index_and_clean_on_exit(
mut self,
f: impl FnOnce(
compile_index_and_clean_config::CompileIndexAndCleanConfigBuilder,
) -> compile_index_and_clean_config::CompileIndexAndCleanConfigBuilder,
) -> Self {
match &mut self.difftests_env_inner {
DifftestsEnvInner::Test {
compile_index_and_clean,
self_dir,
..
} => {
let c = compile_index_and_clean_config::CompileIndexAndCleanConfigBuilder::new(
self_dir.clone(),
);
let c = f(c);
*compile_index_and_clean = Some(compile_index_and_clean_config::RunOnDrop::new(c.build()));
}
DifftestsEnvInner::Group { .. } => {
panic!(
"and_compile_index_on_exit can only be called in a non-group test environment"
);
}
}

self
}
}

/// Initializes the difftests environment.
Expand Down Expand Up @@ -177,6 +215,12 @@ pub fn init<T: serde::Serialize>(
not(feature = "parallel-groups")
))]
_t_lock,

#[cfg(feature = "compile-index-and-clean")]
compile_index_and_clean: None,

#[cfg(feature = "compile-index-and-clean")]
self_dir: tmpdir.to_path_buf(),
},
});

Expand Down
Loading

0 comments on commit 1949308

Please sign in to comment.