1use fidl_fuchsia_memory_attribution as fattribution;
6use futures::TryStreamExt;
7use refaults_vmo::PageFaultCounter;
8use std::collections::HashMap;
9use std::sync::atomic::Ordering;
10use std::sync::{Arc, Mutex};
11use zx::Status;
12
13pub trait PageFaultProvider: Clone + Send + Sync + 'static {
14 fn get_refault_count(&self) -> u64;
17
18 fn get_fault_count(&self) -> u64;
21}
22
23#[derive(Default, Clone)]
24pub struct PageFaultProviderImpl {
25 inner: Arc<Mutex<Inner>>,
26}
27
28impl PageFaultProviderImpl {
29 pub async fn listen_to_page_faults(
30 &self,
31 mut stream: fattribution::PagerStatsSinkRequestStream,
32 ) -> Result<(), anyhow::Error> {
33 loop {
34 match stream.try_next().await {
35 Ok(Some(request)) => match request {
36 fattribution::PagerStatsSinkRequest::SendPagerStats {
37 pager_stats_vmo, ..
38 } => {
39 self.inner.lock().unwrap().set_new_counter(pager_stats_vmo)?;
40 }
41 fattribution::PagerStatsSinkRequest::_UnknownMethod { .. } => unimplemented!(),
42 },
43 Ok(None) => {
44 return Ok(());
45 }
46 Err(e) => {
47 return Err(e.into());
48 }
49 }
50 }
51 }
52}
53
54impl PageFaultProvider for PageFaultProviderImpl {
55 fn get_refault_count(&self) -> u64 {
56 self.inner.lock().unwrap().get_refault_count()
57 }
58
59 fn get_fault_count(&self) -> u64 {
60 self.inner.lock().unwrap().get_fault_count()
61 }
62}
63
64#[derive(Clone, Copy, PartialEq, Eq, Hash)]
65struct CounterIndex(usize);
66
67#[derive(Default)]
68struct Inner {
69 counters: HashMap<CounterIndex, PageFaultCounter>,
70}
71
72impl Inner {
73 fn set_new_counter(&mut self, pager_stats_vmo: zx::Vmo) -> Result<(), Status> {
74 let index = CounterIndex(self.counters.len());
75 self.counters.insert(index, PageFaultCounter::from_vmo_readonly(pager_stats_vmo)?);
76 Ok(())
77 }
78
79 fn get_refault_count(&self) -> u64 {
80 self.counters.values().map(|c| c.read_refaults(Ordering::Relaxed)).sum::<u64>()
81 }
82
83 fn get_fault_count(&self) -> u64 {
84 self.counters.values().map(|c| c.read_faults(Ordering::Relaxed)).sum::<u64>()
85 }
86}