Skip to content

Commit fee5f1f

Browse files
page_fault metric
1 parent 10fa6f2 commit fee5f1f

3 files changed

Lines changed: 29 additions & 5 deletions

File tree

runtime/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ stability_scope!(BETA {
753753
}
754754

755755
/// Interface that any runtime must implement to provide buffer pools.
756-
pub trait BufferPooler: Clone + Send + Sync + 'static {
756+
pub trait BufferPooler: Metrics + Clone + Send + Sync + 'static {
757757
/// Returns the network [BufferPool].
758758
fn network_buffer_pool(&self) -> &BufferPool;
759759

runtime/src/utils/buffer/paged/append.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -991,7 +991,7 @@ mod tests {
991991
.with_max_per_class(NZUsize!(2)),
992992
&mut registry,
993993
);
994-
let cache_ref = CacheRef::new(pool.clone(), PAGE_SIZE, NZUsize!(1));
994+
let cache_ref = CacheRef::new(&context, pool.clone(), PAGE_SIZE, NZUsize!(1));
995995

996996
let (blob, blob_size) = context
997997
.open("test_partition", b"release_tip_backing")

runtime/src/utils/buffer/paged/cache.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
//! physical page format used by the blob, which is left to the blob implementation.
33
44
use super::get_page_from_blob;
5-
use crate::{Blob, BufferPool, BufferPooler, Error, IoBuf, IoBufMut};
5+
use crate::{Blob, BufferPool, BufferPooler, Error, IoBuf, IoBufMut, Metrics};
66
use commonware_utils::sync::RwLock;
77
use futures::{future::Shared, FutureExt};
8+
use prometheus_client::metrics::counter::Counter;
89
use std::{
910
collections::{hash_map::Entry, HashMap},
1011
future::Future,
@@ -162,6 +163,9 @@ pub struct CacheRef {
162163
/// Shareable reference to the page cache.
163164
cache: Arc<RwLock<Cache>>,
164165

166+
/// Number of page faults (cache misses that enter the fault handler).
167+
page_faults: Counter,
168+
165169
/// Pool used for page-cache and associated buffer allocations.
166170
pool: BufferPool,
167171
}
@@ -171,13 +175,21 @@ impl CacheRef {
171175
///
172176
/// The cache stores at most `capacity` pages, each exactly `page_size` bytes.
173177
/// Initialization eagerly allocates and zeroes all cache slots from `pool`.
174-
pub fn new(pool: BufferPool, page_size: NonZeroU16, capacity: NonZeroUsize) -> Self {
178+
pub fn new(
179+
context: &impl Metrics,
180+
pool: BufferPool,
181+
page_size: NonZeroU16,
182+
capacity: NonZeroUsize,
183+
) -> Self {
175184
let page_size_u64 = page_size.get() as u64;
185+
let page_faults = Counter::default();
186+
context.register("page_faults", "Number of page faults", page_faults.clone());
176187

177188
Self {
178189
page_size: page_size_u64,
179190
next_id: Arc::new(AtomicU64::new(0)),
180191
cache: Arc::new(RwLock::new(Cache::new(pool.clone(), page_size, capacity))),
192+
page_faults,
181193
pool,
182194
}
183195
}
@@ -189,7 +201,7 @@ impl CacheRef {
189201
page_size: NonZeroU16,
190202
capacity: NonZeroUsize,
191203
) -> Self {
192-
Self::new(pooler.storage_buffer_pool().clone(), page_size, capacity)
204+
Self::new(pooler, pooler.storage_buffer_pool().clone(), page_size, capacity)
193205
}
194206

195207
/// The page size used by this page cache.
@@ -204,6 +216,12 @@ impl CacheRef {
204216
&self.pool
205217
}
206218

219+
/// Returns the number of page faults (cache misses) that have occurred.
220+
#[cfg(test)]
221+
pub fn page_faults(&self) -> u64 {
222+
self.page_faults.get()
223+
}
224+
207225
/// Returns a unique id for the next blob that will use this page cache.
208226
pub fn next_id(&self) -> u64 {
209227
self.next_id.fetch_add(1, Ordering::Relaxed)
@@ -285,6 +303,7 @@ impl CacheRef {
285303

286304
let (page_num, offset_in_page) = Cache::offset_to_page(self.page_size, offset);
287305
let offset_in_page = offset_in_page as usize;
306+
self.page_faults.inc();
288307
trace!(page_num, blob_id, "page fault");
289308

290309
// Create or clone a future that retrieves the desired page from the underlying blob. This
@@ -759,6 +778,7 @@ mod tests {
759778
let cache_ref = CacheRef::from_pooler(&context, PAGE_SIZE, NZUsize!(10));
760779
assert_eq!(cache_ref.next_id(), 0);
761780
assert_eq!(cache_ref.next_id(), 1);
781+
assert_eq!(cache_ref.page_faults(), 0);
762782
for i in 0..11 {
763783
// Read expects logical bytes only (CRCs are stripped).
764784
let mut buf = vec![0; PAGE_SIZE.get() as usize];
@@ -768,6 +788,8 @@ mod tests {
768788
.unwrap();
769789
assert_eq!(buf, [i as u8; PAGE_SIZE.get() as usize]);
770790
}
791+
// 11 pages read, each was a cache miss.
792+
assert_eq!(cache_ref.page_faults(), 11);
771793

772794
// Repeat the read to exercise reading from the page cache. Must start at 1 because
773795
// page 0 should be evicted.
@@ -779,6 +801,8 @@ mod tests {
779801
.unwrap();
780802
assert_eq!(buf, [i as u8; PAGE_SIZE.get() as usize]);
781803
}
804+
// All 10 pages were cached, no new faults.
805+
assert_eq!(cache_ref.page_faults(), 11);
782806

783807
// Cleanup.
784808
blob.sync().await.unwrap();

0 commit comments

Comments
 (0)