Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/bin/wasm2obj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use std::str;
use std::str::FromStr;
use target_lexicon::Triple;
use wasmtime_debug::{emit_debugsections, read_debuginfo};
use wasmtime_environ::cache_config;
use wasmtime_environ::cache_init;
use wasmtime_environ::{
Compiler, Cranelift, ModuleEnvironment, ModuleVmctxInfo, Tunables, VMOffsets,
};
Expand Down Expand Up @@ -121,7 +121,7 @@ fn main() {
Some(prefix)
};

let errors = cache_config::init(
let errors = cache_init(
args.flag_cache || args.flag_cache_config_file.is_some(),
args.flag_cache_config_file.as_ref(),
args.flag_create_cache_config,
Expand Down
4 changes: 2 additions & 2 deletions src/bin/wasmtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use std::process::exit;
use wabt;
use wasi_common::preopen_dir;
use wasmtime_api::{Config, Engine, HostRef, Instance, Module, Store};
use wasmtime_environ::cache_config;
use wasmtime_environ::cache_init;
use wasmtime_interface_types::ModuleData;
use wasmtime_jit::Features;
use wasmtime_wasi::instantiate_wasi;
Expand Down Expand Up @@ -222,7 +222,7 @@ fn rmain() -> Result<(), Error> {
Some(prefix)
};

let errors = cache_config::init(
let errors = cache_init(
args.flag_cache || args.flag_cache_config_file.is_some(),
args.flag_cache_config_file.as_ref(),
args.flag_create_cache_config,
Expand Down
4 changes: 2 additions & 2 deletions src/bin/wast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use pretty_env_logger;
use serde::Deserialize;
use std::path::Path;
use std::process;
use wasmtime_environ::cache_config;
use wasmtime_environ::cache_init;
use wasmtime_jit::{Compiler, Features};
use wasmtime_wast::WastContext;

Expand Down Expand Up @@ -89,7 +89,7 @@ fn main() {
Some(prefix)
};

let errors = cache_config::init(
let errors = cache_init(
args.flag_cache || args.flag_cache_config_file.is_some(),
args.flag_cache_config_file.as_ref(),
args.flag_create_cache_config,
Expand Down
46 changes: 36 additions & 10 deletions wasmtime-environ/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ use std::io::Write;
use std::path::{Path, PathBuf};
use std::string::{String, ToString};

pub mod config;
use config as cache_config; // so we have namespaced methods
mod config;
mod worker;

pub use config::init;
use config::{cache_config, CacheConfig};
use worker::worker;

lazy_static! {
static ref SELF_MTIME: String = {
std::env::current_exe()
Expand All @@ -45,8 +48,9 @@ lazy_static! {
};
}

pub struct ModuleCacheEntry {
pub struct ModuleCacheEntry<'config> {
mod_cache_path: Option<PathBuf>,
cache_config: &'config CacheConfig,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
Expand All @@ -68,15 +72,33 @@ type ModuleCacheDataTupleType = (

struct Sha256Hasher(Sha256);

impl ModuleCacheEntry {
impl<'config> ModuleCacheEntry<'config> {
pub fn new<'data>(
module: &Module,
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
compiler_name: &str,
generate_debug_info: bool,
) -> Self {
let mod_cache_path = if cache_config::enabled() {
Self::new_with_config(
module,
function_body_inputs,
isa,
compiler_name,
generate_debug_info,
cache_config(),
)
}

fn new_with_config<'data>(
module: &Module,
function_body_inputs: &PrimaryMap<DefinedFuncIndex, FunctionBodyData<'data>>,
isa: &dyn isa::TargetIsa,
compiler_name: &str,
generate_debug_info: bool,
cache_config: &'config CacheConfig,
) -> Self {
let mod_cache_path = if cache_config.enabled() {
let hash = Sha256Hasher::digest(module, function_body_inputs);
let compiler_dir = if cfg!(debug_assertions) {
format!(
Expand All @@ -98,7 +120,8 @@ impl ModuleCacheEntry {
mod_dbg = if generate_debug_info { ".d" } else { "" },
);
Some(
cache_config::directory()
cache_config
.directory()
.join(isa.triple().to_string())
.join(compiler_dir)
.join(mod_filename),
Expand All @@ -107,7 +130,10 @@ impl ModuleCacheEntry {
None
};

Self { mod_cache_path }
Self {
mod_cache_path,
cache_config,
}
}

pub fn get_data(&self) -> Option<ModuleCacheData> {
Expand All @@ -121,14 +147,14 @@ impl ModuleCacheEntry {
.map_err(|err| warn!("Failed to deserialize cached code: {}", err))
.ok()?;

worker::on_cache_get_async(path); // call on success
worker().on_cache_get_async(path); // call on success
Some(ret)
}

pub fn update_data(&self, data: &ModuleCacheData) {
if self.update_data_impl(data).is_some() {
let path = self.mod_cache_path.as_ref().unwrap();
worker::on_cache_update_async(path); // call on success
worker().on_cache_update_async(path); // call on success
}
}

Expand All @@ -140,7 +166,7 @@ impl ModuleCacheEntry {
.ok()?;
let compressed_data = zstd::encode_all(
&serialized_data[..],
cache_config::baseline_compression_level(),
self.cache_config.baseline_compression_level(),
)
.map_err(|err| warn!("Failed to compress cached code: {}", err))
.ok()?;
Expand Down
138 changes: 78 additions & 60 deletions wasmtime-environ/src/cache/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,46 +22,53 @@ struct Config {
cache: CacheConfig,
}

// todo: markdown documention of these options
// todo: markdown documention of these options (name, format, default, explanation)
// todo: don't flush default values (create config from simple template + url to docs)
// todo: more user-friendly cache config creation
#[derive(Serialize, Deserialize, Debug)]
struct CacheConfig {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CacheConfig {
#[serde(skip)]
pub errors: Vec<String>,
errors: Vec<String>,

pub enabled: bool,
pub directory: Option<PathBuf>,
enabled: bool,
directory: Option<PathBuf>,
#[serde(rename = "worker-event-queue-size")]
pub worker_event_queue_size: Option<usize>,
worker_event_queue_size: Option<usize>,
#[serde(rename = "baseline-compression-level")]
pub baseline_compression_level: Option<i32>,
baseline_compression_level: Option<i32>,
#[serde(rename = "optimized-compression-level")]
pub optimized_compression_level: Option<i32>,
optimized_compression_level: Option<i32>,
#[serde(rename = "optimized-compression-usage-counter-threshold")]
pub optimized_compression_usage_counter_threshold: Option<u64>,
optimized_compression_usage_counter_threshold: Option<u64>,
#[serde(
default,
rename = "cleanup-interval-in-seconds",
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)] // todo unit?
pub cleanup_interval: Option<Duration>,
cleanup_interval: Option<Duration>,
#[serde(
default,
rename = "optimizing-compression-task-timeout-in-seconds",
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)] // todo unit?
pub optimizing_compression_task_timeout: Option<Duration>,
optimizing_compression_task_timeout: Option<Duration>,
#[serde(
default,
rename = "allowed-clock-drift-for-locks-from-future",
serialize_with = "serialize_duration",
deserialize_with = "deserialize_duration"
)] // todo unit?
allowed_clock_drift_for_locks_from_future: Option<Duration>,
#[serde(rename = "files-count-soft-limit")]
pub files_count_soft_limit: Option<u64>,
files_count_soft_limit: Option<u64>,
#[serde(rename = "files-total-size-soft-limit")]
pub files_total_size_soft_limit: Option<u64>, // todo unit?
files_total_size_soft_limit: Option<u64>, // todo unit?
#[serde(rename = "files-count-limit-percent-if-deleting")]
pub files_count_limit_percent_if_deleting: Option<u8>, // todo format: integer + %
files_count_limit_percent_if_deleting: Option<u8>, // todo format: integer + %
#[serde(rename = "files-total-size-limit-percent-if-deleting")]
pub files_total_size_limit_percent_if_deleting: Option<u8>,
files_total_size_limit_percent_if_deleting: Option<u8>,
}

// toml-rs fails to serialize Duration ("values must be emitted before tables")
Expand All @@ -84,53 +91,14 @@ where
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.
/// Returns cache configuration.
///
/// Panics if the cache is disabled.
pub fn directory() -> &'static PathBuf {
&CONFIG
.r#try()
.expect("Cache system must be initialized")
.directory
.as_ref()
.expect("All cache system settings must be validated or defaulted")
}

macro_rules! generate_setting_getter {
($setting:ident: $setting_type:ty) => {
/// Returns `$setting`.
///
/// Panics if the cache is disabled.
pub fn $setting() -> $setting_type {
CONFIG
.r#try()
.expect("Cache system must be initialized")
.$setting
.expect("All cache system settings must be validated or defaulted")
}
};
/// 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())
}

generate_setting_getter!(worker_event_queue_size: usize);
generate_setting_getter!(baseline_compression_level: i32);
generate_setting_getter!(optimized_compression_level: i32);
generate_setting_getter!(optimized_compression_usage_counter_threshold: u64);
generate_setting_getter!(cleanup_interval: Duration);
generate_setting_getter!(optimizing_compression_task_timeout: Duration);
generate_setting_getter!(files_count_soft_limit: u64);
generate_setting_getter!(files_total_size_soft_limit: u64);
generate_setting_getter!(files_count_limit_percent_if_deleting: u8);
generate_setting_getter!(files_total_size_limit_percent_if_deleting: u8);

/// 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.
Expand Down Expand Up @@ -178,12 +146,53 @@ const DEFAULT_OPTIMIZED_COMPRESSION_LEVEL: i32 = 20;
const DEFAULT_OPTIMIZED_COMPRESSION_USAGE_COUNTER_THRESHOLD: u64 = 0x100;
const DEFAULT_CLEANUP_INTERVAL: Duration = Duration::from_secs(60 * 60);
const DEFAULT_OPTIMIZING_COMPRESSION_TASK_TIMEOUT: Duration = Duration::from_secs(30 * 60);
const DEFAULT_ALLOWED_CLOCK_DRIFT_FOR_LOCKS_FROM_FUTURE: Duration =
Duration::from_secs(60 * 60 * 24);
const DEFAULT_FILES_COUNT_SOFT_LIMIT: u64 = 0x10_000;
const DEFAULT_FILES_TOTAL_SIZE_SOFT_LIMIT: u64 = 1024 * 1024 * 512;
const DEFAULT_FILES_COUNT_LIMIT_PERCENT_IF_DELETING: u8 = 70;
const DEFAULT_FILES_TOTAL_SIZE_LIMIT_PERCENT_IF_DELETING: u8 = 70;

macro_rules! generate_setting_getter {
($setting:ident: $setting_type:ty) => {
/// Returns `$setting`.
///
/// Panics if the cache is disabled.
pub fn $setting(&self) -> $setting_type {
self
.$setting
.expect("All cache system settings must be validated or defaulted")
}
};
}

impl CacheConfig {
generate_setting_getter!(worker_event_queue_size: usize);
generate_setting_getter!(baseline_compression_level: i32);
generate_setting_getter!(optimized_compression_level: i32);
generate_setting_getter!(optimized_compression_usage_counter_threshold: u64);
generate_setting_getter!(cleanup_interval: Duration);
generate_setting_getter!(optimizing_compression_task_timeout: Duration);
generate_setting_getter!(allowed_clock_drift_for_locks_from_future: Duration);
generate_setting_getter!(files_count_soft_limit: u64);
generate_setting_getter!(files_total_size_soft_limit: u64);
generate_setting_getter!(files_count_limit_percent_if_deleting: u8);
generate_setting_getter!(files_total_size_limit_percent_if_deleting: u8);

/// Returns true if and only if the cache is enabled.
pub fn enabled(&self) -> bool {
self.enabled
}

/// Returns path to the cache directory.
///
/// Panics if the cache is disabled.
pub fn directory(&self) -> &PathBuf {
self.directory
.as_ref()
.expect("All cache system settings must be validated or defaulted")
}

pub fn new_cache_disabled() -> Self {
Self {
errors: Vec::new(),
Expand All @@ -195,6 +204,7 @@ impl CacheConfig {
optimized_compression_usage_counter_threshold: None,
cleanup_interval: None,
optimizing_compression_task_timeout: None,
allowed_clock_drift_for_locks_from_future: None,
files_count_soft_limit: None,
files_total_size_soft_limit: None,
files_count_limit_percent_if_deleting: None,
Expand Down Expand Up @@ -237,6 +247,7 @@ impl CacheConfig {
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_locks_from_future_or_default();
config.validate_files_count_soft_limit_or_default();
config.validate_files_total_size_soft_limit_or_default();
config.validate_files_count_limit_percent_if_deleting_or_default();
Expand Down Expand Up @@ -410,6 +421,13 @@ impl CacheConfig {
}
}

fn validate_allowed_clock_drift_for_locks_from_future_or_default(&mut self) {
if self.allowed_clock_drift_for_locks_from_future.is_none() {
self.allowed_clock_drift_for_locks_from_future =
Some(DEFAULT_ALLOWED_CLOCK_DRIFT_FOR_LOCKS_FROM_FUTURE);
}
}

fn validate_files_count_soft_limit_or_default(&mut self) {
if self.files_count_soft_limit.is_none() {
self.files_count_soft_limit = Some(DEFAULT_FILES_COUNT_SOFT_LIMIT);
Expand Down
Loading