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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,16 @@ and this project adheres to
integers `p` and `q`. `Decimal` now implements `Fraction<u128>`, which
provides public getters `::numerator()` and `::denominator()`.
- cosmwasm-std: Add `Decimal::inv` that returns `1/d` for decimal `d`.
- cosmwasm-vm: Add `Cache::metrics` to expose internal data for monitoring
purposes ([#763]).

[#692]: https://github.com/CosmWasm/cosmwasm/issues/692
[#706]: https://github.com/CosmWasm/cosmwasm/pull/706
[#710]: https://github.com/CosmWasm/cosmwasm/pull/710
[#711]: https://github.com/CosmWasm/cosmwasm/pull/711
[#714]: https://github.com/CosmWasm/cosmwasm/pull/714
[#716]: https://github.com/CosmWasm/cosmwasm/pull/716
[#763]: https://github.com/CosmWasm/cosmwasm/issues/763
[#768]: https://github.com/CosmWasm/cosmwasm/pull/768
[#793]: https://github.com/CosmWasm/cosmwasm/pull/793
[#796]: https://github.com/CosmWasm/cosmwasm/pull/796
Expand Down
44 changes: 37 additions & 7 deletions packages/vm/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ pub struct Stats {
pub misses: u32,
}

#[derive(Debug, Clone, Copy)]
pub struct Metrics {
pub stats: Stats,
pub elements_pinned_memory_cache: usize,
pub elements_memory_cache: usize,
pub size_pinned_memory_cache: usize,
pub size_memory_cache: usize,
}

#[derive(Clone, Debug)]
pub struct CacheOptions {
pub base_dir: PathBuf,
Expand Down Expand Up @@ -108,6 +117,17 @@ where
self.inner.lock().unwrap().stats
}

pub fn metrics(&self) -> Metrics {
let cache = self.inner.lock().unwrap();
Metrics {
stats: cache.stats,
elements_pinned_memory_cache: cache.pinned_memory_cache.len(),
elements_memory_cache: cache.memory_cache.len(),
size_pinned_memory_cache: cache.pinned_memory_cache.size(),
size_memory_cache: cache.memory_cache.size(),
}
}

pub fn save_wasm(&self, wasm: &[u8]) -> VmResult<Checksum> {
check_wasm(wasm, &self.supported_features)?;
let module = compile(wasm, None)?;
Expand Down Expand Up @@ -165,22 +185,28 @@ where
// Try to get module from the memory cache
if let Some(module) = cache.memory_cache.load(checksum)? {
cache.stats.hits_memory_cache += 1;
return cache.pinned_memory_cache.store(checksum, module);
return cache
.pinned_memory_cache
.store(checksum, module.module, module.size);
}

// Try to get module from file system cache
let store = make_runtime_store(Some(cache.instance_memory_limit));
if let Some((module, _)) = cache.fs_cache.load(checksum, &store)? {
if let Some((module, module_size)) = cache.fs_cache.load(checksum, &store)? {
cache.stats.hits_fs_cache += 1;
return cache.pinned_memory_cache.store(checksum, module);
return cache
.pinned_memory_cache
.store(checksum, module, module_size);
}

// Re-compile from original Wasm bytecode
let code = self.load_wasm_with_path(&cache.wasm_path, checksum)?;
let module = compile(&code, Some(cache.instance_memory_limit))?;
// Store into the fs cache too
cache.fs_cache.store(checksum, &module)?;
cache.pinned_memory_cache.store(checksum, module)
let module_size = cache.fs_cache.store(checksum, &module)?;
cache
.pinned_memory_cache
.store(checksum, module, module_size)
}

/// Unpins a Module, i.e. removes it from the pinned memory cache.
Expand Down Expand Up @@ -215,8 +241,12 @@ where
// Get module from memory cache
if let Some(module) = cache.memory_cache.load(checksum)? {
cache.stats.hits_memory_cache += 1;
let instance =
Instance::from_module(&module, backend, options.gas_limit, options.print_debug)?;
let instance = Instance::from_module(
&module.module,
backend,
options.gas_limit,
options.print_debug,
)?;
return Ok(instance);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ mod wasm_backend;
pub use crate::backend::{
Backend, BackendApi, BackendError, BackendResult, GasInfo, Querier, Storage,
};
pub use crate::cache::{AnalysisReport, Cache, CacheOptions, Stats};
pub use crate::cache::{AnalysisReport, Cache, CacheOptions, Metrics, Stats};
pub use crate::calls::{
call_execute, call_execute_raw, call_instantiate, call_instantiate_raw, call_migrate,
call_migrate_raw, call_query, call_query_raw, call_reply, call_reply_raw, call_sudo,
Expand Down
154 changes: 144 additions & 10 deletions packages/vm/src/modules/in_memory_cache.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use clru::{CLruCache, CLruCacheConfig, WeightScale};
use std::collections::hash_map::RandomState;
use std::num::NonZeroUsize;
use wasmer::Module;

use super::sized_module::SizedModule;
use crate::{Checksum, Size, VmError, VmResult};
use std::num::NonZeroUsize;

// Minimum module size.
// Based on `examples/module_size.sh`, and the cosmwasm-plus contracts.
Expand All @@ -14,12 +15,6 @@ use std::num::NonZeroUsize;
// Which is a very small percentage (~0.03%) of our typical cache memory budget (2 GB).
const MINIMUM_MODULE_SIZE: Size = Size::kibi(250);

#[derive(Debug)]
struct SizedModule {
pub module: Module,
pub size: usize,
}

#[derive(Debug)]
struct SizeScale;

Expand Down Expand Up @@ -64,16 +59,35 @@ impl InMemoryCache {
}

/// Looks up a module in the cache and creates a new module
pub fn load(&mut self, checksum: &Checksum) -> VmResult<Option<Module>> {
pub fn load(&mut self, checksum: &Checksum) -> VmResult<Option<SizedModule>> {
if let Some(modules) = &mut self.modules {
match modules.get(checksum) {
Some(sized_module) => Ok(Some(sized_module.module.clone())),
Some(module) => Ok(Some(module.clone())),
None => Ok(None),
}
} else {
Ok(None)
}
}

/// Returns the number of elements in the cache.
pub fn len(&self) -> usize {
self.modules
.as_ref()
.map(|modules| modules.len())
.unwrap_or_default()
}

/// Returns cumulative size of all elements in the cache.
///
/// This is based on the values provided with `store`. No actual
/// memory size is measured here.
pub fn size(&self) -> usize {
self.modules
.as_ref()
.map(|modules| modules.weight())
.unwrap_or_default()
}
}

#[cfg(test)]
Expand Down Expand Up @@ -148,11 +162,131 @@ mod tests {

// Ensure cached module can be executed
{
let instance = WasmerInstance::new(&cached, &imports! {}).unwrap();
let instance = WasmerInstance::new(&cached.module, &imports! {}).unwrap();
set_remaining_points(&instance, TESTING_GAS_LIMIT);
let add_one = instance.exports.get_function("add_one").unwrap();
let result = add_one.call(&[42.into()]).unwrap();
assert_eq!(result[0].unwrap_i32(), 43);
}
}

#[test]
fn len_works() {
let mut cache = InMemoryCache::new(Size::mebi(2));

// Create module
let wasm1 = wat::parse_str(
r#"(module
(type $t0 (func (param i32) (result i32)))
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 1
i32.add)
)"#,
)
.unwrap();
let checksum1 = Checksum::generate(&wasm1);
let wasm2 = wat::parse_str(
r#"(module
(type $t0 (func (param i32) (result i32)))
(func $add_one (export "add_two") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 2
i32.add)
)"#,
)
.unwrap();
let checksum2 = Checksum::generate(&wasm2);
let wasm3 = wat::parse_str(
r#"(module
(type $t0 (func (param i32) (result i32)))
(func $add_one (export "add_three") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 3
i32.add)
)"#,
)
.unwrap();
let checksum3 = Checksum::generate(&wasm3);

assert_eq!(cache.len(), 0);

// Add 1
cache
.store(&checksum1, compile(&wasm1, None).unwrap(), 900_000)
.unwrap();
assert_eq!(cache.len(), 1);

// Add 2
cache
.store(&checksum2, compile(&wasm2, None).unwrap(), 900_000)
.unwrap();
assert_eq!(cache.len(), 2);

// Add 3 (pushes out the previous two)
cache
.store(&checksum3, compile(&wasm3, None).unwrap(), 1_500_000)
.unwrap();
assert_eq!(cache.len(), 1);
}

#[test]
fn size_works() {
let mut cache = InMemoryCache::new(Size::mebi(2));

// Create module
let wasm1 = wat::parse_str(
r#"(module
(type $t0 (func (param i32) (result i32)))
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 1
i32.add)
)"#,
)
.unwrap();
let checksum1 = Checksum::generate(&wasm1);
let wasm2 = wat::parse_str(
r#"(module
(type $t0 (func (param i32) (result i32)))
(func $add_one (export "add_two") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 2
i32.add)
)"#,
)
.unwrap();
let checksum2 = Checksum::generate(&wasm2);
let wasm3 = wat::parse_str(
r#"(module
(type $t0 (func (param i32) (result i32)))
(func $add_one (export "add_three") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 3
i32.add)
)"#,
)
.unwrap();
let checksum3 = Checksum::generate(&wasm3);

assert_eq!(cache.size(), 0);

// Add 1
cache
.store(&checksum1, compile(&wasm1, None).unwrap(), 900_000)
.unwrap();
assert_eq!(cache.size(), 900_000);

// Add 2
cache
.store(&checksum2, compile(&wasm2, None).unwrap(), 800_000)
.unwrap();
assert_eq!(cache.size(), 1_700_000);

// Add 3 (pushes out the previous two)
cache
.store(&checksum3, compile(&wasm3, None).unwrap(), 1_500_000)
.unwrap();
assert_eq!(cache.size(), 1_500_000);
}
}
1 change: 1 addition & 0 deletions packages/vm/src/modules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod file_system_cache;
mod in_memory_cache;
mod pinned_memory_cache;
mod sized_module;

pub use file_system_cache::FileSystemCache;
pub use in_memory_cache::InMemoryCache;
Expand Down
Loading