stalls/
refaults.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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    // Returns the current number of page refaults of the system, since its start.
15    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}