Cache config as a file
This commit is contained in:
@@ -50,7 +50,7 @@ use std::str;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use target_lexicon::Triple;
|
use target_lexicon::Triple;
|
||||||
use wasmtime_debug::{emit_debugsections, read_debuginfo};
|
use wasmtime_debug::{emit_debugsections, read_debuginfo};
|
||||||
use wasmtime_environ::cache_conf;
|
use wasmtime_environ::cache_config;
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
Compiler, Cranelift, ModuleEnvironment, ModuleVmctxInfo, Tunables, VMOffsets,
|
Compiler, Cranelift, ModuleEnvironment, ModuleVmctxInfo, Tunables, VMOffsets,
|
||||||
};
|
};
|
||||||
@@ -63,7 +63,7 @@ The translation is dependent on the environment chosen.
|
|||||||
The default is a dummy environment that produces placeholder values.
|
The default is a dummy environment that produces placeholder values.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
wasm2obj [--target TARGET] [-dg] [--cache] [--cache-dir=<cache_dir>] [--cache-compression-level=<compr_level>] [--enable-simd] <file> -o <output>
|
wasm2obj [--target TARGET] [-dg] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--enable-simd] <file> -o <output>
|
||||||
wasm2obj --help | --version
|
wasm2obj --help | --version
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@@ -71,11 +71,12 @@ Options:
|
|||||||
-h, --help print this help message
|
-h, --help print this help message
|
||||||
--target <TARGET> build for the target triple; default is the host machine
|
--target <TARGET> build for the target triple; default is the host machine
|
||||||
-g generate debug information
|
-g generate debug information
|
||||||
-c, --cache enable caching system, use default cache directory
|
-c, --cache enable caching system, use default configuration
|
||||||
--cache-dir=<cache_dir>
|
--cache-config=<cache_config_file>
|
||||||
enable caching system, use specified cache directory
|
enable caching system, use specified cache configuration
|
||||||
--cache-compression-level=<compr_level>
|
--create-cache-config
|
||||||
enable caching system, use custom compression level for new cache, values 1-21
|
used with --cache or --cache-config, creates default configuration and writes it to the disk,
|
||||||
|
will fail if specified file already exists (or default file if used with --cache)
|
||||||
--enable-simd enable proposed SIMD instructions
|
--enable-simd enable proposed SIMD instructions
|
||||||
--version print the Cranelift version
|
--version print the Cranelift version
|
||||||
-d, --debug enable debug output on stderr/stdout
|
-d, --debug enable debug output on stderr/stdout
|
||||||
@@ -88,9 +89,9 @@ struct Args {
|
|||||||
arg_target: Option<String>,
|
arg_target: Option<String>,
|
||||||
flag_g: bool,
|
flag_g: bool,
|
||||||
flag_debug: bool,
|
flag_debug: bool,
|
||||||
flag_cache: bool,
|
flag_cache: bool, // TODO change to disable cache after implementing cache eviction
|
||||||
flag_cache_dir: Option<String>,
|
flag_cache_config_file: Option<String>,
|
||||||
flag_cache_compression_level: Option<i32>,
|
flag_create_cache_config: bool,
|
||||||
flag_enable_simd: bool,
|
flag_enable_simd: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,14 +118,20 @@ fn main() {
|
|||||||
wasmtime::init_file_per_thread_logger("wasm2obj.dbg.");
|
wasmtime::init_file_per_thread_logger("wasm2obj.dbg.");
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_conf::init(
|
let errors = cache_config::init(
|
||||||
args.flag_cache
|
args.flag_cache || args.flag_cache_config_file.is_some(),
|
||||||
|| args.flag_cache_dir.is_some()
|
args.flag_cache_config_file.as_ref(),
|
||||||
|| args.flag_cache_compression_level.is_some(),
|
args.flag_create_cache_config,
|
||||||
args.flag_cache_dir.as_ref(),
|
|
||||||
args.flag_cache_compression_level,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if !errors.is_empty() {
|
||||||
|
eprintln!("Cache initialization failed. Errors:");
|
||||||
|
for e in errors {
|
||||||
|
eprintln!("-> {}", e);
|
||||||
|
}
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
let path = Path::new(&args.arg_file);
|
let path = Path::new(&args.arg_file);
|
||||||
match handle_module(
|
match handle_module(
|
||||||
path.to_path_buf(),
|
path.to_path_buf(),
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ use std::rc::Rc;
|
|||||||
use wabt;
|
use wabt;
|
||||||
use wasi_common::preopen_dir;
|
use wasi_common::preopen_dir;
|
||||||
use wasmtime_api::{Config, Engine, Instance, Module, Store};
|
use wasmtime_api::{Config, Engine, Instance, Module, Store};
|
||||||
use wasmtime_environ::cache_conf;
|
use wasmtime_environ::cache_config;
|
||||||
use wasmtime_interface_types::ModuleData;
|
use wasmtime_interface_types::ModuleData;
|
||||||
use wasmtime_jit::Features;
|
use wasmtime_jit::Features;
|
||||||
use wasmtime_wasi::instantiate_wasi;
|
use wasmtime_wasi::instantiate_wasi;
|
||||||
@@ -64,18 +64,19 @@ including calling the start function if one is present. Additional functions
|
|||||||
given with --invoke are then called.
|
given with --invoke are then called.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
wasmtime [-odg] [--enable-simd] [--wasi-c] [--cache] [--cache-dir=<cache_dir>] [--cache-compression-level=<compr_level>] [--preload=<wasm>...] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] <file> [<arg>...]
|
wasmtime [-odg] [--enable-simd] [--wasi-c] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--preload=<wasm>...] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] <file> [<arg>...]
|
||||||
wasmtime [-odg] [--enable-simd] [--wasi-c] [--cache] [--cache-dir=<cache_dir>] [--cache-compression-level=<compr_level>] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] --invoke=<fn> <file> [<arg>...]
|
wasmtime [-odg] [--enable-simd] [--wasi-c] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] [--env=<env>...] [--dir=<dir>...] [--mapdir=<mapping>...] --invoke=<fn> <file> [<arg>...]
|
||||||
wasmtime --help | --version
|
wasmtime --help | --version
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--invoke=<fn> name of function to run
|
--invoke=<fn> name of function to run
|
||||||
-o, --optimize runs optimization passes on the translated functions
|
-o, --optimize runs optimization passes on the translated functions
|
||||||
-c, --cache enable caching system, use default cache directory
|
-c, --cache enable caching system, use default configuration
|
||||||
--cache-dir=<cache_dir>
|
--cache-config=<cache_config_file>
|
||||||
enable caching system, use specified cache directory
|
enable caching system, use specified cache configuration
|
||||||
--cache-compression-level=<compr_level>
|
--create-cache-config
|
||||||
enable caching system, use custom compression level for new cache, values 1-21
|
used with --cache or --cache-config, creates default configuration and writes it to the disk,
|
||||||
|
will fail if specified file already exists (or default file if used with --cache)
|
||||||
-g generate debug information
|
-g generate debug information
|
||||||
-d, --debug enable debug output on stderr/stdout
|
-d, --debug enable debug output on stderr/stdout
|
||||||
--enable-simd enable proposed SIMD instructions
|
--enable-simd enable proposed SIMD instructions
|
||||||
@@ -94,9 +95,9 @@ struct Args {
|
|||||||
arg_file: String,
|
arg_file: String,
|
||||||
arg_arg: Vec<String>,
|
arg_arg: Vec<String>,
|
||||||
flag_optimize: bool,
|
flag_optimize: bool,
|
||||||
flag_cache: bool,
|
flag_cache: bool, // TODO change to disable cache after implementing cache eviction
|
||||||
flag_cache_dir: Option<String>,
|
flag_cache_config_file: Option<String>,
|
||||||
flag_cache_compression_level: Option<i32>,
|
flag_create_cache_config: bool,
|
||||||
flag_debug: bool,
|
flag_debug: bool,
|
||||||
flag_g: bool,
|
flag_g: bool,
|
||||||
flag_enable_simd: bool,
|
flag_enable_simd: bool,
|
||||||
@@ -201,7 +202,7 @@ fn main() {
|
|||||||
for cause in err.iter_causes() {
|
for cause in err.iter_causes() {
|
||||||
eprintln!(" caused by: {}", cause);
|
eprintln!(" caused by: {}", cause);
|
||||||
}
|
}
|
||||||
std::process::exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rmain() -> Result<(), Error> {
|
fn rmain() -> Result<(), Error> {
|
||||||
@@ -220,14 +221,20 @@ fn rmain() -> Result<(), Error> {
|
|||||||
wasmtime::init_file_per_thread_logger("wasmtime.dbg.");
|
wasmtime::init_file_per_thread_logger("wasmtime.dbg.");
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_conf::init(
|
let errors = cache_config::init(
|
||||||
args.flag_cache
|
args.flag_cache || args.flag_cache_config_file.is_some(),
|
||||||
|| args.flag_cache_dir.is_some()
|
args.flag_cache_config_file.as_ref(),
|
||||||
|| args.flag_cache_compression_level.is_some(),
|
args.flag_create_cache_config,
|
||||||
args.flag_cache_dir.as_ref(),
|
|
||||||
args.flag_cache_compression_level,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if !errors.is_empty() {
|
||||||
|
eprintln!("Cache initialization failed. Errors:");
|
||||||
|
for e in errors {
|
||||||
|
eprintln!("-> {}", e);
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
let mut flag_builder = settings::builder();
|
let mut flag_builder = settings::builder();
|
||||||
let mut features: Features = Default::default();
|
let mut features: Features = Default::default();
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ use pretty_env_logger;
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process;
|
use std::process;
|
||||||
use wasmtime_environ::cache_conf;
|
use wasmtime_environ::cache_config;
|
||||||
use wasmtime_jit::{Compiler, Features};
|
use wasmtime_jit::{Compiler, Features};
|
||||||
use wasmtime_wast::WastContext;
|
use wasmtime_wast::WastContext;
|
||||||
|
|
||||||
@@ -41,18 +41,19 @@ const USAGE: &str = "
|
|||||||
Wast test runner.
|
Wast test runner.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
wast [-do] [--enable-simd] [--cache] [--cache-dir=<cache_dir>] [--cache-compression-level=<compr_level>] <file>...
|
wast [-do] [--enable-simd] [--cache | --cache-config=<cache_config_file>] [--create-cache-config] <file>...
|
||||||
wast --help | --version
|
wast --help | --version
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-h, --help print this help message
|
-h, --help print this help message
|
||||||
--version print the Cranelift version
|
--version print the Cranelift version
|
||||||
-o, --optimize runs optimization passes on the translated functions
|
-o, --optimize runs optimization passes on the translated functions
|
||||||
-c, --cache enable caching system, use default cache directory
|
-c, --cache enable caching system, use default configuration
|
||||||
--cache-dir=<cache_dir>
|
--cache-config=<cache_config_file>
|
||||||
enable caching system, use specified cache directory
|
enable caching system, use specified cache configuration
|
||||||
--cache-compression-level=<compr_level>
|
--create-cache-config
|
||||||
enable caching system, use custom compression level for new cache, values 1-21
|
used with --cache or --cache-config, creates default configuration and writes it to the disk,
|
||||||
|
will fail if specified file already exists (or default file if used with --cache)
|
||||||
-d, --debug enable debug output on stderr/stdout
|
-d, --debug enable debug output on stderr/stdout
|
||||||
--enable-simd enable proposed SIMD instructions
|
--enable-simd enable proposed SIMD instructions
|
||||||
";
|
";
|
||||||
@@ -63,9 +64,9 @@ struct Args {
|
|||||||
flag_debug: bool,
|
flag_debug: bool,
|
||||||
flag_function: Option<String>,
|
flag_function: Option<String>,
|
||||||
flag_optimize: bool,
|
flag_optimize: bool,
|
||||||
flag_cache: bool,
|
flag_cache: bool, // TODO change to disable cache after implementing cache eviction
|
||||||
flag_cache_dir: Option<String>,
|
flag_cache_config_file: Option<String>,
|
||||||
flag_cache_compression_level: Option<i32>,
|
flag_create_cache_config: bool,
|
||||||
flag_enable_simd: bool,
|
flag_enable_simd: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,14 +86,20 @@ fn main() {
|
|||||||
wasmtime::init_file_per_thread_logger("cranelift.dbg.");
|
wasmtime::init_file_per_thread_logger("cranelift.dbg.");
|
||||||
}
|
}
|
||||||
|
|
||||||
cache_conf::init(
|
let errors = cache_config::init(
|
||||||
args.flag_cache
|
args.flag_cache || args.flag_cache_config_file.is_some(),
|
||||||
|| args.flag_cache_dir.is_some()
|
args.flag_cache_config_file.as_ref(),
|
||||||
|| args.flag_cache_compression_level.is_some(),
|
args.flag_create_cache_config,
|
||||||
args.flag_cache_dir.as_ref(),
|
|
||||||
args.flag_cache_compression_level,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if !errors.is_empty() {
|
||||||
|
eprintln!("Cache initialization failed. Errors:");
|
||||||
|
for e in errors {
|
||||||
|
eprintln!("-> {}", e);
|
||||||
|
}
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
let isa_builder = cranelift_native::builder().unwrap_or_else(|_| {
|
let isa_builder = cranelift_native::builder().unwrap_or_else(|_| {
|
||||||
panic!("host machine is not a supported target");
|
panic!("host machine is not a supported target");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ lazy_static = "1.3.0"
|
|||||||
spin = "0.5.0"
|
spin = "0.5.0"
|
||||||
log = { version = "0.4.8", default-features = false }
|
log = { version = "0.4.8", default-features = false }
|
||||||
zstd = "0.4"
|
zstd = "0.4"
|
||||||
|
toml = "0.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|||||||
@@ -15,138 +15,8 @@ use std::io;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::string::{String, ToString};
|
use std::string::{String, ToString};
|
||||||
|
|
||||||
/// Module for configuring the cache system.
|
pub mod config;
|
||||||
pub mod conf {
|
use config as cache_config; // so we have namespaced methods
|
||||||
use directories::ProjectDirs;
|
|
||||||
use log::{debug, warn};
|
|
||||||
use spin::Once;
|
|
||||||
use std::fs;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
struct Config {
|
|
||||||
pub cache_enabled: bool,
|
|
||||||
pub cache_dir: PathBuf,
|
|
||||||
pub compression_level: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private static, so only internal function can access it.
|
|
||||||
static CONFIG: Once<Config> = Once::new();
|
|
||||||
static INIT_CALLED: AtomicBool = AtomicBool::new(false);
|
|
||||||
static DEFAULT_COMPRESSION_LEVEL: i32 = 0; // 0 for zstd means "use default level"
|
|
||||||
|
|
||||||
/// Returns true if and only if the cache is enabled.
|
|
||||||
pub fn cache_enabled() -> bool {
|
|
||||||
// Not everyone knows about the cache system, i.e. the tests,
|
|
||||||
// so the default is cache disabled.
|
|
||||||
CONFIG
|
|
||||||
.call_once(|| Config::new_cache_disabled())
|
|
||||||
.cache_enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns path to the cache directory.
|
|
||||||
///
|
|
||||||
/// Panics if the cache is disabled.
|
|
||||||
pub fn cache_directory() -> &'static PathBuf {
|
|
||||||
&CONFIG
|
|
||||||
.r#try()
|
|
||||||
.expect("Cache system must be initialized")
|
|
||||||
.cache_dir
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns cache compression level.
|
|
||||||
///
|
|
||||||
/// Panics if the cache is disabled.
|
|
||||||
pub fn compression_level() -> i32 {
|
|
||||||
CONFIG
|
|
||||||
.r#try()
|
|
||||||
.expect("Cache system must be initialized")
|
|
||||||
.compression_level
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes the cache system. Should be called exactly once,
|
|
||||||
/// and before using the cache system. Otherwise it can panic.
|
|
||||||
pub fn init<P: AsRef<Path>>(enabled: bool, dir: Option<P>, compression_level: Option<i32>) {
|
|
||||||
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 = CONFIG.call_once(|| {
|
|
||||||
Config::new(
|
|
||||||
enabled,
|
|
||||||
dir,
|
|
||||||
compression_level.unwrap_or(DEFAULT_COMPRESSION_LEVEL),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
debug!(
|
|
||||||
"Cache init(): enabled={}, cache-dir={:?}, compression-level={}",
|
|
||||||
conf.cache_enabled, conf.cache_dir, conf.compression_level,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn new_cache_disabled() -> Self {
|
|
||||||
Self {
|
|
||||||
cache_enabled: false,
|
|
||||||
cache_dir: PathBuf::new(),
|
|
||||||
compression_level: DEFAULT_COMPRESSION_LEVEL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new<P: AsRef<Path>>(enabled: bool, dir: Option<P>, compression_level: i32) -> Self {
|
|
||||||
if enabled {
|
|
||||||
match dir {
|
|
||||||
Some(dir) => Self::new_step2(dir.as_ref(), compression_level),
|
|
||||||
None => match ProjectDirs::from("", "CraneStation", "wasmtime") {
|
|
||||||
Some(proj_dirs) => {
|
|
||||||
Self::new_step2(proj_dirs.cache_dir(), compression_level)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
warn!("Cache directory not specified and failed to find the default. Disabling cache.");
|
|
||||||
Self::new_cache_disabled()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Self::new_cache_disabled()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_step2(dir: &Path, compression_level: i32) -> Self {
|
|
||||||
// On Windows, if we want long paths, we need '\\?\' prefix, but it doesn't work
|
|
||||||
// with relative paths. One way to get absolute path (the only one?) is to use
|
|
||||||
// fs::canonicalize, but it requires that given path exists. The extra advantage
|
|
||||||
// of this method is fact that the method prepends '\\?\' on Windows.
|
|
||||||
match fs::create_dir_all(dir) {
|
|
||||||
Ok(()) => match fs::canonicalize(dir) {
|
|
||||||
Ok(p) => Self {
|
|
||||||
cache_enabled: true,
|
|
||||||
cache_dir: p,
|
|
||||||
compression_level,
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
warn!(
|
|
||||||
"Failed to canonicalize the cache directory. Disabling cache. \
|
|
||||||
Message: {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
Self::new_cache_disabled()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
warn!(
|
|
||||||
"Failed to create the cache directory. Disabling cache. Message: {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
Self::new_cache_disabled()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref SELF_MTIME: String = {
|
static ref SELF_MTIME: String = {
|
||||||
@@ -205,7 +75,7 @@ impl ModuleCacheEntry {
|
|||||||
compiler_name: &str,
|
compiler_name: &str,
|
||||||
generate_debug_info: bool,
|
generate_debug_info: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mod_cache_path = if conf::cache_enabled() {
|
let mod_cache_path = if cache_config::enabled() {
|
||||||
let hash = Sha256Hasher::digest(module, function_body_inputs);
|
let hash = Sha256Hasher::digest(module, function_body_inputs);
|
||||||
let compiler_dir = if cfg!(debug_assertions) {
|
let compiler_dir = if cfg!(debug_assertions) {
|
||||||
format!(
|
format!(
|
||||||
@@ -227,7 +97,7 @@ impl ModuleCacheEntry {
|
|||||||
mod_dbg = if generate_debug_info { ".d" } else { "" },
|
mod_dbg = if generate_debug_info { ".d" } else { "" },
|
||||||
);
|
);
|
||||||
Some(
|
Some(
|
||||||
conf::cache_directory()
|
cache_config::directory()
|
||||||
.join(isa.triple().to_string())
|
.join(isa.triple().to_string())
|
||||||
.join(compiler_dir)
|
.join(compiler_dir)
|
||||||
.join(mod_filename),
|
.join(mod_filename),
|
||||||
@@ -261,7 +131,10 @@ impl ModuleCacheEntry {
|
|||||||
let serialized_data = bincode::serialize(&data)
|
let serialized_data = bincode::serialize(&data)
|
||||||
.map_err(|err| warn!("Failed to serialize cached code: {}", err))
|
.map_err(|err| warn!("Failed to serialize cached code: {}", err))
|
||||||
.ok()?;
|
.ok()?;
|
||||||
let compressed_data = zstd::encode_all(&serialized_data[..], conf::compression_level())
|
let compressed_data = zstd::encode_all(
|
||||||
|
&serialized_data[..],
|
||||||
|
cache_config::baseline_compression_level(),
|
||||||
|
)
|
||||||
.map_err(|err| warn!("Failed to compress cached code: {}", err))
|
.map_err(|err| warn!("Failed to compress cached code: {}", err))
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
|
|||||||
340
wasmtime-environ/src/cache/config.rs
vendored
Normal file
340
wasmtime-environ/src/cache/config.rs
vendored
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
//! Module for configuring the cache system.
|
||||||
|
|
||||||
|
use directories::ProjectDirs;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use log::{debug, error, trace};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use spin::Once;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::fs;
|
||||||
|
use std::mem;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::string::{String, ToString};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
// wrapped, so we have named section in config,
|
||||||
|
// also, for possible future compatibility
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Config {
|
||||||
|
cache: CacheConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct CacheConfig {
|
||||||
|
#[serde(skip)]
|
||||||
|
pub errors: Vec<String>,
|
||||||
|
|
||||||
|
pub enabled: bool,
|
||||||
|
pub directory: Option<PathBuf>,
|
||||||
|
#[serde(rename = "baseline-compression-level")]
|
||||||
|
pub baseline_compression_level: Option<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private static, so only internal function can access it.
|
||||||
|
static CONFIG: Once<CacheConfig> = Once::new();
|
||||||
|
static INIT_CALLED: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
|
/// Returns true if and only if the cache is enabled.
|
||||||
|
pub fn enabled() -> bool {
|
||||||
|
// Not everyone knows about the cache system, i.e. the tests,
|
||||||
|
// so the default is cache disabled.
|
||||||
|
CONFIG
|
||||||
|
.call_once(|| CacheConfig::new_cache_disabled())
|
||||||
|
.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns path to the cache directory.
|
||||||
|
///
|
||||||
|
/// Panics if the cache is disabled.
|
||||||
|
pub fn directory() -> &'static PathBuf {
|
||||||
|
&CONFIG
|
||||||
|
.r#try()
|
||||||
|
.expect("Cache system must be initialized")
|
||||||
|
.directory
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns cache compression level.
|
||||||
|
///
|
||||||
|
/// Panics if the cache is disabled.
|
||||||
|
pub fn baseline_compression_level() -> i32 {
|
||||||
|
CONFIG
|
||||||
|
.r#try()
|
||||||
|
.expect("Cache system must be initialized")
|
||||||
|
.baseline_compression_level
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<P: AsRef<Path> + Debug>(
|
||||||
|
enabled: bool,
|
||||||
|
config_file: Option<P>,
|
||||||
|
create_new_config: bool,
|
||||||
|
) -> &'static Vec<String> {
|
||||||
|
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, create_new_config));
|
||||||
|
if conf.errors.is_empty() {
|
||||||
|
debug!(
|
||||||
|
"Cache init(\"{}\"): enabled={}, directory={:?}, baseline-compression-level={:?}",
|
||||||
|
conf_file_str, conf.enabled, conf.directory, conf.baseline_compression_level,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Cache init(\"{}\"): errors: {:#?}",
|
||||||
|
conf_file_str, conf.errors,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
&conf.errors
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<i32> = 0..=21;
|
||||||
|
lazy_static! {
|
||||||
|
static ref PROJECT_DIRS: Option<ProjectDirs> =
|
||||||
|
ProjectDirs::from("", "CraneStation", "wasmtime");
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CacheConfig {
|
||||||
|
pub fn new_cache_disabled() -> Self {
|
||||||
|
Self {
|
||||||
|
errors: Vec::new(),
|
||||||
|
enabled: false,
|
||||||
|
directory: None,
|
||||||
|
baseline_compression_level: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_cache_enabled_template() -> Self {
|
||||||
|
let mut conf = Self::new_cache_disabled();
|
||||||
|
conf.enabled = true;
|
||||||
|
conf
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_cache_with_errors(errors: Vec<String>) -> Self {
|
||||||
|
let mut conf = Self::new_cache_disabled();
|
||||||
|
conf.errors = errors;
|
||||||
|
conf
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_file<P: AsRef<Path>>(
|
||||||
|
enabled: bool,
|
||||||
|
config_file: Option<P>,
|
||||||
|
create_new_config: bool,
|
||||||
|
) -> Self {
|
||||||
|
if !enabled {
|
||||||
|
return Self::new_cache_disabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut config, path_if_flush_to_disk) =
|
||||||
|
match Self::load_and_parse_file(config_file, create_new_config) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => return Self::new_cache_with_errors(vec![err]),
|
||||||
|
};
|
||||||
|
|
||||||
|
// validate values and fill in defaults
|
||||||
|
config.validate_cache_directory_or_default();
|
||||||
|
config.validate_baseline_compression_level_or_default();
|
||||||
|
|
||||||
|
path_if_flush_to_disk.map(|p| config.flush_to_disk(p));
|
||||||
|
|
||||||
|
config.disable_if_any_error();
|
||||||
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_and_parse_file<P: AsRef<Path>>(
|
||||||
|
config_file: Option<P>,
|
||||||
|
create_new_config: bool,
|
||||||
|
) -> Result<(Self, Option<PathBuf>), String> {
|
||||||
|
// get config file path
|
||||||
|
let (config_file, user_custom_file) = match config_file {
|
||||||
|
Some(p) => (PathBuf::from(p.as_ref()), true),
|
||||||
|
None => match &*PROJECT_DIRS {
|
||||||
|
Some(proj_dirs) => (
|
||||||
|
proj_dirs.config_dir().join("wasmtime-cache-config.toml"),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
None => Err("Config file not specified and failed to get the default".to_string())?,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// read config, or create an empty one
|
||||||
|
let entity_exists = config_file.exists();
|
||||||
|
match (create_new_config, entity_exists, user_custom_file) {
|
||||||
|
(true, true, _) => Err(format!(
|
||||||
|
"Tried to create a new config, but given entity already exists, path: {}",
|
||||||
|
config_file.display()
|
||||||
|
)),
|
||||||
|
(true, false, _) => Ok((Self::new_cache_enabled_template(), Some(config_file))),
|
||||||
|
(false, false, false) => Ok((Self::new_cache_enabled_template(), None)),
|
||||||
|
(false, _, _) => match fs::read(&config_file) {
|
||||||
|
Ok(bytes) => match toml::from_slice::<Config>(&bytes[..]) {
|
||||||
|
Ok(config) => Ok((config.cache, None)),
|
||||||
|
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
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_cache_directory_or_default(&mut self) {
|
||||||
|
if self.directory.is_none() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows, if we want long paths, we need '\\?\' prefix, but it doesn't work
|
||||||
|
// with relative paths. One way to get absolute path (the only one?) is to use
|
||||||
|
// fs::canonicalize, but it requires that given path exists. The extra advantage
|
||||||
|
// of this method is fact that the method prepends '\\?\' on Windows.
|
||||||
|
let cache_dir = self.directory.as_ref().unwrap();
|
||||||
|
|
||||||
|
if !cache_dir.is_absolute() {
|
||||||
|
self.errors.push(format!(
|
||||||
|
"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
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_baseline_compression_level_or_default(&mut self) {
|
||||||
|
if self.baseline_compression_level.is_none() {
|
||||||
|
self.baseline_compression_level = Some(zstd::DEFAULT_COMPRESSION_LEVEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !ZSTD_COMPRESSION_LEVELS.contains(&self.baseline_compression_level.unwrap()) {
|
||||||
|
self.errors.push(format!(
|
||||||
|
"Invalid baseline compression level: {} not in {:#?}",
|
||||||
|
self.baseline_compression_level.unwrap(),
|
||||||
|
ZSTD_COMPRESSION_LEVELS
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_to_disk(&mut self, path: PathBuf) {
|
||||||
|
if !self.errors.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!(
|
||||||
|
"Flushing cache config file to the disk, path: {}",
|
||||||
|
path.display()
|
||||||
|
);
|
||||||
|
|
||||||
|
let parent_dir = match path.parent() {
|
||||||
|
Some(p) => p,
|
||||||
|
None => {
|
||||||
|
self.errors
|
||||||
|
.push(format!("Invalid cache config path: {}", path.display()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match fs::create_dir_all(parent_dir) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => {
|
||||||
|
self.errors.push(format!(
|
||||||
|
"Failed to create config directory, config path: {}, error: {}",
|
||||||
|
path.display(),
|
||||||
|
err
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized = match self.exec_as_config(|config| toml::to_string_pretty(&config)) {
|
||||||
|
Ok(data) => data,
|
||||||
|
Err(err) => {
|
||||||
|
self.errors.push(format!(
|
||||||
|
"Failed to serialize config, (unused) path: {}, msg: {}",
|
||||||
|
path.display(),
|
||||||
|
err
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let header = "# Automatically generated with defaults.\n\
|
||||||
|
# Comment out certain fields to use default values.\n\n";
|
||||||
|
|
||||||
|
let content = format!("{}{}", header, serialized);
|
||||||
|
match fs::write(&path, &content) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => {
|
||||||
|
self.errors.push(format!(
|
||||||
|
"Failed to flush config to the disk, path: {}, msg: {}",
|
||||||
|
path.display(),
|
||||||
|
err
|
||||||
|
));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exec_as_config<T>(&mut self, closure: impl FnOnce(&mut Config) -> T) -> T {
|
||||||
|
let mut config = Config {
|
||||||
|
cache: CacheConfig::new_cache_disabled(),
|
||||||
|
};
|
||||||
|
mem::swap(self, &mut config.cache);
|
||||||
|
let ret = closure(&mut config);
|
||||||
|
mem::swap(self, &mut config.cache);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
30
wasmtime-environ/src/cache/tests.rs
vendored
30
wasmtime-environ/src/cache/tests.rs
vendored
@@ -25,15 +25,33 @@ use tempfile;
|
|||||||
fn test_write_read_cache() {
|
fn test_write_read_cache() {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
||||||
let compression_level = 5;
|
|
||||||
conf::init(true, Some(dir.path()), Some(compression_level));
|
let cache_dir = dir.path().join("cache-dir");
|
||||||
assert!(conf::cache_enabled());
|
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_config::init(true, Some(&config_path), false);
|
||||||
|
assert!(errors.is_empty());
|
||||||
|
assert!(cache_config::enabled());
|
||||||
// assumption: config init creates cache directory and returns canonicalized path
|
// assumption: config init creates cache directory and returns canonicalized path
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*conf::cache_directory(),
|
*cache_config::directory(),
|
||||||
fs::canonicalize(dir.path()).unwrap()
|
fs::canonicalize(cache_dir).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cache_config::baseline_compression_level(),
|
||||||
|
baseline_compression_level
|
||||||
);
|
);
|
||||||
assert_eq!(conf::compression_level(), compression_level);
|
|
||||||
|
|
||||||
let mut rng = SmallRng::from_seed([
|
let mut rng = SmallRng::from_seed([
|
||||||
0x42, 0x04, 0xF3, 0x44, 0x11, 0x22, 0x33, 0x44, 0x67, 0x68, 0xFF, 0x00, 0x44, 0x23, 0x7F,
|
0x42, 0x04, 0xF3, 0x44, 0x11, 0x22, 0x33, 0x44, 0x67, 0x68, 0xFF, 0x00, 0x44, 0x23, 0x7F,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub mod lightbeam;
|
|||||||
pub use crate::address_map::{
|
pub use crate::address_map::{
|
||||||
FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges,
|
FunctionAddressMap, InstructionAddressMap, ModuleAddressMap, ModuleVmctxInfo, ValueLabelsRanges,
|
||||||
};
|
};
|
||||||
pub use crate::cache::conf as cache_conf;
|
pub use crate::cache::config as cache_config;
|
||||||
pub use crate::compilation::{
|
pub use crate::compilation::{
|
||||||
Compilation, CompileError, Compiler, Relocation, RelocationTarget, Relocations,
|
Compilation, CompileError, Compiler, Relocation, RelocationTarget, Relocations,
|
||||||
};
|
};
|
||||||
|
|||||||
7
wasmtime-environ/tests/cache_default_config_in_memory.rs
Normal file
7
wasmtime-environ/tests/cache_default_config_in_memory.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
use wasmtime_environ::cache_config;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cache_default_config_in_memory() {
|
||||||
|
let errors = cache_config::init::<&str>(true, None, false);
|
||||||
|
assert!(errors.is_empty());
|
||||||
|
}
|
||||||
@@ -1,10 +1,26 @@
|
|||||||
|
use std::fs;
|
||||||
use tempfile;
|
use tempfile;
|
||||||
use wasmtime_environ::cache_conf;
|
use wasmtime_environ::cache_config;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_fail_calling_init_twice() {
|
fn test_cache_fail_calling_init_twice() {
|
||||||
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
||||||
cache_conf::init(true, Some(dir.path()), Some(5));
|
let cache_dir = dir.path().join("cache-dir");
|
||||||
cache_conf::init(true, Some(dir.path()), Some(5));
|
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_config::init(true, Some(&config_path), false);
|
||||||
|
assert!(errors.is_empty());
|
||||||
|
let _errors = cache_config::init(true, Some(&config_path), false);
|
||||||
}
|
}
|
||||||
|
|||||||
23
wasmtime-environ/tests/cache_fail_invalid_config.rs
Normal file
23
wasmtime-environ/tests/cache_fail_invalid_config.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use std::fs;
|
||||||
|
use tempfile;
|
||||||
|
use wasmtime_environ::cache_config;
|
||||||
|
|
||||||
|
#[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_config::init(true, Some(&config_path), false);
|
||||||
|
assert!(!errors.is_empty());
|
||||||
|
}
|
||||||
10
wasmtime-environ/tests/cache_fail_invalid_path_to_config.rs
Normal file
10
wasmtime-environ/tests/cache_fail_invalid_path_to_config.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
use tempfile;
|
||||||
|
use wasmtime_environ::cache_config;
|
||||||
|
|
||||||
|
#[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_config::init(true, Some(&config_path), false);
|
||||||
|
assert!(!errors.is_empty());
|
||||||
|
}
|
||||||
@@ -1,7 +1,15 @@
|
|||||||
use wasmtime_environ::cache_conf;
|
// These tests doesn't call init(), so we can test a multiple certain things here
|
||||||
|
|
||||||
|
use wasmtime_environ::cache_config;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn test_fail_usage_without_init() {
|
fn test_cache_fail_usage_without_init_directory() {
|
||||||
let _ = cache_conf::cache_directory();
|
let _ = cache_config::directory();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_cache_fail_usage_without_init_baseline_compression_level() {
|
||||||
|
let _ = cache_config::baseline_compression_level();
|
||||||
}
|
}
|
||||||
|
|||||||
12
wasmtime-environ/tests/cache_write_default_config.rs
Normal file
12
wasmtime-environ/tests/cache_write_default_config.rs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
use tempfile;
|
||||||
|
use wasmtime_environ::cache_config;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cache_write_default_config() {
|
||||||
|
let dir = tempfile::tempdir().expect("Can't create temporary directory");
|
||||||
|
let config_path = dir.path().join("cache-config.toml");
|
||||||
|
|
||||||
|
let errors = cache_config::init(true, Some(&config_path), true);
|
||||||
|
assert!(errors.is_empty());
|
||||||
|
assert!(config_path.exists());
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user