Skip to content

Commit f1fa4bb

Browse files
authored
Merge pull request #2059 from CosmWasm/aw/pinned-cache-metrics
Metrics for the pinned cache
2 parents 4060b2c + 0840ab1 commit f1fa4bb

File tree

4 files changed

+154
-6
lines changed

4 files changed

+154
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to
1010

1111
- cosmwasm-vm: Add `secp256r1_verify` and `secp256r1_recover_pubkey` imports for
1212
ECDSA signature verification over secp256r1. ([#1983], [#2057], [#2058])
13+
- cosmwasm-vm: Add metrics for the pinned memory cache ([#2059])
1314

1415
[#1983]: https://github.com/CosmWasm/cosmwasm/pull/1983
1516
[#2057]: https://github.com/CosmWasm/cosmwasm/pull/2057
@@ -23,6 +24,7 @@ and this project adheres to
2324

2425
[#2044]: https://github.com/CosmWasm/cosmwasm/pull/2044
2526
[#2051]: https://github.com/CosmWasm/cosmwasm/pull/2051
27+
[#2059]: https://github.com/CosmWasm/cosmwasm/pull/2059
2628

2729
## [2.0.0] - 2024-03-12
2830

packages/vm/src/cache.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,22 @@ pub struct Metrics {
5353
pub size_memory_cache: usize,
5454
}
5555

56+
#[derive(Debug, Clone)]
57+
pub struct PerModuleMetrics {
58+
/// Hits (i.e. loads) of the module from the cache
59+
pub hits: u32,
60+
/// Size the module takes up in memory
61+
pub size: usize,
62+
}
63+
64+
#[derive(Debug, Clone)]
65+
pub struct PinnedMetrics {
66+
// It is *intentional* that this is only a vector
67+
// We don't need a potentially expensive hashing algorithm here
68+
// The checksums are sourced from a hashmap already, ensuring uniqueness of the checksums
69+
pub per_module: Vec<(Checksum, PerModuleMetrics)>,
70+
}
71+
5672
#[derive(Clone, Debug)]
5773
#[non_exhaustive]
5874
pub struct CacheOptions {
@@ -182,6 +198,24 @@ where
182198
self.inner.lock().unwrap().stats
183199
}
184200

201+
pub fn pinned_metrics(&self) -> PinnedMetrics {
202+
let cache = self.inner.lock().unwrap();
203+
let per_module = cache
204+
.pinned_memory_cache
205+
.iter()
206+
.map(|(checksum, module)| {
207+
let metrics = PerModuleMetrics {
208+
hits: module.hits,
209+
size: module.module.size_estimate,
210+
};
211+
212+
(*checksum, metrics)
213+
})
214+
.collect();
215+
216+
PinnedMetrics { per_module }
217+
}
218+
185219
pub fn metrics(&self) -> Metrics {
186220
let cache = self.inner.lock().unwrap();
187221
Metrics {
@@ -1409,6 +1443,48 @@ mod tests {
14091443
);
14101444
}
14111445

1446+
#[test]
1447+
fn pinned_metrics_works() {
1448+
let cache = unsafe { Cache::new(make_testing_options()).unwrap() };
1449+
let checksum = cache.save_wasm(CONTRACT).unwrap();
1450+
1451+
cache.pin(&checksum).unwrap();
1452+
1453+
let pinned_metrics = cache.pinned_metrics();
1454+
assert_eq!(pinned_metrics.per_module.len(), 1);
1455+
assert_eq!(pinned_metrics.per_module[0].0, checksum);
1456+
assert_eq!(pinned_metrics.per_module[0].1.hits, 0);
1457+
1458+
let backend = mock_backend(&[]);
1459+
let _ = cache
1460+
.get_instance(&checksum, backend, TESTING_OPTIONS)
1461+
.unwrap();
1462+
1463+
let pinned_metrics = cache.pinned_metrics();
1464+
assert_eq!(pinned_metrics.per_module.len(), 1);
1465+
assert_eq!(pinned_metrics.per_module[0].0, checksum);
1466+
assert_eq!(pinned_metrics.per_module[0].1.hits, 1);
1467+
1468+
let empty_checksum = cache.save_wasm(EMPTY_CONTRACT).unwrap();
1469+
cache.pin(&empty_checksum).unwrap();
1470+
1471+
let pinned_metrics = cache.pinned_metrics();
1472+
assert_eq!(pinned_metrics.per_module.len(), 2);
1473+
1474+
let get_module_hits = |checksum| {
1475+
pinned_metrics
1476+
.per_module
1477+
.iter()
1478+
.find(|(iter_checksum, _module)| *iter_checksum == checksum)
1479+
.map(|(_checksum, module)| module)
1480+
.cloned()
1481+
.unwrap()
1482+
};
1483+
1484+
assert_eq!(get_module_hits(checksum).hits, 1);
1485+
assert_eq!(get_module_hits(empty_checksum).hits, 0);
1486+
}
1487+
14121488
#[test]
14131489
fn pin_unpin_works() {
14141490
let cache = unsafe { Cache::new(make_testing_options()).unwrap() };

packages/vm/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ mod wasm_backend;
2323
pub use crate::backend::{
2424
Backend, BackendApi, BackendError, BackendResult, GasInfo, Querier, Storage,
2525
};
26-
pub use crate::cache::{AnalysisReport, Cache, CacheOptions, Metrics, Stats};
26+
pub use crate::cache::{
27+
AnalysisReport, Cache, CacheOptions, Metrics, PerModuleMetrics, PinnedMetrics, Stats,
28+
};
2729
pub use crate::calls::{
2830
call_execute, call_execute_raw, call_instantiate, call_instantiate_raw, call_migrate,
2931
call_migrate_raw, call_query, call_query_raw, call_reply, call_reply_raw, call_sudo,

packages/vm/src/modules/pinned_memory_cache.rs

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,18 @@ use std::collections::HashMap;
44
use super::cached_module::CachedModule;
55
use crate::VmResult;
66

7+
/// Struct storing some additional metadata, which is only of interest for the pinned cache,
8+
/// alongside the cached module.
9+
pub struct InstrumentedModule {
10+
/// Number of loads from memory this module received
11+
pub hits: u32,
12+
/// The actual cached module
13+
pub module: CachedModule,
14+
}
15+
716
/// An pinned in memory module cache
817
pub struct PinnedMemoryCache {
9-
modules: HashMap<Checksum, CachedModule>,
18+
modules: HashMap<Checksum, InstrumentedModule>,
1019
}
1120

1221
impl PinnedMemoryCache {
@@ -17,8 +26,19 @@ impl PinnedMemoryCache {
1726
}
1827
}
1928

29+
pub fn iter(&self) -> impl Iterator<Item = (&Checksum, &InstrumentedModule)> {
30+
self.modules.iter()
31+
}
32+
2033
pub fn store(&mut self, checksum: &Checksum, cached_module: CachedModule) -> VmResult<()> {
21-
self.modules.insert(*checksum, cached_module);
34+
self.modules.insert(
35+
*checksum,
36+
InstrumentedModule {
37+
hits: 0,
38+
module: cached_module,
39+
},
40+
);
41+
2242
Ok(())
2343
}
2444

@@ -31,8 +51,11 @@ impl PinnedMemoryCache {
3151

3252
/// Looks up a module in the cache and creates a new module
3353
pub fn load(&mut self, checksum: &Checksum) -> VmResult<Option<CachedModule>> {
34-
match self.modules.get(checksum) {
35-
Some(cached) => Ok(Some(cached.clone())),
54+
match self.modules.get_mut(checksum) {
55+
Some(cached) => {
56+
cached.hits = cached.hits.saturating_add(1);
57+
Ok(Some(cached.module.clone()))
58+
}
3659
None => Ok(None),
3760
}
3861
}
@@ -54,7 +77,7 @@ impl PinnedMemoryCache {
5477
pub fn size(&self) -> usize {
5578
self.modules
5679
.iter()
57-
.map(|(key, module)| std::mem::size_of_val(key) + module.size_estimate)
80+
.map(|(key, module)| std::mem::size_of_val(key) + module.module.size_estimate)
5881
.sum()
5982
}
6083
}
@@ -166,6 +189,51 @@ mod tests {
166189
assert!(!cache.has(&checksum));
167190
}
168191

192+
#[test]
193+
fn hit_metric_works() {
194+
let mut cache = PinnedMemoryCache::new();
195+
196+
// Create module
197+
let wasm = wat::parse_str(
198+
r#"(module
199+
(type $t0 (func (param i32) (result i32)))
200+
(func $add_one (export "add_one") (type $t0) (param $p0 i32) (result i32)
201+
local.get $p0
202+
i32.const 1
203+
i32.add)
204+
)"#,
205+
)
206+
.unwrap();
207+
let checksum = Checksum::generate(&wasm);
208+
209+
assert!(!cache.has(&checksum));
210+
211+
// Add
212+
let engine = make_compiling_engine(TESTING_MEMORY_LIMIT);
213+
let original = compile(&engine, &wasm).unwrap();
214+
let module = CachedModule {
215+
module: original,
216+
engine: make_runtime_engine(TESTING_MEMORY_LIMIT),
217+
size_estimate: 0,
218+
};
219+
cache.store(&checksum, module).unwrap();
220+
221+
let (_checksum, module) = cache
222+
.iter()
223+
.find(|(iter_checksum, _module)| **iter_checksum == checksum)
224+
.unwrap();
225+
226+
assert_eq!(module.hits, 0);
227+
228+
let _ = cache.load(&checksum).unwrap();
229+
let (_checksum, module) = cache
230+
.iter()
231+
.find(|(iter_checksum, _module)| **iter_checksum == checksum)
232+
.unwrap();
233+
234+
assert_eq!(module.hits, 1);
235+
}
236+
169237
#[test]
170238
fn len_works() {
171239
let mut cache = PinnedMemoryCache::new();

0 commit comments

Comments
 (0)