Skip to content

Commit 1f43164

Browse files
authored
Merge pull request #877 from CosmWasm/add-cache-metrics
Add cache metrics
2 parents afbd217 + 78a0b94 commit 1f43164

File tree

7 files changed

+293
-24
lines changed

7 files changed

+293
-24
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,16 @@ and this project adheres to
6161
integers `p` and `q`. `Decimal` now implements `Fraction<u128>`, which
6262
provides public getters `::numerator()` and `::denominator()`.
6363
- cosmwasm-std: Add `Decimal::inv` that returns `1/d` for decimal `d`.
64+
- cosmwasm-vm: Add `Cache::metrics` to expose internal data for monitoring
65+
purposes ([#763]).
6466

6567
[#692]: https://github.com/CosmWasm/cosmwasm/issues/692
6668
[#706]: https://github.com/CosmWasm/cosmwasm/pull/706
6769
[#710]: https://github.com/CosmWasm/cosmwasm/pull/710
6870
[#711]: https://github.com/CosmWasm/cosmwasm/pull/711
6971
[#714]: https://github.com/CosmWasm/cosmwasm/pull/714
7072
[#716]: https://github.com/CosmWasm/cosmwasm/pull/716
73+
[#763]: https://github.com/CosmWasm/cosmwasm/issues/763
7174
[#768]: https://github.com/CosmWasm/cosmwasm/pull/768
7275
[#793]: https://github.com/CosmWasm/cosmwasm/pull/793
7376
[#796]: https://github.com/CosmWasm/cosmwasm/pull/796

packages/vm/src/cache.rs

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ pub struct Stats {
2626
pub misses: u32,
2727
}
2828

29+
#[derive(Debug, Clone, Copy)]
30+
pub struct Metrics {
31+
pub stats: Stats,
32+
pub elements_pinned_memory_cache: usize,
33+
pub elements_memory_cache: usize,
34+
pub size_pinned_memory_cache: usize,
35+
pub size_memory_cache: usize,
36+
}
37+
2938
#[derive(Clone, Debug)]
3039
pub struct CacheOptions {
3140
pub base_dir: PathBuf,
@@ -108,6 +117,17 @@ where
108117
self.inner.lock().unwrap().stats
109118
}
110119

120+
pub fn metrics(&self) -> Metrics {
121+
let cache = self.inner.lock().unwrap();
122+
Metrics {
123+
stats: cache.stats,
124+
elements_pinned_memory_cache: cache.pinned_memory_cache.len(),
125+
elements_memory_cache: cache.memory_cache.len(),
126+
size_pinned_memory_cache: cache.pinned_memory_cache.size(),
127+
size_memory_cache: cache.memory_cache.size(),
128+
}
129+
}
130+
111131
pub fn save_wasm(&self, wasm: &[u8]) -> VmResult<Checksum> {
112132
check_wasm(wasm, &self.supported_features)?;
113133
let module = compile(wasm, None)?;
@@ -165,22 +185,28 @@ where
165185
// Try to get module from the memory cache
166186
if let Some(module) = cache.memory_cache.load(checksum)? {
167187
cache.stats.hits_memory_cache += 1;
168-
return cache.pinned_memory_cache.store(checksum, module);
188+
return cache
189+
.pinned_memory_cache
190+
.store(checksum, module.module, module.size);
169191
}
170192

171193
// Try to get module from file system cache
172194
let store = make_runtime_store(Some(cache.instance_memory_limit));
173-
if let Some((module, _)) = cache.fs_cache.load(checksum, &store)? {
195+
if let Some((module, module_size)) = cache.fs_cache.load(checksum, &store)? {
174196
cache.stats.hits_fs_cache += 1;
175-
return cache.pinned_memory_cache.store(checksum, module);
197+
return cache
198+
.pinned_memory_cache
199+
.store(checksum, module, module_size);
176200
}
177201

178202
// Re-compile from original Wasm bytecode
179203
let code = self.load_wasm_with_path(&cache.wasm_path, checksum)?;
180204
let module = compile(&code, Some(cache.instance_memory_limit))?;
181205
// Store into the fs cache too
182-
cache.fs_cache.store(checksum, &module)?;
183-
cache.pinned_memory_cache.store(checksum, module)
206+
let module_size = cache.fs_cache.store(checksum, &module)?;
207+
cache
208+
.pinned_memory_cache
209+
.store(checksum, module, module_size)
184210
}
185211

186212
/// Unpins a Module, i.e. removes it from the pinned memory cache.
@@ -215,8 +241,12 @@ where
215241
// Get module from memory cache
216242
if let Some(module) = cache.memory_cache.load(checksum)? {
217243
cache.stats.hits_memory_cache += 1;
218-
let instance =
219-
Instance::from_module(&module, backend, options.gas_limit, options.print_debug)?;
244+
let instance = Instance::from_module(
245+
&module.module,
246+
backend,
247+
options.gas_limit,
248+
options.print_debug,
249+
)?;
220250
return Ok(instance);
221251
}
222252

packages/vm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ mod wasm_backend;
2727
pub use crate::backend::{
2828
Backend, BackendApi, BackendError, BackendResult, GasInfo, Querier, Storage,
2929
};
30-
pub use crate::cache::{AnalysisReport, Cache, CacheOptions, Stats};
30+
pub use crate::cache::{AnalysisReport, Cache, CacheOptions, Metrics, Stats};
3131
pub use crate::calls::{
3232
call_execute, call_execute_raw, call_instantiate, call_instantiate_raw, call_migrate,
3333
call_migrate_raw, call_query, call_query_raw, call_reply, call_reply_raw, call_sudo,

packages/vm/src/modules/in_memory_cache.rs

Lines changed: 144 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
use clru::{CLruCache, CLruCacheConfig, WeightScale};
22
use std::collections::hash_map::RandomState;
3+
use std::num::NonZeroUsize;
34
use wasmer::Module;
45

6+
use super::sized_module::SizedModule;
57
use crate::{Checksum, Size, VmError, VmResult};
6-
use std::num::NonZeroUsize;
78

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

17-
#[derive(Debug)]
18-
struct SizedModule {
19-
pub module: Module,
20-
pub size: usize,
21-
}
22-
2318
#[derive(Debug)]
2419
struct SizeScale;
2520

@@ -64,16 +59,35 @@ impl InMemoryCache {
6459
}
6560

6661
/// Looks up a module in the cache and creates a new module
67-
pub fn load(&mut self, checksum: &Checksum) -> VmResult<Option<Module>> {
62+
pub fn load(&mut self, checksum: &Checksum) -> VmResult<Option<SizedModule>> {
6863
if let Some(modules) = &mut self.modules {
6964
match modules.get(checksum) {
70-
Some(sized_module) => Ok(Some(sized_module.module.clone())),
65+
Some(module) => Ok(Some(module.clone())),
7166
None => Ok(None),
7267
}
7368
} else {
7469
Ok(None)
7570
}
7671
}
72+
73+
/// Returns the number of elements in the cache.
74+
pub fn len(&self) -> usize {
75+
self.modules
76+
.as_ref()
77+
.map(|modules| modules.len())
78+
.unwrap_or_default()
79+
}
80+
81+
/// Returns cumulative size of all elements in the cache.
82+
///
83+
/// This is based on the values provided with `store`. No actual
84+
/// memory size is measured here.
85+
pub fn size(&self) -> usize {
86+
self.modules
87+
.as_ref()
88+
.map(|modules| modules.weight())
89+
.unwrap_or_default()
90+
}
7791
}
7892

7993
#[cfg(test)]
@@ -148,11 +162,131 @@ mod tests {
148162

149163
// Ensure cached module can be executed
150164
{
151-
let instance = WasmerInstance::new(&cached, &imports! {}).unwrap();
165+
let instance = WasmerInstance::new(&cached.module, &imports! {}).unwrap();
152166
set_remaining_points(&instance, TESTING_GAS_LIMIT);
153167
let add_one = instance.exports.get_function("add_one").unwrap();
154168
let result = add_one.call(&[42.into()]).unwrap();
155169
assert_eq!(result[0].unwrap_i32(), 43);
156170
}
157171
}
172+
173+
#[test]
174+
fn len_works() {
175+
let mut cache = InMemoryCache::new(Size::mebi(2));
176+
177+
// Create module
178+
let wasm1 = wat::parse_str(
179+
r#"(module
180+
(type $t0 (func (param i32) (result i32)))
181+
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
182+
get_local $p0
183+
i32.const 1
184+
i32.add)
185+
)"#,
186+
)
187+
.unwrap();
188+
let checksum1 = Checksum::generate(&wasm1);
189+
let wasm2 = wat::parse_str(
190+
r#"(module
191+
(type $t0 (func (param i32) (result i32)))
192+
(func $add_one (export "add_two") (type $t0) (param $p0 i32) (result i32)
193+
get_local $p0
194+
i32.const 2
195+
i32.add)
196+
)"#,
197+
)
198+
.unwrap();
199+
let checksum2 = Checksum::generate(&wasm2);
200+
let wasm3 = wat::parse_str(
201+
r#"(module
202+
(type $t0 (func (param i32) (result i32)))
203+
(func $add_one (export "add_three") (type $t0) (param $p0 i32) (result i32)
204+
get_local $p0
205+
i32.const 3
206+
i32.add)
207+
)"#,
208+
)
209+
.unwrap();
210+
let checksum3 = Checksum::generate(&wasm3);
211+
212+
assert_eq!(cache.len(), 0);
213+
214+
// Add 1
215+
cache
216+
.store(&checksum1, compile(&wasm1, None).unwrap(), 900_000)
217+
.unwrap();
218+
assert_eq!(cache.len(), 1);
219+
220+
// Add 2
221+
cache
222+
.store(&checksum2, compile(&wasm2, None).unwrap(), 900_000)
223+
.unwrap();
224+
assert_eq!(cache.len(), 2);
225+
226+
// Add 3 (pushes out the previous two)
227+
cache
228+
.store(&checksum3, compile(&wasm3, None).unwrap(), 1_500_000)
229+
.unwrap();
230+
assert_eq!(cache.len(), 1);
231+
}
232+
233+
#[test]
234+
fn size_works() {
235+
let mut cache = InMemoryCache::new(Size::mebi(2));
236+
237+
// Create module
238+
let wasm1 = wat::parse_str(
239+
r#"(module
240+
(type $t0 (func (param i32) (result i32)))
241+
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
242+
get_local $p0
243+
i32.const 1
244+
i32.add)
245+
)"#,
246+
)
247+
.unwrap();
248+
let checksum1 = Checksum::generate(&wasm1);
249+
let wasm2 = wat::parse_str(
250+
r#"(module
251+
(type $t0 (func (param i32) (result i32)))
252+
(func $add_one (export "add_two") (type $t0) (param $p0 i32) (result i32)
253+
get_local $p0
254+
i32.const 2
255+
i32.add)
256+
)"#,
257+
)
258+
.unwrap();
259+
let checksum2 = Checksum::generate(&wasm2);
260+
let wasm3 = wat::parse_str(
261+
r#"(module
262+
(type $t0 (func (param i32) (result i32)))
263+
(func $add_one (export "add_three") (type $t0) (param $p0 i32) (result i32)
264+
get_local $p0
265+
i32.const 3
266+
i32.add)
267+
)"#,
268+
)
269+
.unwrap();
270+
let checksum3 = Checksum::generate(&wasm3);
271+
272+
assert_eq!(cache.size(), 0);
273+
274+
// Add 1
275+
cache
276+
.store(&checksum1, compile(&wasm1, None).unwrap(), 900_000)
277+
.unwrap();
278+
assert_eq!(cache.size(), 900_000);
279+
280+
// Add 2
281+
cache
282+
.store(&checksum2, compile(&wasm2, None).unwrap(), 800_000)
283+
.unwrap();
284+
assert_eq!(cache.size(), 1_700_000);
285+
286+
// Add 3 (pushes out the previous two)
287+
cache
288+
.store(&checksum3, compile(&wasm3, None).unwrap(), 1_500_000)
289+
.unwrap();
290+
assert_eq!(cache.size(), 1_500_000);
291+
}
158292
}

packages/vm/src/modules/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod file_system_cache;
22
mod in_memory_cache;
33
mod pinned_memory_cache;
4+
mod sized_module;
45

56
pub use file_system_cache::FileSystemCache;
67
pub use in_memory_cache::InMemoryCache;

0 commit comments

Comments
 (0)