fn sample_bpf_counters()

in src/samplers/page_cache/mod.rs [159:221]


    fn sample_bpf_counters(&mut self) -> Result<(), std::io::Error> {
        if let Some(ref bpf) = self.bpf {
            let bpf = bpf.lock().unwrap();
            let time = Instant::now();
            let mut page_accessed = 0;
            let mut buffer_dirty = 0;
            let mut add_to_page_cache_lru = 0;
            let mut page_dirtied = 0;

            // to make things simple for wraparound behavior, clear each BPF
            // counter after reading it.
            if let Ok(mut table) = (*bpf).inner.table("page_accessed") {
                page_accessed = crate::common::bpf::parse_u64(table.iter().next().unwrap().value);
                let _ = table.set(&mut [0, 0, 0, 0], &mut [0, 0, 0, 0, 0, 0, 0, 0]);
            }
            if let Ok(mut table) = (*bpf).inner.table("buffer_dirty") {
                buffer_dirty = crate::common::bpf::parse_u64(table.iter().next().unwrap().value);
                let _ = table.set(&mut [0, 0, 0, 0], &mut [0, 0, 0, 0, 0, 0, 0, 0]);
            }
            if let Ok(mut table) = (*bpf).inner.table("add_to_page_cache_lru") {
                add_to_page_cache_lru =
                    crate::common::bpf::parse_u64(table.iter().next().unwrap().value);
                let _ = table.set(&mut [0, 0, 0, 0], &mut [0, 0, 0, 0, 0, 0, 0, 0]);
            }
            if let Ok(mut table) = (*bpf).inner.table("page_dirtied") {
                page_dirtied = crate::common::bpf::parse_u64(table.iter().next().unwrap().value);
                let _ = table.set(&mut [0, 0, 0, 0], &mut [0, 0, 0, 0, 0, 0, 0, 0]);
            }

            // the logic here is taken from https://github.com/iovisor/bcc/blob/master/tools/cachestat.py
            let total = page_accessed.saturating_sub(buffer_dirty);
            let misses = add_to_page_cache_lru.saturating_sub(page_dirtied);

            // misses may be overestimated due to readahead adding more pages
            // than needed. If this is the case, assume misses = total,
            let misses = if misses > total { total } else { misses };
            let hits = total.saturating_sub(misses);

            if let Some(count) = self.counters.get_mut(&PageCacheStatistic::Hit) {
                *count += hits;
            } else {
                self.counters.insert(PageCacheStatistic::Hit, hits);
            }

            if let Some(count) = self.counters.get_mut(&PageCacheStatistic::Miss) {
                *count += misses;
            } else {
                self.counters.insert(PageCacheStatistic::Miss, misses);
            }

            let _ = self.metrics().record_counter(
                &PageCacheStatistic::Hit,
                time,
                *self.counters.get(&PageCacheStatistic::Hit).unwrap_or(&0),
            );
            let _ = self.metrics().record_counter(
                &PageCacheStatistic::Miss,
                time,
                *self.counters.get(&PageCacheStatistic::Miss).unwrap_or(&0),
            );
        }
        Ok(())
    }