Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
270
third-party/vendor/loom/src/model.rs
vendored
Normal file
270
third-party/vendor/loom/src/model.rs
vendored
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
//! Model concurrent programs.
|
||||
|
||||
use crate::rt::{self, Execution, Scheduler};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use tracing::{info, subscriber};
|
||||
use tracing_subscriber::{fmt, EnvFilter};
|
||||
|
||||
const DEFAULT_MAX_THREADS: usize = 4;
|
||||
const DEFAULT_MAX_BRANCHES: usize = 1_000;
|
||||
|
||||
/// Configure a model
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive] // Support adding more fields in the future
|
||||
pub struct Builder {
|
||||
/// Max number of threads to check as part of the execution.
|
||||
///
|
||||
/// This should be set as low as possible and must be less than
|
||||
/// [`MAX_THREADS`](crate::MAX_THREADS).
|
||||
pub max_threads: usize,
|
||||
|
||||
/// Maximum number of thread switches per permutation.
|
||||
///
|
||||
/// Defaults to `LOOM_MAX_BRANCHES` environment variable.
|
||||
pub max_branches: usize,
|
||||
|
||||
/// Maximum number of permutations to explore.
|
||||
///
|
||||
/// Defaults to `LOOM_MAX_PERMUTATIONS` environment variable.
|
||||
pub max_permutations: Option<usize>,
|
||||
|
||||
/// Maximum amount of time to spend on checking
|
||||
///
|
||||
/// Defaults to `LOOM_MAX_DURATION` environment variable.
|
||||
pub max_duration: Option<Duration>,
|
||||
|
||||
/// Maximum number of thread preemptions to explore
|
||||
///
|
||||
/// Defaults to `LOOM_MAX_PREEMPTIONS` environment variable.
|
||||
pub preemption_bound: Option<usize>,
|
||||
|
||||
/// When doing an exhaustive check, uses the file to store and load the
|
||||
/// check progress
|
||||
///
|
||||
/// Defaults to `LOOM_CHECKPOINT_FILE` environment variable.
|
||||
pub checkpoint_file: Option<PathBuf>,
|
||||
|
||||
/// How often to write the checkpoint file
|
||||
///
|
||||
/// Defaults to `LOOM_CHECKPOINT_INTERVAL` environment variable.
|
||||
pub checkpoint_interval: usize,
|
||||
|
||||
/// When `true`, locations are captured on each loom operation.
|
||||
///
|
||||
/// Note that is is **very** expensive. It is recommended to first isolate a
|
||||
/// failing iteration using `LOOM_CHECKPOINT_FILE`, then enable location
|
||||
/// tracking.
|
||||
///
|
||||
/// Defaults to `LOOM_LOCATION` environment variable.
|
||||
pub location: bool,
|
||||
|
||||
/// Log execution output to stdout.
|
||||
///
|
||||
/// Defaults to existence of `LOOM_LOG` environment variable.
|
||||
pub log: bool,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
/// Create a new `Builder` instance with default values.
|
||||
pub fn new() -> Builder {
|
||||
use std::env;
|
||||
|
||||
let checkpoint_interval = env::var("LOOM_CHECKPOINT_INTERVAL")
|
||||
.map(|v| {
|
||||
v.parse()
|
||||
.expect("invalid value for `LOOM_CHECKPOINT_INTERVAL`")
|
||||
})
|
||||
.unwrap_or(20_000);
|
||||
|
||||
let max_branches = env::var("LOOM_MAX_BRANCHES")
|
||||
.map(|v| v.parse().expect("invalid value for `LOOM_MAX_BRANCHES`"))
|
||||
.unwrap_or(DEFAULT_MAX_BRANCHES);
|
||||
|
||||
let location = env::var("LOOM_LOCATION").is_ok();
|
||||
|
||||
let log = env::var("LOOM_LOG").is_ok();
|
||||
|
||||
let max_duration = env::var("LOOM_MAX_DURATION")
|
||||
.map(|v| {
|
||||
let secs = v.parse().expect("invalid value for `LOOM_MAX_DURATION`");
|
||||
Duration::from_secs(secs)
|
||||
})
|
||||
.ok();
|
||||
|
||||
let max_permutations = env::var("LOOM_MAX_PERMUTATIONS")
|
||||
.map(|v| {
|
||||
v.parse()
|
||||
.expect("invalid value for `LOOM_MAX_PERMUTATIONS`")
|
||||
})
|
||||
.ok();
|
||||
|
||||
let preemption_bound = env::var("LOOM_MAX_PREEMPTIONS")
|
||||
.map(|v| v.parse().expect("invalid value for `LOOM_MAX_PREEMPTIONS`"))
|
||||
.ok();
|
||||
|
||||
let checkpoint_file = env::var("LOOM_CHECKPOINT_FILE")
|
||||
.map(|v| v.parse().expect("invalid value for `LOOM_CHECKPOINT_FILE`"))
|
||||
.ok();
|
||||
|
||||
Builder {
|
||||
max_threads: DEFAULT_MAX_THREADS,
|
||||
max_branches,
|
||||
max_duration,
|
||||
max_permutations,
|
||||
preemption_bound,
|
||||
checkpoint_file,
|
||||
checkpoint_interval,
|
||||
location,
|
||||
log,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the checkpoint file.
|
||||
pub fn checkpoint_file(&mut self, file: &str) -> &mut Self {
|
||||
self.checkpoint_file = Some(file.into());
|
||||
self
|
||||
}
|
||||
|
||||
/// Check the provided model.
|
||||
pub fn check<F>(&self, f: F)
|
||||
where
|
||||
F: Fn() + Sync + Send + 'static,
|
||||
{
|
||||
let mut i = 1;
|
||||
let mut _span = tracing::info_span!("iter", message = i).entered();
|
||||
|
||||
let mut execution =
|
||||
Execution::new(self.max_threads, self.max_branches, self.preemption_bound);
|
||||
let mut scheduler = Scheduler::new(self.max_threads);
|
||||
|
||||
if let Some(ref path) = self.checkpoint_file {
|
||||
if path.exists() {
|
||||
execution.path = checkpoint::load_execution_path(path);
|
||||
execution.path.set_max_branches(self.max_branches);
|
||||
}
|
||||
}
|
||||
|
||||
execution.log = self.log;
|
||||
execution.location = self.location;
|
||||
|
||||
let f = Arc::new(f);
|
||||
|
||||
let start = Instant::now();
|
||||
loop {
|
||||
if i % self.checkpoint_interval == 0 {
|
||||
info!(parent: None, "");
|
||||
info!(
|
||||
parent: None,
|
||||
" ================== Iteration {} ==================", i
|
||||
);
|
||||
info!(parent: None, "");
|
||||
|
||||
if let Some(ref path) = self.checkpoint_file {
|
||||
checkpoint::store_execution_path(&execution.path, path);
|
||||
}
|
||||
|
||||
if let Some(max_permutations) = self.max_permutations {
|
||||
if i >= max_permutations {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(max_duration) = self.max_duration {
|
||||
if start.elapsed() >= max_duration {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let f = f.clone();
|
||||
|
||||
scheduler.run(&mut execution, move || {
|
||||
f();
|
||||
|
||||
let lazy_statics = rt::execution(|execution| execution.lazy_statics.drop());
|
||||
|
||||
// drop outside of execution
|
||||
drop(lazy_statics);
|
||||
|
||||
rt::thread_done();
|
||||
});
|
||||
|
||||
execution.check_for_leaks();
|
||||
|
||||
i += 1;
|
||||
|
||||
// Create the next iteration's `tracing` span before trying to step to the next
|
||||
// execution, as the `Execution` will capture the current span when
|
||||
// it's reset.
|
||||
_span = tracing::info_span!(parent: None, "iter", message = i).entered();
|
||||
if let Some(next) = execution.step() {
|
||||
execution = next;
|
||||
} else {
|
||||
info!(parent: None, "Completed in {} iterations", i - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Run all concurrent permutations of the provided closure.
|
||||
///
|
||||
/// Uses a default [`Builder`](crate::model::Builder) which can be affected
|
||||
/// by environment variables.
|
||||
pub fn model<F>(f: F)
|
||||
where
|
||||
F: Fn() + Sync + Send + 'static,
|
||||
{
|
||||
let subscriber = fmt::Subscriber::builder()
|
||||
.with_env_filter(EnvFilter::from_env("LOOM_LOG"))
|
||||
.with_test_writer()
|
||||
.without_time()
|
||||
.finish();
|
||||
|
||||
subscriber::with_default(subscriber, || {
|
||||
Builder::new().check(f);
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "checkpoint")]
|
||||
mod checkpoint {
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) fn load_execution_path(fs_path: &Path) -> crate::rt::Path {
|
||||
let mut file = File::open(fs_path).unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
serde_json::from_str(&contents).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn store_execution_path(path: &crate::rt::Path, fs_path: &Path) {
|
||||
let serialized = serde_json::to_string(path).unwrap();
|
||||
|
||||
let mut file = File::create(fs_path).unwrap();
|
||||
file.write_all(serialized.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "checkpoint"))]
|
||||
mod checkpoint {
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) fn load_execution_path(_fs_path: &Path) -> crate::rt::Path {
|
||||
panic!("not compiled with `checkpoint` feature")
|
||||
}
|
||||
|
||||
pub(crate) fn store_execution_path(_path: &crate::rt::Path, _fs_path: &Path) {
|
||||
panic!("not compiled with `checkpoint` feature")
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue