perf_event/events/
cache.rs

1use c_enum::c_enum;
2use perf_event_open_sys::bindings;
3
4use crate::events::Event;
5
6/// A cache event.
7///
8/// A cache event has three identifying characteristics:
9///
10/// - which cache to observe ([`which`])
11///
12/// - what sort of request it's handling ([`operation`])
13///
14/// - whether we want to count all cache accesses, or just misses ([`result`]).
15///
16/// For example, to measure the L1 data cache's miss rate:
17///
18/// ```
19/// # use perf_event::{Builder, Group};
20/// # use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
21/// # fn main() -> std::io::Result<()> {
22/// // A `Cache` value representing L1 data cache read accesses.
23/// const ACCESS: Cache = Cache {
24///     which: WhichCache::L1D,
25///     operation: CacheOp::READ,
26///     result: CacheResult::ACCESS,
27/// };
28///
29/// // A `Cache` value representing L1 data cache read misses.
30/// const MISS: Cache = Cache {
31///     result: CacheResult::MISS,
32///     ..ACCESS
33/// };
34///
35/// // Construct a `Group` containing the two new counters, from which we
36/// // can get counts over matching periods of time.
37/// let mut group = Group::new()?;
38/// let access_counter = group.add(&Builder::new(ACCESS))?;
39/// let miss_counter = group.add(&Builder::new(MISS))?;
40/// # Ok(()) }
41/// ```
42///
43/// [`which`]: enum.WhichCache.html
44/// [`operation`]: enum.CacheOp.html
45/// [`result`]: enum.CacheResult.html
46#[derive(Debug, Clone, Eq, PartialEq)]
47pub struct Cache {
48    /// Which cache is being monitored? (data, instruction, ...)
49    pub which: CacheId,
50
51    /// What operation is being monitored? (read, write, etc.)
52    pub operation: CacheOp,
53
54    /// All accesses, or just misses?
55    pub result: CacheResult,
56}
57
58impl Cache {
59    fn as_config(&self) -> u64 {
60        self.which.0 as u64 | ((self.operation.0 as u64) << 8) | ((self.result.0 as u64) << 16)
61    }
62}
63
64impl Event for Cache {
65    fn update_attrs(self, attr: &mut bindings::perf_event_attr) {
66        attr.type_ = bindings::PERF_TYPE_HW_CACHE;
67        attr.config = self.as_config()
68    }
69}
70
71#[doc(hidden)]
72#[deprecated = "WhichCache has been renamed to CacheId"]
73pub type WhichCache = CacheId;
74
75c_enum! {
76    /// A cache whose events we would like to count.
77    ///
78    /// This is used in the `Cache` type as part of the identification of a cache
79    /// event. Each variant here corresponds to a particular
80    /// `PERF_COUNT_HW_CACHE_...` constant supported by the [`perf_event_open`][man]
81    /// system call.
82    ///
83    /// [man]: https://www.mankier.com/2/perf_event_open
84    #[repr(transparent)]
85    #[derive(Clone, Copy, Eq, PartialEq, Hash)]
86    pub enum CacheId : u8 {
87        /// Level 1 data cache.
88        L1D = bindings::PERF_COUNT_HW_CACHE_L1D as _,
89
90        /// Level 1 instruction cache.
91        L1I = bindings::PERF_COUNT_HW_CACHE_L1I as _,
92
93        /// Last-level cache.
94        LL = bindings::PERF_COUNT_HW_CACHE_LL as _,
95
96        /// Data translation lookaside buffer (virtual address translation).
97        DTLB = bindings::PERF_COUNT_HW_CACHE_DTLB as _,
98
99        /// Instruction translation lookaside buffer (virtual address translation).
100        ITLB = bindings::PERF_COUNT_HW_CACHE_ITLB as _,
101
102        /// Branch prediction.
103        BPU = bindings::PERF_COUNT_HW_CACHE_BPU as _,
104
105        /// Memory accesses that stay local to the originating NUMA node.
106        NODE = bindings::PERF_COUNT_HW_CACHE_NODE as _,
107    }
108}
109
110c_enum! {
111    /// What sort of cache operation we would like to observe.
112    ///
113    /// This is used in the `Cache` type as part of the identification of a cache
114    /// event. Each variant here corresponds to a particular
115    /// `PERF_COUNT_HW_CACHE_OP_...` constant supported by the
116    /// [`perf_event_open`][man] system call.
117    ///
118    /// [man]: https://www.mankier.com/2/perf_event_open
119    #[repr(transparent)]
120    #[derive(Clone, Copy, Eq, PartialEq, Hash)]
121    pub enum CacheOp : u8 {
122        /// Read accesses.
123        READ = bindings::PERF_COUNT_HW_CACHE_OP_READ as _,
124
125        /// Write accesses.
126        WRITE = bindings::PERF_COUNT_HW_CACHE_OP_WRITE as _,
127
128        /// Prefetch accesses.
129        PREFETCH = bindings::PERF_COUNT_HW_CACHE_OP_PREFETCH as _,
130    }
131}
132
133c_enum! {
134    /// What sort of cache result we're interested in observing.
135    ///
136    /// `ACCESS` counts the total number of operations performed on the cache,
137    /// whereas `MISS` counts only those requests that the cache could not satisfy.
138    /// Treating `MISS` as a fraction of `ACCESS` gives you the cache's miss rate.
139    ///
140    /// This is used used in the `Cache` type as part of the identification of a
141    /// cache event. Each variant here corresponds to a particular
142    /// `PERF_COUNT_HW_CACHE_RESULT_...` constant supported by the
143    /// [`perf_event_open`][man] system call.
144    ///
145    /// [man]: https://www.mankier.com/2/perf_event_open
146    #[repr(transparent)]
147    #[derive(Clone, Copy, Eq, PartialEq, Hash)]
148    pub enum CacheResult : u8 {
149        /// Cache was accessed.
150        ACCESS = bindings::PERF_COUNT_HW_CACHE_RESULT_ACCESS as _,
151
152        /// Cache access was a miss.
153        MISS = bindings::PERF_COUNT_HW_CACHE_RESULT_MISS as _,
154    }
155}