1use fidl_fuchsia_memory_attribution as fattribution;
6use futures::TryStreamExt;
7use refaults_vmo::PageRefaultCounter;
8use std::collections::HashMap;
9use std::sync::atomic::Ordering;
10use std::sync::{Arc, Mutex};
11use zx::Status;
12
13pub trait RefaultProvider: Clone {
14 fn get_count(&self) -> u64;
16}
17
18#[derive(Default, Clone)]
19pub struct RefaultProviderImpl {
20 inner: Arc<Mutex<Inner>>,
21}
22
23impl RefaultProviderImpl {
24 pub async fn listen_to_page_refaults(
25 &self,
26 mut stream: fattribution::PageRefaultSinkRequestStream,
27 ) -> Result<(), anyhow::Error> {
28 loop {
29 match stream.try_next().await {
30 Ok(Some(request)) => match request {
31 fattribution::PageRefaultSinkRequest::SendPageRefaultCount {
32 page_refaults_vmo,
33 ..
34 } => {
35 self.inner.lock().unwrap().set_new_counter(page_refaults_vmo)?;
36 }
37 fattribution::PageRefaultSinkRequest::_UnknownMethod { .. } => unimplemented!(),
38 },
39 Ok(None) => {
40 return Ok(());
41 }
42 Err(e) => {
43 return Err(e.into());
44 }
45 }
46 }
47 }
48}
49
50impl RefaultProvider for RefaultProviderImpl {
51 fn get_count(&self) -> u64 {
52 self.inner.lock().unwrap().get_count()
53 }
54}
55
56#[derive(Clone, Copy, PartialEq, Eq, Hash)]
57struct CounterIndex(usize);
58
59#[derive(Default)]
60struct Inner {
61 counters: HashMap<CounterIndex, PageRefaultCounter>,
62}
63
64impl Inner {
65 fn set_new_counter(&mut self, page_refaults_vmo: zx::Vmo) -> Result<(), Status> {
66 let index = CounterIndex(self.counters.len());
67 self.counters.insert(index, PageRefaultCounter::from_vmo_readonly(page_refaults_vmo)?);
68 Ok(())
69 }
70
71 fn get_count(&self) -> u64 {
72 self.counters.values().map(|c| c.read(Ordering::Relaxed)).sum::<u64>()
73 }
74}