diff --git a/Cargo.lock b/Cargo.lock index 801d2ab8ef..31c9b56548 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1980,7 +1980,6 @@ dependencies = [ "rayon", "serde", "sha2", - "spin", "target-lexicon", "tempfile", "thiserror", diff --git a/crates/api/src/runtime.rs b/crates/api/src/runtime.rs index 7bc5edaf65..199cf32450 100644 --- a/crates/api/src/runtime.rs +++ b/crates/api/src/runtime.rs @@ -1,9 +1,11 @@ use anyhow::Result; use std::cell::RefCell; use std::fmt; +use std::path::Path; use std::rc::Rc; use std::sync::Arc; use wasmtime_environ::settings::{self, Configurable}; +use wasmtime_environ::CacheConfig; use wasmtime_jit::{native, CompilationStrategy, Compiler, Features}; // Runtime Environment @@ -21,6 +23,7 @@ pub struct Config { pub(crate) features: Features, pub(crate) debug_info: bool, pub(crate) strategy: CompilationStrategy, + pub(crate) cache_config: CacheConfig, } impl Config { @@ -45,6 +48,7 @@ impl Config { features: Default::default(), flags, strategy: CompilationStrategy::Auto, + cache_config: CacheConfig::new_cache_disabled(), } } @@ -221,6 +225,49 @@ impl Config { .expect("should be valid flag"); self } + + /// Loads cache configuration specified at `path`. + /// + /// This method will read the file specified by `path` on the filesystem and + /// attempt to load cache configuration from it. This method can also fail + /// due to I/O errors, misconfiguration, syntax errors, etc. For expected + /// syntax in the configuration file see the [documentation online][docs]. + /// + /// By default cache configuration is not enabled or loaded. + /// + /// # Errors + /// + /// This method can fail due to any error that happens when loading the file + /// pointed to by `path` and attempting to load the cache configuration. + /// + /// [docs]: https://bytecodealliance.github.io/wasmtime/cli-cache.html + pub fn cache_config_load(&mut self, path: impl AsRef) -> Result<&mut Self> { + self.cache_config = wasmtime_environ::CacheConfig::from_file(Some(path.as_ref()))?; + Ok(self) + } + + /// Loads cache configuration from the system default path. + /// + /// This commit is the same as [`Config::cache_config_load`] except that it + /// does not take a path argument and instead loads the default + /// configuration present on the system. This is located, for example, on + /// Unix at `$HOME/.config/wasmtime/config.toml` and is typically created + /// with the `wasmtime config new` command. + /// + /// By default cache configuration is not enabled or loaded. + /// + /// # Errors + /// + /// This method can fail due to any error that happens when loading the + /// default system configuration. Note that it is not an error if the + /// default config file does not exist, in which case the default settings + /// for an enabled cache are applied. + /// + /// [docs]: https://bytecodealliance.github.io/wasmtime/cli-cache.html + pub fn cache_config_load_default(&mut self) -> Result<&mut Self> { + self.cache_config = wasmtime_environ::CacheConfig::from_file(None)?; + Ok(self) + } } impl Default for Config { @@ -364,7 +411,11 @@ impl Store { /// Creates a new store to be associated with the given [`Engine`]. pub fn new(engine: &Engine) -> Store { let isa = native::builder().finish(settings::Flags::new(engine.config.flags.clone())); - let compiler = Compiler::new(isa, engine.config.strategy); + let compiler = Compiler::new( + isa, + engine.config.strategy, + engine.config.cache_config.clone(), + ); Store { inner: Rc::new(StoreInner { engine: engine.clone(), diff --git a/crates/environ/Cargo.toml b/crates/environ/Cargo.toml index 331a7e0147..d4d8867c37 100644 --- a/crates/environ/Cargo.toml +++ b/crates/environ/Cargo.toml @@ -27,7 +27,6 @@ base64 = "0.11.0" serde = { version = "1.0.94", features = ["derive"] } bincode = "1.1.4" lazy_static = "1.3.0" -spin = "0.5.0" log = { version = "0.4.8", default-features = false } zstd = "0.5" toml = "0.5.5" diff --git a/crates/environ/src/cache.rs b/crates/environ/src/cache.rs index 57861433ad..15a9a01c61 100644 --- a/crates/environ/src/cache.rs +++ b/crates/environ/src/cache.rs @@ -18,9 +18,8 @@ use std::path::{Path, PathBuf}; mod config; mod worker; -use config::{cache_config, CacheConfig}; -pub use config::{create_new_config, init}; -use worker::{worker, Worker}; +pub use config::{create_new_config, CacheConfig}; +use worker::Worker; lazy_static! { static ref SELF_MTIME: String = { @@ -48,12 +47,11 @@ lazy_static! { }; } -pub struct ModuleCacheEntry<'config, 'worker>(Option>); +pub struct ModuleCacheEntry<'config>(Option>); -struct ModuleCacheEntryInner<'config, 'worker> { +struct ModuleCacheEntryInner<'config> { mod_cache_path: PathBuf, cache_config: &'config CacheConfig, - worker: &'worker Worker, } /// Cached compilation data of a Wasm module. @@ -79,15 +77,15 @@ pub type ModuleCacheDataTupleType = ( struct Sha256Hasher(Sha256); -impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> { +impl<'config> ModuleCacheEntry<'config> { pub fn new<'data>( module: &Module, function_body_inputs: &PrimaryMap>, isa: &dyn isa::TargetIsa, compiler_name: &str, generate_debug_info: bool, + cache_config: &'config CacheConfig, ) -> Self { - let cache_config = cache_config(); if cache_config.enabled() { Self(Some(ModuleCacheEntryInner::new( module, @@ -96,7 +94,6 @@ impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> { compiler_name, generate_debug_info, cache_config, - worker(), ))) } else { Self(None) @@ -104,14 +101,17 @@ impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> { } #[cfg(test)] - fn from_inner(inner: ModuleCacheEntryInner<'config, 'worker>) -> Self { + fn from_inner(inner: ModuleCacheEntryInner<'config>) -> Self { Self(Some(inner)) } pub fn get_data(&self) -> Option { if let Some(inner) = &self.0 { inner.get_data().map(|val| { - inner.worker.on_cache_get_async(&inner.mod_cache_path); // call on success + inner + .cache_config + .worker() + .on_cache_get_async(&inner.mod_cache_path); // call on success val }) } else { @@ -122,13 +122,16 @@ impl<'config, 'worker> ModuleCacheEntry<'config, 'worker> { pub fn update_data(&self, data: &ModuleCacheData) { if let Some(inner) = &self.0 { if inner.update_data(data).is_some() { - inner.worker.on_cache_update_async(&inner.mod_cache_path); // call on success + inner + .cache_config + .worker() + .on_cache_update_async(&inner.mod_cache_path); // call on success } } } } -impl<'config, 'worker> ModuleCacheEntryInner<'config, 'worker> { +impl<'config> ModuleCacheEntryInner<'config> { fn new<'data>( module: &Module, function_body_inputs: &PrimaryMap>, @@ -136,7 +139,6 @@ impl<'config, 'worker> ModuleCacheEntryInner<'config, 'worker> { compiler_name: &str, generate_debug_info: bool, cache_config: &'config CacheConfig, - worker: &'worker Worker, ) -> Self { let hash = Sha256Hasher::digest(module, function_body_inputs); let compiler_dir = if cfg!(debug_assertions) { @@ -167,7 +169,6 @@ impl<'config, 'worker> ModuleCacheEntryInner<'config, 'worker> { Self { mod_cache_path, cache_config, - worker, } } diff --git a/crates/environ/src/cache/config.rs b/crates/environ/src/cache/config.rs index 1db0c6833a..7686d187cd 100644 --- a/crates/environ/src/cache/config.rs +++ b/crates/environ/src/cache/config.rs @@ -1,20 +1,16 @@ //! Module for configuring the cache system. -use super::worker; +use super::Worker; use anyhow::{anyhow, bail, Context, Result}; use directories::ProjectDirs; -use lazy_static::lazy_static; -use log::{debug, error, trace, warn}; +use log::{trace, warn}; use serde::{ de::{self, Deserializer}, Deserialize, }; -use spin::Once; use std::fmt::Debug; use std::fs; -use std::mem; use std::path::{Path, PathBuf}; -use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; // wrapped, so we have named section in config, @@ -25,12 +21,10 @@ struct Config { cache: CacheConfig, } +/// Global configuration for how the cache is managed #[derive(Deserialize, Debug, Clone)] #[serde(deny_unknown_fields)] pub struct CacheConfig { - #[serde(skip)] - errors: Vec, - enabled: bool, directory: Option, #[serde( @@ -91,49 +85,9 @@ pub struct CacheConfig { deserialize_with = "deserialize_percent" )] files_total_size_limit_percent_if_deleting: Option, -} -// Private static, so only internal function can access it. -static CONFIG: Once = Once::new(); -static INIT_CALLED: AtomicBool = AtomicBool::new(false); - -/// Returns cache configuration. -/// -/// If system has not been initialized, it disables it. -/// You mustn't call init() after it. -pub fn cache_config() -> &'static CacheConfig { - CONFIG.call_once(CacheConfig::new_cache_disabled) -} - -/// Initializes the cache system. Should be called exactly once, -/// and before using the cache system. Otherwise it can panic. -/// Returns list of errors. If empty, initialization succeeded. -pub fn init + Debug>( - enabled: bool, - config_file: Option

, - init_file_per_thread_logger: Option<&'static str>, -) -> &'static Vec { - INIT_CALLED - .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) - .expect("Cache system init must be called at most once"); - assert!( - CONFIG.r#try().is_none(), - "Cache system init must be called before using the system." - ); - let conf_file_str = format!("{:?}", config_file); - let conf = CONFIG.call_once(|| CacheConfig::from_file(enabled, config_file)); - if conf.errors.is_empty() { - if conf.enabled() { - worker::init(init_file_per_thread_logger); - } - debug!("Cache init(\"{}\"): {:#?}", conf_file_str, conf) - } else { - error!( - "Cache init(\"{}\"): errors: {:#?}", - conf_file_str, conf.errors, - ) - } - &conf.errors + #[serde(skip)] + worker: Option, } /// Creates a new configuration file at specified path, or default path if None is passed. @@ -141,13 +95,10 @@ pub fn init + Debug>( pub fn create_new_config + Debug>(config_file: Option

) -> Result { trace!("Creating new config file, path: {:?}", config_file); - let config_file = config_file - .as_ref() - .map_or_else( - || DEFAULT_CONFIG_PATH.as_ref().map(|p| p.as_ref()), - |p| Ok(p.as_ref()), - ) - .map_err(|s| anyhow!("{}", s))?; + let config_file = match config_file { + Some(path) => path.as_ref().to_path_buf(), + None => default_config_path()?, + }; if config_file.exists() { bail!( @@ -188,14 +139,6 @@ enabled = true // permitted levels from: https://docs.rs/zstd/0.4.28+zstd.1.4.3/zstd/stream/write/struct.Encoder.html const ZSTD_COMPRESSION_LEVELS: std::ops::RangeInclusive = 0..=21; -lazy_static! { - static ref PROJECT_DIRS: Option = - ProjectDirs::from("", "BytecodeAlliance", "wasmtime"); - static ref DEFAULT_CONFIG_PATH: Result = PROJECT_DIRS - .as_ref() - .map(|proj_dirs| proj_dirs.config_dir().join("config.toml")) - .ok_or_else(|| "Config file not specified and failed to get the default".to_string()); -} // Default settings, you're welcome to tune them! // TODO: what do we want to warn users about? @@ -232,6 +175,17 @@ const DEFAULT_FILE_COUNT_LIMIT_PERCENT_IF_DELETING: u8 = 70; // if changed, update cli-cache.md const DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING: u8 = 70; +fn project_dirs() -> Option { + ProjectDirs::from("", "BytecodeAlliance", "wasmtime") +} + +fn default_config_path() -> Result { + match project_dirs() { + Some(dirs) => Ok(dirs.config_dir().join("config.toml")), + None => bail!("config file not specified and failed to get the default"), + } +} + // Deserializers of our custom formats // can be replaced with const generics later macro_rules! generate_deserializer { @@ -353,9 +307,9 @@ impl CacheConfig { .expect(CACHE_IMPROPER_CONFIG_ERROR_MSG) } + /// Creates a new set of configuration which represents a disabled cache pub fn new_cache_disabled() -> Self { Self { - errors: Vec::new(), enabled: false, directory: None, worker_event_queue_size: None, @@ -369,6 +323,7 @@ impl CacheConfig { files_total_size_soft_limit: None, file_count_limit_percent_if_deleting: None, files_total_size_limit_percent_if_deleting: None, + worker: None, } } @@ -378,78 +333,70 @@ impl CacheConfig { conf } - fn new_cache_with_errors(errors: Vec) -> Self { - let mut conf = Self::new_cache_disabled(); - conf.errors = errors; - conf - } - - pub fn from_file>(enabled: bool, config_file: Option

) -> Self { - if !enabled { - return Self::new_cache_disabled(); - } - - let mut config = match Self::load_and_parse_file(config_file) { - Ok(data) => data, - Err(err) => return Self::new_cache_with_errors(vec![err]), - }; + /// Parses cache configuration from the file specified + pub fn from_file(config_file: Option<&Path>) -> Result { + let mut config = Self::load_and_parse_file(config_file)?; // validate values and fill in defaults - config.validate_directory_or_default(); + config.validate_directory_or_default()?; config.validate_worker_event_queue_size_or_default(); - config.validate_baseline_compression_level_or_default(); - config.validate_optimized_compression_level_or_default(); + config.validate_baseline_compression_level_or_default()?; + config.validate_optimized_compression_level_or_default()?; config.validate_optimized_compression_usage_counter_threshold_or_default(); config.validate_cleanup_interval_or_default(); config.validate_optimizing_compression_task_timeout_or_default(); config.validate_allowed_clock_drift_for_files_from_future_or_default(); config.validate_file_count_soft_limit_or_default(); config.validate_files_total_size_soft_limit_or_default(); - config.validate_file_count_limit_percent_if_deleting_or_default(); - config.validate_files_total_size_limit_percent_if_deleting_or_default(); + config.validate_file_count_limit_percent_if_deleting_or_default()?; + config.validate_files_total_size_limit_percent_if_deleting_or_default()?; + config.spawn_worker(); - config.disable_if_any_error(); - config + Ok(config) } - fn load_and_parse_file>(config_file: Option

) -> Result { + fn spawn_worker(&mut self) { + if self.enabled { + self.worker = Some(Worker::start_new(self, None)); + } + } + + pub(super) fn worker(&self) -> &Worker { + assert!(self.enabled); + self.worker.as_ref().unwrap() + } + + fn load_and_parse_file(config_file: Option<&Path>) -> Result { // get config file path - let (config_file, user_custom_file) = config_file.as_ref().map_or_else( - || DEFAULT_CONFIG_PATH.as_ref().map(|p| (p.as_ref(), false)), - |p| Ok((p.as_ref(), true)), - )?; + let (config_file, user_custom_file) = match config_file { + Some(path) => (path.to_path_buf(), true), + None => (default_config_path()?, false), + }; // read config, or use default one let entity_exists = config_file.exists(); match (entity_exists, user_custom_file) { (false, false) => Ok(Self::new_cache_enabled_template()), - _ => match fs::read(&config_file) { - Ok(bytes) => match toml::from_slice::(&bytes[..]) { - Ok(config) => Ok(config.cache), - Err(err) => Err(format!( - "Failed to parse config file, path: {}, error: {}", - config_file.display(), - err - )), - }, - Err(err) => Err(format!( - "Failed to read config file, path: {}, error: {}", - config_file.display(), - err - )), - }, + _ => { + let bytes = fs::read(&config_file).context(format!( + "failed to read config file: {}", + config_file.display() + ))?; + let config = toml::from_slice::(&bytes[..]).context(format!( + "failed to parse config file: {}", + config_file.display() + ))?; + Ok(config.cache) + } } } - fn validate_directory_or_default(&mut self) { + fn validate_directory_or_default(&mut self) -> Result<()> { if self.directory.is_none() { - match &*PROJECT_DIRS { + match project_dirs() { Some(proj_dirs) => self.directory = Some(proj_dirs.cache_dir().to_path_buf()), None => { - self.errors.push( - "Cache directory not specified and failed to get the default".to_string(), - ); - return; + bail!("Cache directory not specified and failed to get the default"); } } } @@ -461,35 +408,22 @@ impl CacheConfig { let cache_dir = self.directory.as_ref().unwrap(); if !cache_dir.is_absolute() { - self.errors.push(format!( + bail!( "Cache directory path has to be absolute, path: {}", cache_dir.display(), - )); - return; + ); } - match fs::create_dir_all(cache_dir) { - Ok(()) => (), - Err(err) => { - self.errors.push(format!( - "Failed to create the cache directory, path: {}, error: {}", - cache_dir.display(), - err - )); - return; - } - }; - - match fs::canonicalize(cache_dir) { - Ok(p) => self.directory = Some(p), - Err(err) => { - self.errors.push(format!( - "Failed to canonicalize the cache directory, path: {}, error: {}", - cache_dir.display(), - err - )); - } - } + fs::create_dir_all(cache_dir).context(format!( + "failed to create cache directory: {}", + cache_dir.display() + ))?; + let canonical = fs::canonicalize(cache_dir).context(format!( + "failed to canonicalize cache directory: {}", + cache_dir.display() + ))?; + self.directory = Some(canonical); + Ok(()) } fn validate_worker_event_queue_size_or_default(&mut self) { @@ -502,22 +436,23 @@ impl CacheConfig { } } - fn validate_baseline_compression_level_or_default(&mut self) { + fn validate_baseline_compression_level_or_default(&mut self) -> Result<()> { if self.baseline_compression_level.is_none() { self.baseline_compression_level = Some(DEFAULT_BASELINE_COMPRESSION_LEVEL); } if !ZSTD_COMPRESSION_LEVELS.contains(&self.baseline_compression_level.unwrap()) { - self.errors.push(format!( + bail!( "Invalid baseline compression level: {} not in {:#?}", self.baseline_compression_level.unwrap(), ZSTD_COMPRESSION_LEVELS - )); + ); } + Ok(()) } // assumption: baseline compression level has been verified - fn validate_optimized_compression_level_or_default(&mut self) { + fn validate_optimized_compression_level_or_default(&mut self) -> Result<()> { if self.optimized_compression_level.is_none() { self.optimized_compression_level = Some(DEFAULT_OPTIMIZED_COMPRESSION_LEVEL); } @@ -526,18 +461,21 @@ impl CacheConfig { let base_lvl = self.baseline_compression_level.unwrap(); if !ZSTD_COMPRESSION_LEVELS.contains(&opt_lvl) { - self.errors.push(format!( + bail!( "Invalid optimized compression level: {} not in {:#?}", - opt_lvl, ZSTD_COMPRESSION_LEVELS - )); + opt_lvl, + ZSTD_COMPRESSION_LEVELS + ); } if opt_lvl < base_lvl { - self.errors.push(format!( + bail!( "Invalid optimized compression level is lower than baseline: {} < {}", - opt_lvl, base_lvl - )); + opt_lvl, + base_lvl + ); } + Ok(()) } fn validate_optimized_compression_usage_counter_threshold_or_default(&mut self) { @@ -579,7 +517,7 @@ impl CacheConfig { } } - fn validate_file_count_limit_percent_if_deleting_or_default(&mut self) { + fn validate_file_count_limit_percent_if_deleting_or_default(&mut self) -> Result<()> { if self.file_count_limit_percent_if_deleting.is_none() { self.file_count_limit_percent_if_deleting = Some(DEFAULT_FILE_COUNT_LIMIT_PERCENT_IF_DELETING); @@ -587,14 +525,15 @@ impl CacheConfig { let percent = self.file_count_limit_percent_if_deleting.unwrap(); if percent > 100 { - self.errors.push(format!( + bail!( "Invalid files count limit percent if deleting: {} not in range 0-100%", percent - )); + ); } + Ok(()) } - fn validate_files_total_size_limit_percent_if_deleting_or_default(&mut self) { + fn validate_files_total_size_limit_percent_if_deleting_or_default(&mut self) -> Result<()> { if self.files_total_size_limit_percent_if_deleting.is_none() { self.files_total_size_limit_percent_if_deleting = Some(DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING); @@ -602,19 +541,12 @@ impl CacheConfig { let percent = self.files_total_size_limit_percent_if_deleting.unwrap(); if percent > 100 { - self.errors.push(format!( + bail!( "Invalid files total size limit percent if deleting: {} not in range 0-100%", percent - )); - } - } - - fn disable_if_any_error(&mut self) { - if !self.errors.is_empty() { - let mut conf = Self::new_cache_disabled(); - mem::swap(self, &mut conf); - mem::swap(&mut self.errors, &mut conf.errors); + ); } + Ok(()) } } diff --git a/crates/environ/src/cache/config/tests.rs b/crates/environ/src/cache/config/tests.rs index 7a9094a2ad..0c1dc873fb 100644 --- a/crates/environ/src/cache/config/tests.rs +++ b/crates/environ/src/cache/config/tests.rs @@ -24,7 +24,19 @@ macro_rules! load_config { cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap() ); fs::write(config_path, content).expect("Failed to write test config file"); - CacheConfig::from_file(true, Some(config_path)) + CacheConfig::from_file(Some(config_path)).unwrap() + }}; +} + +macro_rules! bad_config { + ($config_path:ident, $content_fmt:expr, $cache_dir:ident) => {{ + let config_path = &$config_path; + let content = format!( + $content_fmt, + cache_dir = toml::to_string_pretty(&format!("{}", $cache_dir.display())).unwrap() + ); + fs::write(config_path, content).expect("Failed to write test config file"); + assert!(CacheConfig::from_file(Some(config_path)).is_err()); }}; } @@ -33,25 +45,17 @@ macro_rules! load_config { fn test_disabled() { let dir = tempfile::tempdir().expect("Can't create temporary directory"); let config_path = dir.path().join("cache-config.toml"); - let config_content = "[cache]\n\ - enabled = true\n"; - fs::write(&config_path, config_content).expect("Failed to write test config file"); - let conf = CacheConfig::from_file(false, Some(&config_path)); - assert!(!conf.enabled()); - assert!(conf.errors.is_empty()); - let config_content = "[cache]\n\ enabled = false\n"; fs::write(&config_path, config_content).expect("Failed to write test config file"); - let conf = CacheConfig::from_file(true, Some(&config_path)); + let conf = CacheConfig::from_file(Some(&config_path)).unwrap(); assert!(!conf.enabled()); - assert!(conf.errors.is_empty()); } #[test] fn test_unrecognized_settings() { let (_td, cd, cp) = test_prolog(); - let conf = load_config!( + bad_config!( cp, "unrecognized-setting = 42\n\ [cache]\n\ @@ -59,10 +63,8 @@ fn test_unrecognized_settings() { directory = {cache_dir}", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -70,8 +72,6 @@ fn test_unrecognized_settings() { unrecognized-setting = 42", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); } #[test] @@ -119,9 +119,7 @@ fn test_all_settings() { check_conf(&conf, &cd); fn check_conf(conf: &CacheConfig, cd: &PathBuf) { - eprintln!("errors: {:#?}", conf.errors); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!( conf.directory(), &fs::canonicalize(cd).expect("canonicalize failed") @@ -159,11 +157,10 @@ fn test_compression_level_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.baseline_compression_level(), 1); assert_eq!(conf.optimized_compression_level(), 21); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -172,10 +169,8 @@ fn test_compression_level_settings() { optimized-compression-level = 21", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -184,8 +179,6 @@ fn test_compression_level_settings() { optimized-compression-level = 10", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); } #[test] @@ -202,7 +195,6 @@ fn test_si_prefix_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.worker_event_queue_size(), 42); assert_eq!(conf.optimized_compression_usage_counter_threshold(), 4_000); assert_eq!(conf.file_count_soft_limit(), 3_000_000); @@ -212,14 +204,13 @@ fn test_si_prefix_settings() { "[cache]\n\ enabled = true\n\ directory = {cache_dir}\n\ - worker-event-queue-size = '2G'\n\ + worker-event-queue-size = '2K'\n\ optimized-compression-usage-counter-threshold = '4444T'\n\ file-count-soft-limit = '1P'", cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); - assert_eq!(conf.worker_event_queue_size(), 2_000_000_000); + assert_eq!(conf.worker_event_queue_size(), 2_000); assert_eq!( conf.optimized_compression_usage_counter_threshold(), 4_444_000_000_000_000 @@ -227,7 +218,7 @@ fn test_si_prefix_settings() { assert_eq!(conf.file_count_soft_limit(), 1_000_000_000_000_000); // different errors - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -235,10 +226,8 @@ fn test_si_prefix_settings() { worker-event-queue-size = '2g'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -246,10 +235,8 @@ fn test_si_prefix_settings() { file-count-soft-limit = 1", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -257,10 +244,8 @@ fn test_si_prefix_settings() { file-count-soft-limit = '-31337'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -268,8 +253,6 @@ fn test_si_prefix_settings() { file-count-soft-limit = '3.14M'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); } #[test] @@ -284,7 +267,6 @@ fn test_disk_space_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.files_total_size_soft_limit(), 76); let conf = load_config!( @@ -296,7 +278,6 @@ fn test_disk_space_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.files_total_size_soft_limit(), 42 * (1u64 << 20)); let conf = load_config!( @@ -308,7 +289,6 @@ fn test_disk_space_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.files_total_size_soft_limit(), 2 * (1u64 << 30)); let conf = load_config!( @@ -320,7 +300,6 @@ fn test_disk_space_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.files_total_size_soft_limit(), 31337 * (1u64 << 40)); let conf = load_config!( @@ -332,7 +311,6 @@ fn test_disk_space_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.files_total_size_soft_limit(), 7 * (1u64 << 50)); let conf = load_config!( @@ -344,11 +322,10 @@ fn test_disk_space_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.files_total_size_soft_limit(), 7_000_000); // different errors - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -356,10 +333,8 @@ fn test_disk_space_settings() { files-total-size-soft-limit = '7 mi'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -367,10 +342,8 @@ fn test_disk_space_settings() { files-total-size-soft-limit = 1", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -378,10 +351,8 @@ fn test_disk_space_settings() { files-total-size-soft-limit = '-31337'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -389,8 +360,6 @@ fn test_disk_space_settings() { files-total-size-soft-limit = '3.14Ki'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); } #[test] @@ -407,7 +376,6 @@ fn test_duration_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.cleanup_interval(), Duration::from_secs(100)); assert_eq!( conf.optimizing_compression_task_timeout(), @@ -428,7 +396,6 @@ fn test_duration_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!( conf.cleanup_interval(), Duration::from_secs(2 * 24 * 60 * 60) @@ -439,7 +406,7 @@ fn test_duration_settings() { ); // different errors - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -447,10 +414,8 @@ fn test_duration_settings() { optimizing-compression-task-timeout = '333'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -458,10 +423,8 @@ fn test_duration_settings() { optimizing-compression-task-timeout = 333", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -469,10 +432,8 @@ fn test_duration_settings() { optimizing-compression-task-timeout = '10 M'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -480,10 +441,8 @@ fn test_duration_settings() { optimizing-compression-task-timeout = '10 min'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -491,10 +450,8 @@ fn test_duration_settings() { optimizing-compression-task-timeout = '-10s'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -502,8 +459,6 @@ fn test_duration_settings() { optimizing-compression-task-timeout = '1.5m'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); } #[test] @@ -519,12 +474,11 @@ fn test_percent_settings() { cd ); assert!(conf.enabled()); - assert!(conf.errors.is_empty()); assert_eq!(conf.file_count_limit_percent_if_deleting(), 62); assert_eq!(conf.files_total_size_limit_percent_if_deleting(), 23); // different errors - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -532,10 +486,8 @@ fn test_percent_settings() { files-total-size-limit-percent-if-deleting = '23'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -543,10 +495,8 @@ fn test_percent_settings() { files-total-size-limit-percent-if-deleting = '22.5%'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -554,10 +504,8 @@ fn test_percent_settings() { files-total-size-limit-percent-if-deleting = '0.5'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -565,10 +513,8 @@ fn test_percent_settings() { files-total-size-limit-percent-if-deleting = '-1%'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); - let conf = load_config!( + bad_config!( cp, "[cache]\n\ enabled = true\n\ @@ -576,6 +522,4 @@ fn test_percent_settings() { files-total-size-limit-percent-if-deleting = '101%'", cd ); - assert!(!conf.enabled()); - assert!(!conf.errors.is_empty()); } diff --git a/crates/environ/src/cache/tests.rs b/crates/environ/src/cache/tests.rs index d990288042..781cd4b529 100644 --- a/crates/environ/src/cache/tests.rs +++ b/crates/environ/src/cache/tests.rs @@ -36,11 +36,9 @@ fn test_cache_init() { ); fs::write(&config_path, config_content).expect("Failed to write test config file"); - let errors = init(true, Some(&config_path), None); - assert!(errors.is_empty()); + let cache_config = CacheConfig::from_file(Some(&config_path)).unwrap(); // test if we can use config - let cache_config = cache_config(); assert!(cache_config.enabled()); // assumption: config init creates cache directory and returns canonicalized path assert_eq!( @@ -53,8 +51,7 @@ fn test_cache_init() { ); // test if we can use worker - let worker = worker(); - worker.on_cache_update_async(config_path); + cache_config.worker().on_cache_update_async(config_path); } #[test] @@ -69,7 +66,6 @@ fn test_write_read_cache() { cache_dir ); assert!(cache_config.enabled()); - let worker = Worker::start_new(&cache_config, None); // assumption: config load creates cache directory and returns canonicalized path assert_eq!( @@ -102,7 +98,6 @@ fn test_write_read_cache() { compiler1, false, &cache_config, - &worker, )); assert!(entry1.0.is_some()); assert!(entry1.get_data().is_none()); @@ -117,7 +112,6 @@ fn test_write_read_cache() { compiler1, false, &cache_config, - &worker, )); let data2 = new_module_cache_data(&mut rng); entry2.update_data(&data2); @@ -131,7 +125,6 @@ fn test_write_read_cache() { compiler1, false, &cache_config, - &worker, )); let data3 = new_module_cache_data(&mut rng); entry3.update_data(&data3); @@ -146,7 +139,6 @@ fn test_write_read_cache() { compiler1, false, &cache_config, - &worker, )); let data4 = new_module_cache_data(&mut rng); entry4.update_data(&data4); @@ -162,7 +154,6 @@ fn test_write_read_cache() { compiler2, false, &cache_config, - &worker, )); let data5 = new_module_cache_data(&mut rng); entry5.update_data(&data5); diff --git a/crates/environ/src/cache/worker.rs b/crates/environ/src/cache/worker.rs index 452b4d9c3f..047276b83f 100644 --- a/crates/environ/src/cache/worker.rs +++ b/crates/environ/src/cache/worker.rs @@ -5,16 +5,15 @@ //! but we guarantee eventual consistency and fault tolerancy. //! Background tasks can be CPU intensive, but the worker thread has low priority. -use super::{cache_config, fs_write_atomic, CacheConfig}; +use super::{fs_write_atomic, CacheConfig}; use log::{debug, info, trace, warn}; use serde::{Deserialize, Serialize}; -use spin::Once; use std::cmp; use std::collections::HashMap; use std::ffi::OsStr; +use std::fmt; use std::fs; use std::path::{Path, PathBuf}; -use std::sync::atomic::{self, AtomicBool}; use std::sync::mpsc::{sync_channel, Receiver, SyncSender}; #[cfg(test)] use std::sync::{Arc, Condvar, Mutex}; @@ -25,6 +24,7 @@ use std::time::SystemTime; #[cfg(test)] use tests::system_time_stub::SystemTimeStub as SystemTime; +#[derive(Clone)] pub(super) struct Worker { sender: SyncSender, #[cfg(test)] @@ -46,29 +46,6 @@ struct WorkerStats { handled: u32, } -static WORKER: Once = Once::new(); -static INIT_CALLED: AtomicBool = AtomicBool::new(false); - -pub(super) fn worker() -> &'static Worker { - WORKER - .r#try() - .expect("Cache worker must be initialized before usage") -} - -pub(super) fn init(init_file_per_thread_logger: Option<&'static str>) { - INIT_CALLED - .compare_exchange( - false, - true, - atomic::Ordering::SeqCst, - atomic::Ordering::SeqCst, - ) - .expect("Cache worker init must be called at most once"); - - let worker = Worker::start_new(cache_config(), init_file_per_thread_logger); - WORKER.call_once(|| worker); -} - #[derive(Debug, Clone)] enum CacheEvent { OnCacheGet(PathBuf), @@ -168,6 +145,12 @@ impl Worker { } } +impl fmt::Debug for Worker { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Worker").finish() + } +} + #[derive(Serialize, Deserialize)] struct ModuleCacheStatistics { pub usages: u64, @@ -210,9 +193,6 @@ macro_rules! unwrap_or_warn { impl WorkerThread { fn run(self, init_file_per_thread_logger: Option<&'static str>) { - #[cfg(not(test))] // We want to test the worker without relying on init() being called - assert!(INIT_CALLED.load(atomic::Ordering::SeqCst)); - if let Some(prefix) = init_file_per_thread_logger { file_per_thread_logger::initialize(prefix); } diff --git a/crates/environ/src/compilation.rs b/crates/environ/src/compilation.rs index ae57584008..2335565272 100644 --- a/crates/environ/src/compilation.rs +++ b/crates/environ/src/compilation.rs @@ -4,6 +4,7 @@ use crate::cache::ModuleCacheDataTupleType; use crate::module; use crate::module_environ::FunctionBodyData; +use crate::CacheConfig; use cranelift_codegen::{binemit, ir, isa, Context}; use cranelift_entity::PrimaryMap; use cranelift_wasm::{DefinedFuncIndex, FuncIndex, ModuleTranslationState, WasmError}; @@ -300,5 +301,6 @@ pub trait Compiler { function_body_inputs: PrimaryMap>, isa: &dyn isa::TargetIsa, generate_debug_info: bool, + cache_config: &CacheConfig, ) -> Result; } diff --git a/crates/environ/src/cranelift.rs b/crates/environ/src/cranelift.rs index 246838373f..6c48c353f1 100644 --- a/crates/environ/src/cranelift.rs +++ b/crates/environ/src/cranelift.rs @@ -12,6 +12,7 @@ use crate::func_environ::{ }; use crate::module::Module; use crate::module_environ::FunctionBodyData; +use crate::CacheConfig; use cranelift_codegen::ir::{self, ExternalName}; use cranelift_codegen::print_errors::pretty_error; use cranelift_codegen::{binemit, isa, Context}; @@ -176,6 +177,7 @@ impl crate::compilation::Compiler for Cranelift { function_body_inputs: PrimaryMap>, isa: &dyn isa::TargetIsa, generate_debug_info: bool, + cache_config: &CacheConfig, ) -> Result { let cache_entry = ModuleCacheEntry::new( module, @@ -183,6 +185,7 @@ impl crate::compilation::Compiler for Cranelift { isa, "cranelift", generate_debug_info, + cache_config, ); let data = match cache_entry.get_data() { diff --git a/crates/environ/src/lib.rs b/crates/environ/src/lib.rs index 316af5b77e..456e0d819c 100644 --- a/crates/environ/src/lib.rs +++ b/crates/environ/src/lib.rs @@ -43,7 +43,8 @@ pub use crate::address_map::{ FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleMemoryOffset, ModuleVmctxInfo, ValueLabelsRanges, }; -pub use crate::cache::{create_new_config as cache_create_new_config, init as cache_init}; +pub use crate::cache::create_new_config as cache_create_new_config; +pub use crate::cache::CacheConfig; pub use crate::compilation::{ Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, CompiledFunctionUnwindInfoReloc, Compiler, Relocation, RelocationTarget, Relocations, diff --git a/crates/environ/src/lightbeam.rs b/crates/environ/src/lightbeam.rs index 7d7d5e6887..513b305559 100644 --- a/crates/environ/src/lightbeam.rs +++ b/crates/environ/src/lightbeam.rs @@ -1,14 +1,15 @@ //! Support for compiling with Lightbeam. use crate::cache::ModuleCacheDataTupleType; -use crate::compilation::{Compilation, CompileError, Relocations, Traps}; +use crate::compilation::{Compilation, CompileError, Traps}; use crate::func_environ::FuncEnvironment; use crate::module::Module; use crate::module_environ::FunctionBodyData; // TODO: Put this in `compilation` use crate::address_map::{ModuleAddressMap, ValueLabelsRanges}; use crate::cranelift::RelocSink; -use cranelift_codegen::{ir, isa}; +use crate::CacheConfig; +use cranelift_codegen::isa; use cranelift_entity::{PrimaryMap, SecondaryMap}; use cranelift_wasm::{DefinedFuncIndex, ModuleTranslationState}; @@ -25,6 +26,7 @@ impl crate::compilation::Compiler for Lightbeam { isa: &dyn isa::TargetIsa, // TODO generate_debug_info: bool, + _cache_config: &CacheConfig, ) -> Result { if generate_debug_info { return Err(CompileError::DebugInfoNotSupported); diff --git a/crates/environ/tests/cache_default_config_in_memory.rs b/crates/environ/tests/cache_default_config_in_memory.rs deleted file mode 100644 index d6e499003f..0000000000 --- a/crates/environ/tests/cache_default_config_in_memory.rs +++ /dev/null @@ -1,10 +0,0 @@ -use wasmtime_environ::cache_init; - -#[test] -fn test_cache_default_config_in_memory() { - let errors = cache_init::<&str>(true, None, None); - assert!( - errors.is_empty(), - "This test loads config from the default location, if there's one. Make sure it's correct!" - ); -} diff --git a/crates/environ/tests/cache_disabled.rs b/crates/environ/tests/cache_disabled.rs deleted file mode 100644 index 585f90c26d..0000000000 --- a/crates/environ/tests/cache_disabled.rs +++ /dev/null @@ -1,7 +0,0 @@ -use wasmtime_environ::cache_init; - -#[test] -fn test_cache_disabled() { - let errors = cache_init::<&str>(false, None, None); - assert!(errors.is_empty(), "Failed to disable cache system"); -} diff --git a/crates/environ/tests/cache_fail_calling_init_twice.rs b/crates/environ/tests/cache_fail_calling_init_twice.rs deleted file mode 100644 index bdeb62e226..0000000000 --- a/crates/environ/tests/cache_fail_calling_init_twice.rs +++ /dev/null @@ -1,26 +0,0 @@ -use std::fs; -use tempfile; -use wasmtime_environ::cache_init; - -#[test] -#[should_panic] -fn test_cache_fail_calling_init_twice() { - let dir = tempfile::tempdir().expect("Can't create temporary directory"); - let cache_dir = dir.path().join("cache-dir"); - let baseline_compression_level = 5; - - let config_path = dir.path().join("cache-config.toml"); - let config_content = format!( - "[cache]\n\ - enabled = true\n\ - directory = {}\n\ - baseline-compression-level = {}\n", - toml::to_string_pretty(&format!("{}", cache_dir.display())).unwrap(), - baseline_compression_level, - ); - fs::write(&config_path, config_content).expect("Failed to write test config file"); - - let errors = cache_init(true, Some(&config_path), None); - assert!(errors.is_empty()); - let _errors = cache_init(true, Some(&config_path), None); -} diff --git a/crates/environ/tests/cache_fail_invalid_config.rs b/crates/environ/tests/cache_fail_invalid_config.rs deleted file mode 100644 index 30c7630f00..0000000000 --- a/crates/environ/tests/cache_fail_invalid_config.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::fs; -use tempfile; -use wasmtime_environ::cache_init; - -#[test] -fn test_cache_fail_invalid_config() { - let dir = tempfile::tempdir().expect("Can't create temporary directory"); - let baseline_compression_level = -4; - - let config_path = dir.path().join("cache-config.toml"); - let config_content = format!( - "[cache]\n\ - enabled = true\n\ - directory = {}\n\ - baseline-compression-level = {}\n", - toml::to_string_pretty(&format!("{}", config_path.display())).unwrap(), // directory is a file -- incorrect! - baseline_compression_level, - ); - fs::write(&config_path, config_content).expect("Failed to write test config file"); - - let errors = cache_init(true, Some(&config_path), None); - assert!(!errors.is_empty()); -} diff --git a/crates/environ/tests/cache_fail_invalid_path_to_config.rs b/crates/environ/tests/cache_fail_invalid_path_to_config.rs deleted file mode 100644 index cc4cf2bb1f..0000000000 --- a/crates/environ/tests/cache_fail_invalid_path_to_config.rs +++ /dev/null @@ -1,10 +0,0 @@ -use tempfile; -use wasmtime_environ::cache_init; - -#[test] -fn test_cache_fail_invalid_path_to_config() { - let dir = tempfile::tempdir().expect("Can't create temporary directory"); - let config_path = dir.path().join("cache-config.toml"); // doesn't exist - let errors = cache_init(true, Some(&config_path), None); - assert!(!errors.is_empty()); -} diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 7eb7cc4a40..440093d84c 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -16,9 +16,9 @@ use wasmtime_environ::entity::{EntityRef, PrimaryMap}; use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa}; use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex}; use wasmtime_environ::{ - Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, Compiler as _C, - FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations, Traps, Tunables, - VMOffsets, + CacheConfig, Compilation, CompileError, CompiledFunction, CompiledFunctionUnwindInfo, + Compiler as _C, FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations, + Traps, Tunables, VMOffsets, }; use wasmtime_runtime::{ jit_function_registry, InstantiationError, SignatureRegistry, TrapRegistration, TrapRegistry, @@ -56,6 +56,7 @@ pub struct Compiler { trampoline_park: HashMap<*const VMFunctionBody, *const VMFunctionBody>, signatures: SignatureRegistry, strategy: CompilationStrategy, + cache_config: CacheConfig, /// The `FunctionBuilderContext`, shared between trampline function compilations. fn_builder_ctx: FunctionBuilderContext, @@ -63,7 +64,11 @@ pub struct Compiler { impl Compiler { /// Construct a new `Compiler`. - pub fn new(isa: Box, strategy: CompilationStrategy) -> Self { + pub fn new( + isa: Box, + strategy: CompilationStrategy, + cache_config: CacheConfig, + ) -> Self { Self { isa, code_memory: CodeMemory::new(), @@ -73,6 +78,7 @@ impl Compiler { fn_builder_ctx: FunctionBuilderContext::new(), strategy, trap_registry: TrapRegistry::default(), + cache_config, } } } @@ -124,6 +130,7 @@ impl Compiler { function_body_inputs, &*self.isa, debug_data.is_some(), + &self.cache_config, ) } #[cfg(feature = "lightbeam")] @@ -134,6 +141,7 @@ impl Compiler { function_body_inputs, &*self.isa, debug_data.is_some(), + &self.cache_config, ) } } diff --git a/crates/jit/src/context.rs b/crates/jit/src/context.rs index 30922d4967..1d3edec1e1 100644 --- a/crates/jit/src/context.rs +++ b/crates/jit/src/context.rs @@ -1,11 +1,10 @@ use crate::action::{get, inspect_memory, invoke}; use crate::{ - instantiate, ActionError, ActionOutcome, CompilationStrategy, CompiledModule, Compiler, - InstanceHandle, Namespace, RuntimeValue, SetupError, + instantiate, ActionError, ActionOutcome, CompiledModule, Compiler, InstanceHandle, Namespace, + RuntimeValue, SetupError, }; use thiserror::Error; use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig}; -use wasmtime_environ::isa::TargetIsa; /// Indicates an unknown instance was specified. #[derive(Error, Debug)] @@ -83,11 +82,6 @@ impl Context { self.debug_info = value; } - /// Construct a new instance of `Context` with the given target. - pub fn with_isa(isa: Box, strategy: CompilationStrategy) -> Self { - Self::new(Box::new(Compiler::new(isa, strategy))) - } - /// Retrieve the context features pub fn features(&self) -> &Features { &self.features diff --git a/src/commands/run.rs b/src/commands/run.rs index 038672758e..031e10a0b8 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -4,14 +4,12 @@ use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOption use anyhow::{bail, Context as _, Result}; use std::{ ffi::{OsStr, OsString}, - fmt::Write, fs::File, path::{Component, Path, PathBuf}, }; use structopt::{clap::AppSettings, StructOpt}; use wasi_common::preopen_dir; use wasmtime::{Config, Engine, Instance, Module, Store}; -use wasmtime_environ::cache_init; use wasmtime_interface_types::ModuleData; use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi}; @@ -91,28 +89,11 @@ pub struct RunCommand { impl RunCommand { /// Executes the command. pub fn execute(&self) -> Result<()> { - let log_config = if self.common.debug { + if self.common.debug { pretty_env_logger::init(); - None } else { let prefix = "wasmtime.dbg."; init_file_per_thread_logger(prefix); - Some(prefix) - }; - - let errors = cache_init( - !self.common.disable_cache, - self.common.config.as_ref(), - log_config, - ); - - if !errors.is_empty() { - let mut message = String::new(); - writeln!(message, "Cache initialization failed. Errors:")?; - for e in errors { - writeln!(message, " -> {}", e)?; - } - bail!(message); } let mut config = Config::new(); @@ -124,6 +105,7 @@ impl RunCommand { self.common.cranelift, self.common.lightbeam, )?)?; + self.common.configure_cache(&mut config)?; if self.common.optimize { config.cranelift_opt_level(wasmtime::OptLevel::Speed); diff --git a/src/commands/wasm2obj.rs b/src/commands/wasm2obj.rs index efd44e0279..ac5ec4ad0c 100644 --- a/src/commands/wasm2obj.rs +++ b/src/commands/wasm2obj.rs @@ -4,7 +4,6 @@ use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOption use anyhow::{anyhow, bail, Context as _, Result}; use faerie::Artifact; use std::{ - fmt::Write, fs::File, path::{Path, PathBuf}, str::FromStr, @@ -16,9 +15,9 @@ use wasmtime_debug::{emit_debugsections, read_debuginfo}; #[cfg(feature = "lightbeam")] use wasmtime_environ::Lightbeam; use wasmtime_environ::{ - cache_init, entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex, - wasm::MemoryIndex, Compiler, Cranelift, ModuleEnvironment, ModuleMemoryOffset, ModuleVmctxInfo, - Tunables, VMOffsets, + entity::EntityRef, settings, settings::Configurable, wasm::DefinedMemoryIndex, + wasm::MemoryIndex, CacheConfig, Compiler, Cranelift, ModuleEnvironment, ModuleMemoryOffset, + ModuleVmctxInfo, Tunables, VMOffsets, }; use wasmtime_jit::native; use wasmtime_obj::emit_module; @@ -59,34 +58,22 @@ pub struct WasmToObjCommand { impl WasmToObjCommand { /// Executes the command. pub fn execute(&self) -> Result<()> { - let log_config = if self.common.debug { - pretty_env_logger::init(); - None - } else { - let prefix = "wasm2obj.dbg."; - init_file_per_thread_logger(prefix); - Some(prefix) - }; - - let errors = cache_init( - !self.common.disable_cache, - self.common.config.as_ref(), - log_config, - ); - - if !errors.is_empty() { - let mut message = String::new(); - writeln!(message, "Cache initialization failed. Errors:")?; - for e in errors { - writeln!(message, " -> {}", e)?; - } - bail!(message); - } - self.handle_module() } fn handle_module(&self) -> Result<()> { + if self.common.debug { + pretty_env_logger::init(); + } else { + let prefix = "wasm2obj.dbg."; + init_file_per_thread_logger(prefix); + } + + let cache_config = if self.common.disable_cache { + CacheConfig::new_cache_disabled() + } else { + CacheConfig::from_file(self.common.config.as_deref())? + }; let strategy = pick_compilation_strategy(self.common.cranelift, self.common.lightbeam)?; let data = wat::parse_file(&self.module).context("failed to parse module")?; @@ -147,6 +134,7 @@ impl WasmToObjCommand { lazy_function_body_inputs, &*isa, self.common.debug_info, + &cache_config, ), #[cfg(feature = "lightbeam")] Strategy::Lightbeam => Lightbeam::compile_module( @@ -155,6 +143,7 @@ impl WasmToObjCommand { lazy_function_body_inputs, &*isa, self.common.debug_info, + &cache_config, ), #[cfg(not(feature = "lightbeam"))] Strategy::Lightbeam => bail!("lightbeam support not enabled"), diff --git a/src/commands/wast.rs b/src/commands/wast.rs index 7610c0425f..156812e6ed 100644 --- a/src/commands/wast.rs +++ b/src/commands/wast.rs @@ -1,11 +1,10 @@ //! The module that implements the `wasmtime wast` command. use crate::{init_file_per_thread_logger, pick_compilation_strategy, CommonOptions}; -use anyhow::{bail, Context as _, Result}; -use std::{fmt::Write, path::PathBuf}; +use anyhow::{Context as _, Result}; +use std::path::PathBuf; use structopt::{clap::AppSettings, StructOpt}; use wasmtime::{Config, Engine, Store}; -use wasmtime_environ::cache_init; use wasmtime_wast::WastContext; /// Runs a WebAssembly test script file @@ -27,28 +26,11 @@ pub struct WastCommand { impl WastCommand { /// Executes the command. pub fn execute(&self) -> Result<()> { - let log_config = if self.common.debug { + if self.common.debug { pretty_env_logger::init(); - None } else { let prefix = "wast.dbg."; init_file_per_thread_logger(prefix); - Some(prefix) - }; - - let errors = cache_init( - !self.common.disable_cache, - self.common.config.as_ref(), - log_config, - ); - - if !errors.is_empty() { - let mut message = String::new(); - writeln!(message, "Cache initialization failed. Errors:")?; - for e in errors { - writeln!(message, " -> {}", e)?; - } - bail!(message); } let mut config = Config::new(); @@ -60,6 +42,7 @@ impl WastCommand { self.common.cranelift, self.common.lightbeam, )?)?; + self.common.configure_cache(&mut config)?; if self.common.optimize { config.cranelift_opt_level(wasmtime::OptLevel::Speed); diff --git a/src/lib.rs b/src/lib.rs index a7324668fc..9b639512f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,7 +29,7 @@ pub mod commands; use anyhow::{bail, Result}; use std::path::PathBuf; use structopt::StructOpt; -use wasmtime::Strategy; +use wasmtime::{Config, Strategy}; fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result { Ok(match (lightbeam, cranelift) { @@ -101,3 +101,20 @@ struct CommonOptions { #[structopt(short = "O", long)] optimize: bool, } + +impl CommonOptions { + fn configure_cache(&self, config: &mut Config) -> Result<()> { + if self.disable_cache { + return Ok(()); + } + match &self.config { + Some(path) => { + config.cache_config_load(path)?; + } + None => { + config.cache_config_load_default()?; + } + } + Ok(()) + } +} diff --git a/tests/instantiate.rs b/tests/instantiate.rs index aeac14b6bc..7b21cdf784 100644 --- a/tests/instantiate.rs +++ b/tests/instantiate.rs @@ -2,6 +2,7 @@ use more_asserts::assert_gt; use std::path::PathBuf; use wasmtime_environ::settings; use wasmtime_environ::settings::Configurable; +use wasmtime_environ::CacheConfig; use wasmtime_jit::{instantiate, native, CompilationStrategy, Compiler, NullResolver}; const PATH_MODULE_RS2WASM_ADD_FUNC: &str = r"tests/wat/rs2wasm-add-func.wat"; @@ -20,7 +21,8 @@ fn test_environ_translate() { let isa = isa_builder.finish(settings::Flags::new(flag_builder)); let mut resolver = NullResolver {}; - let mut compiler = Compiler::new(isa, CompilationStrategy::Auto); + let cache_config = CacheConfig::new_cache_disabled(); + let mut compiler = Compiler::new(isa, CompilationStrategy::Auto, cache_config); unsafe { let instance = instantiate(&mut compiler, &data, &mut resolver, false); assert!(instance.is_ok());