]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | //! Events we can monitor or count. |
2 | //! | |
3 | //! There are three general categories of event: | |
4 | //! | |
5 | //! - [`Hardware`] events are counted by the processor itself. This | |
6 | //! includes things like clock cycles, instructions retired, and cache and | |
7 | //! branch prediction statistics. | |
8 | //! | |
9 | //! - [`Software`] events are counted by the kernel. This includes things | |
10 | //! like context switches, page faults, and so on. | |
11 | //! | |
12 | //! - [`Cache`] events offer a more detailed view of the processor's cache | |
13 | //! counters. You can select which level of the cache hierarchy to observe, | |
14 | //! discriminate between data and instruction caches, and so on. | |
15 | //! | |
16 | //! The `Event` type is just an enum with a variant for each of the above types, | |
17 | //! which all implement `Into<Event>`. | |
18 | //! | |
19 | //! Linux supports many more kinds of events than this module covers, including | |
20 | //! events specific to particular make and model of processor, and events that | |
21 | //! are dynamically registered by drivers and kernel modules. If something you | |
22 | //! want is missing, think about the best API to expose it, and submit a pull | |
23 | //! request! | |
24 | //! | |
25 | //! [`Hardware`]: enum.Hardware.html | |
26 | //! [`Software`]: enum.Software.html | |
27 | //! [`Cache`]: struct.Cache.html | |
28 | ||
29 | #![allow(non_camel_case_types)] | |
30 | use perf_event_open_sys::bindings as bindings; | |
31 | ||
32 | /// Any sort of event. This is a sum of the [`Hardware`], | |
33 | /// [`Software`], and [`Cache`] types, which all implement | |
34 | /// `Into<Event>`. | |
35 | /// | |
36 | /// [`Hardware`]: enum.Hardware.html | |
37 | /// [`Software`]: enum.Software.html | |
38 | /// [`Cache`]: struct.Cache.html | |
39 | #[derive(Clone, Debug, Eq, PartialEq)] | |
40 | pub enum Event { | |
41 | #[allow(missing_docs)] | |
42 | Hardware(Hardware), | |
43 | ||
44 | #[allow(missing_docs)] | |
45 | Software(Software), | |
46 | ||
47 | #[allow(missing_docs)] | |
48 | Cache(Cache), | |
49 | } | |
50 | ||
51 | impl Event { | |
52 | pub(crate) fn as_type(&self) -> bindings::perf_type_id { | |
53 | match self { | |
54 | Event::Hardware(_) => bindings::perf_type_id_PERF_TYPE_HARDWARE, | |
55 | Event::Software(_) => bindings::perf_type_id_PERF_TYPE_SOFTWARE, | |
56 | Event::Cache(_) => bindings::perf_type_id_PERF_TYPE_HW_CACHE, | |
57 | } | |
58 | } | |
59 | ||
60 | pub(crate) fn as_config(self) -> u64 { | |
61 | match self { | |
62 | Event::Hardware(hw) => hw as _, | |
63 | Event::Software(sw) => sw as _, | |
64 | Event::Cache(cache) => cache.as_config(), | |
65 | } | |
66 | } | |
67 | } | |
68 | ||
69 | /// Hardware counters. | |
70 | /// | |
71 | /// These are counters implemented by the processor itself. Such counters vary | |
72 | /// from one architecture to the next, and even different models within a | |
73 | /// particular architecture will often change the way they expose this data. | |
74 | /// This is a selection of portable names for values that can be obtained on a | |
75 | /// wide variety of systems. | |
76 | /// | |
77 | /// Each variant of this enum corresponds to a particular `PERF_COUNT_HW_`... | |
78 | /// value supported by the [`perf_event_open`][man] system call. | |
79 | /// | |
80 | /// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html | |
81 | #[repr(u32)] | |
82 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | |
83 | pub enum Hardware { | |
84 | /// Total cycles. Be wary of what happens during CPU frequency scaling. | |
85 | CPU_CYCLES = bindings::perf_hw_id_PERF_COUNT_HW_CPU_CYCLES, | |
86 | ||
87 | /// Retired instructions. Be careful, these can be affected by various | |
88 | /// issues, most notably hardware interrupt counts. | |
89 | INSTRUCTIONS = bindings::perf_hw_id_PERF_COUNT_HW_INSTRUCTIONS, | |
90 | ||
91 | /// Cache accesses. Usually this indicates Last Level Cache accesses but | |
92 | /// this may vary depending on your CPU. This may include prefetches and | |
93 | /// coherency messages; again this depends on the design of your CPU. | |
94 | CACHE_REFERENCES = bindings::perf_hw_id_PERF_COUNT_HW_CACHE_REFERENCES, | |
95 | ||
96 | /// Cache misses. Usually this indicates Last Level Cache misses; this is | |
97 | /// intended to be used in conjunction with the | |
98 | /// PERF_COUNT_HW_CACHE_REFERENCES event to calculate cache miss rates. | |
99 | CACHE_MISSES = bindings::perf_hw_id_PERF_COUNT_HW_CACHE_MISSES, | |
100 | ||
101 | /// Retired branch instructions. Prior to Linux 2.6.35, this used the wrong | |
102 | /// event on AMD processors. | |
103 | BRANCH_INSTRUCTIONS = bindings::perf_hw_id_PERF_COUNT_HW_BRANCH_INSTRUCTIONS, | |
104 | ||
105 | /// Mispredicted branch instructions. | |
106 | BRANCH_MISSES = bindings::perf_hw_id_PERF_COUNT_HW_BRANCH_MISSES, | |
107 | ||
108 | /// Bus cycles, which can be different from total cycles. | |
109 | BUS_CYCLES = bindings::perf_hw_id_PERF_COUNT_HW_BUS_CYCLES, | |
110 | ||
111 | /// Stalled cycles during issue. (since Linux 3.0) | |
112 | STALLED_CYCLES_FRONTEND = bindings::perf_hw_id_PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, | |
113 | ||
114 | /// Stalled cycles during retirement. (since Linux 3.0) | |
115 | STALLED_CYCLES_BACKEND = bindings::perf_hw_id_PERF_COUNT_HW_STALLED_CYCLES_BACKEND, | |
116 | ||
117 | /// Total cycles; not affected by CPU frequency scaling. (since Linux 3.3) | |
118 | REF_CPU_CYCLES = bindings::perf_hw_id_PERF_COUNT_HW_REF_CPU_CYCLES, | |
119 | } | |
120 | ||
121 | impl From<Hardware> for Event { | |
122 | fn from(hw: Hardware) -> Event { | |
123 | Event::Hardware(hw) | |
124 | } | |
125 | } | |
126 | ||
127 | /// Software counters, implemented by the kernel. | |
128 | /// | |
129 | /// Each variant of this enum corresponds to a particular `PERF_COUNT_SW_`... | |
130 | /// value supported by the [`perf_event_open`][man] system call. | |
131 | /// | |
132 | /// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html | |
133 | #[repr(u32)] | |
134 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | |
135 | pub enum Software { | |
136 | /// This reports the CPU clock, a high-resolution per-CPU timer. | |
137 | CPU_CLOCK = bindings::perf_sw_ids_PERF_COUNT_SW_CPU_CLOCK, | |
138 | ||
139 | /// This reports a clock count specific to the task that is running. | |
140 | TASK_CLOCK = bindings::perf_sw_ids_PERF_COUNT_SW_TASK_CLOCK, | |
141 | ||
142 | /// This reports the number of page faults. | |
143 | PAGE_FAULTS = bindings::perf_sw_ids_PERF_COUNT_SW_PAGE_FAULTS, | |
144 | ||
145 | /// This counts context switches. Until Linux 2.6.34, these were all | |
146 | /// reported as user-space events, after that they are reported as happening | |
147 | /// in the kernel. | |
148 | CONTEXT_SWITCHES = bindings::perf_sw_ids_PERF_COUNT_SW_CONTEXT_SWITCHES, | |
149 | ||
150 | /// This reports the number of times the process has migrated to a new CPU. | |
151 | CPU_MIGRATIONS = bindings::perf_sw_ids_PERF_COUNT_SW_CPU_MIGRATIONS, | |
152 | ||
153 | /// This counts the number of minor page faults. These did not require disk | |
154 | /// I/O to handle. | |
155 | PAGE_FAULTS_MIN = bindings::perf_sw_ids_PERF_COUNT_SW_PAGE_FAULTS_MIN, | |
156 | ||
157 | /// This counts the number of major page faults. These required disk I/O to | |
158 | /// handle. | |
159 | PAGE_FAULTS_MAJ = bindings::perf_sw_ids_PERF_COUNT_SW_PAGE_FAULTS_MAJ, | |
160 | ||
161 | /// (since Linux 2.6.33) This counts the number of alignment faults. These | |
162 | /// happen when unaligned memory accesses happen; the kernel can handle | |
163 | /// these but it reduces performance. This happens only on some | |
164 | /// architectures (never on x86). | |
165 | ALIGNMENT_FAULTS = bindings::perf_sw_ids_PERF_COUNT_SW_ALIGNMENT_FAULTS, | |
166 | ||
167 | /// (since Linux 2.6.33) This counts the number of emulation faults. The | |
168 | /// kernel sometimes traps on unimplemented instructions and emulates them | |
169 | /// for user space. This can negatively impact performance. | |
170 | EMULATION_FAULTS = bindings::perf_sw_ids_PERF_COUNT_SW_EMULATION_FAULTS, | |
171 | ||
172 | /// (since Linux 3.12) This is a placeholder event that counts nothing. | |
173 | /// Informational sample record types such as mmap or comm must be | |
174 | /// associated with an active event. This dummy event allows gathering such | |
175 | /// records without requiring a counting event. | |
176 | DUMMY = bindings::perf_sw_ids_PERF_COUNT_SW_DUMMY, | |
177 | } | |
178 | ||
179 | impl From<Software> for Event { | |
180 | fn from(hw: Software) -> Event { | |
181 | Event::Software(hw) | |
182 | } | |
183 | } | |
184 | ||
185 | /// A cache event. | |
186 | /// | |
187 | /// A cache event has three identifying characteristics: | |
188 | /// | |
189 | /// - which cache to observe ([`which`]) | |
190 | /// | |
191 | /// - what sort of request it's handling ([`operation`]) | |
192 | /// | |
193 | /// - whether we want to count all cache accesses, or just misses | |
194 | /// ([`result`]). | |
195 | /// | |
196 | /// For example, to measure the L1 data cache's miss rate: | |
197 | /// | |
198 | /// # use perf_event::{Builder, Group}; | |
199 | /// # use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache}; | |
200 | /// # fn main() -> std::io::Result<()> { | |
201 | /// // A `Cache` value representing L1 data cache read accesses. | |
202 | /// const ACCESS: Cache = Cache { | |
203 | /// which: WhichCache::L1D, | |
204 | /// operation: CacheOp::READ, | |
205 | /// result: CacheResult::ACCESS, | |
206 | /// }; | |
207 | /// | |
208 | /// // A `Cache` value representing L1 data cache read misses. | |
209 | /// const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS }; | |
210 | /// | |
211 | /// // Construct a `Group` containing the two new counters, from which we | |
212 | /// // can get counts over matching periods of time. | |
213 | /// let mut group = Group::new()?; | |
214 | /// let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?; | |
215 | /// let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?; | |
216 | /// # Ok(()) } | |
217 | /// | |
218 | /// [`which`]: enum.WhichCache.html | |
219 | /// [`operation`]: enum.CacheOp.html | |
220 | /// [`result`]: enum.CacheResult.html | |
221 | #[derive(Debug, Clone, Eq, PartialEq)] | |
222 | pub struct Cache { | |
223 | /// Which cache is being monitored? (data, instruction, ...) | |
224 | pub which: WhichCache, | |
225 | ||
226 | /// What operation is being monitored? (read, write, etc.) | |
227 | pub operation: CacheOp, | |
228 | ||
229 | /// All accesses, or just misses? | |
230 | pub result: CacheResult, | |
231 | } | |
232 | ||
233 | impl From<Cache> for Event { | |
234 | fn from(hw: Cache) -> Event { | |
235 | Event::Cache(hw) | |
236 | } | |
237 | } | |
238 | ||
239 | impl Cache { | |
240 | fn as_config(&self) -> u64 { | |
241 | self.which as u64 | | |
242 | ((self.operation as u64) << 8) | | |
243 | ((self.result as u64) << 16) | |
244 | } | |
245 | } | |
246 | ||
247 | /// A cache whose events we would like to count. | |
248 | /// | |
249 | /// This is used in the `Cache` type as part of the identification of a cache | |
250 | /// event. Each variant here corresponds to a particular | |
251 | /// `PERF_COUNT_HW_CACHE_...` constant supported by the [`perf_event_open`][man] | |
252 | /// system call. | |
253 | /// | |
254 | /// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html | |
255 | #[repr(u32)] | |
256 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
257 | pub enum WhichCache { | |
258 | /// for measuring Level 1 Data Cache | |
259 | L1D = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_L1D, | |
260 | ||
261 | /// for measuring Level 1 Instruction Cache | |
262 | L1I = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_L1I, | |
263 | ||
264 | /// for measuring Last-Level Cache | |
265 | LL = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_LL, | |
266 | ||
267 | /// for measuring the Data TLB | |
268 | DTLB = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_DTLB, | |
269 | ||
270 | /// for measuring the Instruction TLB | |
271 | ITLB = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_ITLB, | |
272 | ||
273 | /// for measuring the branch prediction unit | |
274 | BPU = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_BPU, | |
275 | ||
276 | /// (since Linux 3.1) for measuring local memory accesses | |
277 | NODE = bindings::perf_hw_cache_id_PERF_COUNT_HW_CACHE_NODE, | |
278 | } | |
279 | ||
280 | /// What sort of cache operation we would like to observe. | |
281 | /// | |
282 | /// This is used in the `Cache` type as part of the identification of a cache | |
283 | /// event. Each variant here corresponds to a particular | |
284 | /// `PERF_COUNT_HW_CACHE_OP_...` constant supported by the | |
285 | /// [`perf_event_open`][man] system call. | |
286 | /// | |
287 | /// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html | |
288 | #[repr(u32)] | |
289 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
290 | pub enum CacheOp { | |
291 | /// Read accesses. | |
292 | READ = bindings::perf_hw_cache_op_id_PERF_COUNT_HW_CACHE_OP_READ, | |
293 | ||
294 | /// Write accesses. | |
295 | WRITE = bindings::perf_hw_cache_op_id_PERF_COUNT_HW_CACHE_OP_WRITE, | |
296 | ||
297 | /// Prefetch accesses. | |
298 | PREFETCH = bindings::perf_hw_cache_op_id_PERF_COUNT_HW_CACHE_OP_PREFETCH, | |
299 | } | |
300 | ||
301 | #[repr(u32)] | |
302 | /// What sort of cache result we're interested in observing. | |
303 | /// | |
304 | /// `ACCESS` counts the total number of operations performed on the cache, | |
305 | /// whereas `MISS` counts only those requests that the cache could not satisfy. | |
306 | /// Treating `MISS` as a fraction of `ACCESS` gives you the cache's miss rate. | |
307 | /// | |
308 | /// This is used used in the `Cache` type as part of the identification of a | |
309 | /// cache event. Each variant here corresponds to a particular | |
310 | /// `PERF_COUNT_HW_CACHE_RESULT_...` constant supported by the | |
311 | /// [`perf_event_open`][man] system call. | |
312 | /// | |
313 | /// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html | |
314 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | |
315 | pub enum CacheResult { | |
316 | /// to measure accesses | |
317 | ACCESS = bindings::perf_hw_cache_op_result_id_PERF_COUNT_HW_CACHE_RESULT_ACCESS, | |
318 | ||
319 | /// to measure misses | |
320 | MISS = bindings::perf_hw_cache_op_result_id_PERF_COUNT_HW_CACHE_RESULT_MISS, | |
321 | } |