selinux/kernel/avc/
cache_stats.rs1use crossbeam_utils::CachePadded;
6use std::sync::atomic::{AtomicU64, Ordering};
7
8#[derive(Default, Debug, Clone, PartialEq)]
10pub struct CacheStats {
11 pub lookups: u64,
13 pub hits: u64,
15 pub misses: u64,
17 pub allocs: u64,
19 pub reclaims: u64,
21 pub frees: u64,
24}
25
26impl std::ops::Add for &CacheStats {
27 type Output = CacheStats;
28
29 fn add(self, other: &CacheStats) -> CacheStats {
30 CacheStats {
31 lookups: self.lookups + other.lookups,
32 hits: self.hits + other.hits,
33 misses: self.misses + other.misses,
34 allocs: self.allocs + other.allocs,
35 reclaims: self.reclaims + other.reclaims,
36 frees: self.frees + other.frees,
37 }
38 }
39}
40
41#[derive(Default, Debug)]
42pub(super) struct AtomicCacheStats {
43 pub lookups: AtomicU64,
44 pub hits: AtomicU64,
45 pub misses: AtomicU64,
46 pub allocs: AtomicU64,
47 pub reclaims: AtomicU64,
48 frees: AtomicU64,
49}
50
51impl AtomicCacheStats {
52 fn snapshot(&self) -> CacheStats {
53 CacheStats {
54 lookups: self.lookups.load(Ordering::Relaxed),
55 hits: self.hits.load(Ordering::Relaxed),
56 misses: self.misses.load(Ordering::Relaxed),
57 allocs: self.allocs.load(Ordering::Relaxed),
58 reclaims: self.reclaims.load(Ordering::Relaxed),
59 frees: self.frees.load(Ordering::Relaxed),
60 }
61 }
62
63 fn reset(&self) {
64 self.lookups.store(0, Ordering::Relaxed);
65 self.hits.store(0, Ordering::Relaxed);
66 self.misses.store(0, Ordering::Relaxed);
67 self.allocs.store(0, Ordering::Relaxed);
68 self.reclaims.store(0, Ordering::Relaxed);
69 self.frees.store(0, Ordering::Relaxed);
70 }
71}
72
73fn num_shards() -> usize {
76 8
77}
78
79unsafe extern "C" {
80 fn thrd_current() -> std::ffi::c_ulong;
81}
82
83pub(super) struct ShardedCacheStats {
85 shards: Vec<CachePadded<AtomicCacheStats>>,
86}
87
88impl ShardedCacheStats {
89 pub fn new() -> ShardedCacheStats {
90 ShardedCacheStats {
91 shards: (0..num_shards())
92 .map(|_| CachePadded::new(AtomicCacheStats::default()))
93 .collect(),
94 }
95 }
96
97 pub fn shard(&self) -> &AtomicCacheStats {
98 let index = (rapidhash::rapidhash(&unsafe { thrd_current() }.to_ne_bytes()) as usize)
100 % num_shards();
101 &self.shards[index]
102 }
103
104 pub fn reset(&self) {
105 for shard in &self.shards {
106 shard.reset();
107 }
108 }
109
110 pub fn read(&self) -> CacheStats {
112 self.shards.iter().fold(CacheStats::default(), |acc, stats| &acc + &stats.snapshot())
113 }
114}