perf_event/events.rs
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//! - [`Cache`] events, also counted by the processor, offer a more
10//! detailed view of the processor's cache counters. You can
11//! select which level of the cache hierarchy to observe,
12//! discriminate between data and instruction caches, and so on.
13//!
14//! - [`Software`] events are counted by the kernel. This includes things
15//! like context switches, page faults, and so on.
16//!
17//! - [`Breakpoint`] events correspond to hardware breakpoints. They can
18//! count read/write accesses to an address as well as execution of an
19//! instruction address.
20//!
21//! The `Event` type is just an enum with a variant for each of the above types,
22//! which all implement `Into<Event>`.
23//!
24//! Linux supports many more kinds of events than this module covers, including
25//! events specific to particular make and model of processor, and events that
26//! are dynamically registered by drivers and kernel modules. If something you
27//! want is missing, think about the best API to expose it, and submit a pull
28//! request!
29//!
30//! [`Hardware`]: enum.Hardware.html
31//! [`Software`]: enum.Software.html
32//! [`Cache`]: struct.Cache.html
33
34#![allow(non_camel_case_types)]
35use bitflags::bitflags;
36use perf_event_open_sys::bindings;
37
38/// Any sort of event. This is a sum of the [`Hardware`],
39/// [`Software`], and [`Cache`] types, which all implement
40/// `Into<Event>`.
41///
42/// [`Hardware`]: enum.Hardware.html
43/// [`Software`]: enum.Software.html
44/// [`Cache`]: struct.Cache.html
45#[derive(Clone, Debug, Eq, PartialEq)]
46pub enum Event {
47 #[allow(missing_docs)]
48 Hardware(Hardware),
49
50 #[allow(missing_docs)]
51 Software(Software),
52
53 #[allow(missing_docs)]
54 Cache(Cache),
55
56 #[allow(missing_docs)]
57 Breakpoint(Breakpoint),
58}
59
60impl Event {
61 pub(crate) fn update_attrs(self, attr: &mut bindings::perf_event_attr) {
62 match self {
63 Event::Hardware(hw) => {
64 attr.type_ = bindings::PERF_TYPE_HARDWARE;
65 attr.config = hw as _;
66 }
67 Event::Software(sw) => {
68 attr.type_ = bindings::PERF_TYPE_SOFTWARE;
69 attr.config = sw as _;
70 }
71 Event::Cache(cache) => {
72 attr.type_ = bindings::PERF_TYPE_HW_CACHE;
73 attr.config = cache.as_config();
74 }
75 Event::Breakpoint(bp) => {
76 attr.type_ = bindings::PERF_TYPE_BREAKPOINT;
77 // Clear config in case it was set by a previous call to update_attrs
78 attr.config = 0;
79
80 match bp {
81 Breakpoint::Data { access, addr, len } => {
82 attr.bp_type = access.bits();
83 attr.__bindgen_anon_3.bp_addr = addr;
84 attr.__bindgen_anon_4.bp_len = len;
85 }
86 Breakpoint::Code { addr } => {
87 attr.bp_type = bindings::HW_BREAKPOINT_X;
88 attr.__bindgen_anon_3.bp_addr = addr;
89 // According to the perf_event_open man page, execute breakpoints
90 // should set len to sizeof(long).
91 attr.__bindgen_anon_4.bp_len = std::mem::size_of::<libc::c_long>() as _;
92 }
93 }
94 }
95 }
96 }
97}
98
99/// Hardware counters.
100///
101/// These are counters implemented by the processor itself. Such counters vary
102/// from one architecture to the next, and even different models within a
103/// particular architecture will often change the way they expose this data.
104/// This is a selection of portable names for values that can be obtained on a
105/// wide variety of systems.
106///
107/// Each variant of this enum corresponds to a particular `PERF_COUNT_HW_`...
108/// value supported by the [`perf_event_open`][man] system call.
109///
110/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
111#[repr(u32)]
112#[derive(Copy, Clone, Debug, Eq, PartialEq)]
113pub enum Hardware {
114 /// Total cycles.
115 CPU_CYCLES = bindings::PERF_COUNT_HW_CPU_CYCLES,
116
117 /// Retired instructions.
118 INSTRUCTIONS = bindings::PERF_COUNT_HW_INSTRUCTIONS,
119
120 /// Cache accesses.
121 CACHE_REFERENCES = bindings::PERF_COUNT_HW_CACHE_REFERENCES,
122
123 /// Cache misses.
124 CACHE_MISSES = bindings::PERF_COUNT_HW_CACHE_MISSES,
125
126 /// Retired branch instructions.
127 BRANCH_INSTRUCTIONS = bindings::PERF_COUNT_HW_BRANCH_INSTRUCTIONS,
128
129 /// Mispredicted branch instructions.
130 BRANCH_MISSES = bindings::PERF_COUNT_HW_BRANCH_MISSES,
131
132 /// Bus cycles.
133 BUS_CYCLES = bindings::PERF_COUNT_HW_BUS_CYCLES,
134
135 /// Stalled cycles during issue.
136 STALLED_CYCLES_FRONTEND = bindings::PERF_COUNT_HW_STALLED_CYCLES_FRONTEND,
137
138 /// Stalled cycles during retirement.
139 STALLED_CYCLES_BACKEND = bindings::PERF_COUNT_HW_STALLED_CYCLES_BACKEND,
140
141 /// Total cycles, independent of frequency scaling.
142 REF_CPU_CYCLES = bindings::PERF_COUNT_HW_REF_CPU_CYCLES,
143}
144
145impl From<Hardware> for Event {
146 fn from(hw: Hardware) -> Event {
147 Event::Hardware(hw)
148 }
149}
150
151/// Software counters, implemented by the kernel.
152///
153/// Each variant of this enum corresponds to a particular `PERF_COUNT_SW_`...
154/// value supported by the [`perf_event_open`][man] system call.
155///
156/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
157#[repr(u32)]
158#[derive(Copy, Clone, Debug, Eq, PartialEq)]
159pub enum Software {
160 /// High-resolution per-CPU timer.
161 CPU_CLOCK = bindings::PERF_COUNT_SW_CPU_CLOCK,
162
163 /// Per-task clock count.
164 TASK_CLOCK = bindings::PERF_COUNT_SW_TASK_CLOCK,
165
166 /// Page faults.
167 PAGE_FAULTS = bindings::PERF_COUNT_SW_PAGE_FAULTS,
168
169 /// Context switches.
170 CONTEXT_SWITCHES = bindings::PERF_COUNT_SW_CONTEXT_SWITCHES,
171
172 /// Process migration to another CPU.
173 CPU_MIGRATIONS = bindings::PERF_COUNT_SW_CPU_MIGRATIONS,
174
175 /// Minor page faults: resolved without needing I/O.
176 PAGE_FAULTS_MIN = bindings::PERF_COUNT_SW_PAGE_FAULTS_MIN,
177
178 /// Major page faults: I/O was required to resolve these.
179 PAGE_FAULTS_MAJ = bindings::PERF_COUNT_SW_PAGE_FAULTS_MAJ,
180
181 /// Alignment faults that required kernel intervention.
182 ///
183 /// This is only generated on some CPUs, and never on x86_64 or
184 /// ARM.
185 ALIGNMENT_FAULTS = bindings::PERF_COUNT_SW_ALIGNMENT_FAULTS,
186
187 /// Instruction emulation faults.
188 EMULATION_FAULTS = bindings::PERF_COUNT_SW_EMULATION_FAULTS,
189
190 /// Placeholder, for collecting informational sample records.
191 DUMMY = bindings::PERF_COUNT_SW_DUMMY,
192}
193
194impl From<Software> for Event {
195 fn from(hw: Software) -> Event {
196 Event::Software(hw)
197 }
198}
199
200/// A cache event.
201///
202/// A cache event has three identifying characteristics:
203///
204/// - which cache to observe ([`which`])
205///
206/// - what sort of request it's handling ([`operation`])
207///
208/// - whether we want to count all cache accesses, or just misses
209/// ([`result`]).
210///
211/// For example, to measure the L1 data cache's miss rate:
212///
213/// # use perf_event::{Builder, Group};
214/// # use perf_event::events::{Cache, CacheOp, CacheResult, Hardware, WhichCache};
215/// # fn main() -> std::io::Result<()> {
216/// // A `Cache` value representing L1 data cache read accesses.
217/// const ACCESS: Cache = Cache {
218/// which: WhichCache::L1D,
219/// operation: CacheOp::READ,
220/// result: CacheResult::ACCESS,
221/// };
222///
223/// // A `Cache` value representing L1 data cache read misses.
224/// const MISS: Cache = Cache { result: CacheResult::MISS, ..ACCESS };
225///
226/// // Construct a `Group` containing the two new counters, from which we
227/// // can get counts over matching periods of time.
228/// let mut group = Group::new()?;
229/// let access_counter = Builder::new().group(&mut group).kind(ACCESS).build()?;
230/// let miss_counter = Builder::new().group(&mut group).kind(MISS).build()?;
231/// # Ok(()) }
232///
233/// [`which`]: enum.WhichCache.html
234/// [`operation`]: enum.CacheOp.html
235/// [`result`]: enum.CacheResult.html
236#[derive(Debug, Clone, Eq, PartialEq)]
237pub struct Cache {
238 /// Which cache is being monitored? (data, instruction, ...)
239 pub which: WhichCache,
240
241 /// What operation is being monitored? (read, write, etc.)
242 pub operation: CacheOp,
243
244 /// All accesses, or just misses?
245 pub result: CacheResult,
246}
247
248impl From<Cache> for Event {
249 fn from(hw: Cache) -> Event {
250 Event::Cache(hw)
251 }
252}
253
254impl Cache {
255 fn as_config(&self) -> u64 {
256 self.which as u64 | ((self.operation as u64) << 8) | ((self.result as u64) << 16)
257 }
258}
259
260/// A cache whose events we would like to count.
261///
262/// This is used in the `Cache` type as part of the identification of a cache
263/// event. Each variant here corresponds to a particular
264/// `PERF_COUNT_HW_CACHE_...` constant supported by the [`perf_event_open`][man]
265/// system call.
266///
267/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
268#[repr(u32)]
269#[derive(Debug, Clone, Copy, Eq, PartialEq)]
270pub enum WhichCache {
271 /// Level 1 data cache.
272 L1D = bindings::PERF_COUNT_HW_CACHE_L1D,
273
274 /// Level 1 instruction cache.
275 L1I = bindings::PERF_COUNT_HW_CACHE_L1I,
276
277 /// Last-level cache.
278 LL = bindings::PERF_COUNT_HW_CACHE_LL,
279
280 /// Data translation lookaside buffer (virtual address translation).
281 DTLB = bindings::PERF_COUNT_HW_CACHE_DTLB,
282
283 /// Instruction translation lookaside buffer (virtual address translation).
284 ITLB = bindings::PERF_COUNT_HW_CACHE_ITLB,
285
286 /// Branch prediction.
287 BPU = bindings::PERF_COUNT_HW_CACHE_BPU,
288
289 /// Memory accesses that stay local to the originating NUMA node.
290 NODE = bindings::PERF_COUNT_HW_CACHE_NODE,
291}
292
293/// What sort of cache operation we would like to observe.
294///
295/// This is used in the `Cache` type as part of the identification of a cache
296/// event. Each variant here corresponds to a particular
297/// `PERF_COUNT_HW_CACHE_OP_...` constant supported by the
298/// [`perf_event_open`][man] system call.
299///
300/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
301#[repr(u32)]
302#[derive(Debug, Clone, Copy, Eq, PartialEq)]
303pub enum CacheOp {
304 /// Read accesses.
305 READ = bindings::PERF_COUNT_HW_CACHE_OP_READ,
306
307 /// Write accesses.
308 WRITE = bindings::PERF_COUNT_HW_CACHE_OP_WRITE,
309
310 /// Prefetch accesses.
311 PREFETCH = bindings::PERF_COUNT_HW_CACHE_OP_PREFETCH,
312}
313
314#[repr(u32)]
315/// What sort of cache result we're interested in observing.
316///
317/// `ACCESS` counts the total number of operations performed on the cache,
318/// whereas `MISS` counts only those requests that the cache could not satisfy.
319/// Treating `MISS` as a fraction of `ACCESS` gives you the cache's miss rate.
320///
321/// This is used used in the `Cache` type as part of the identification of a
322/// cache event. Each variant here corresponds to a particular
323/// `PERF_COUNT_HW_CACHE_RESULT_...` constant supported by the
324/// [`perf_event_open`][man] system call.
325///
326/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
327#[derive(Debug, Clone, Copy, Eq, PartialEq)]
328pub enum CacheResult {
329 /// Cache was accessed.
330 ACCESS = bindings::PERF_COUNT_HW_CACHE_RESULT_ACCESS,
331
332 /// Cache access was a miss.
333 MISS = bindings::PERF_COUNT_HW_CACHE_RESULT_MISS,
334}
335
336bitflags! {
337 /// Memory access mask for a hardware data breakpoint.
338 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
339 pub struct BreakpointAccess : u32 {
340 /// Count when we read the memory location.
341 const READ = bindings::HW_BREAKPOINT_R;
342
343 /// Count when we write the memory location.
344 const WRITE = bindings::HW_BREAKPOINT_W;
345
346 /// Count when we read or write the memory location.
347 const READ_WRITE = Self::READ.union(Self::WRITE).bits();
348 }
349}
350
351/// A hardware breakpoint.
352///
353/// A hardware breakpoint watches a region of memory for accesses. It has three
354/// parameters:
355/// - the address that is being watched (`addr`)
356/// - the number of bytes that breakpoint covers (`len`)
357/// - which type of memory accesses we care about (`ty`)
358///
359/// Note that both number of bytes that can be watched as well as the number of
360/// breakpoints that is allowed to be active at any given time is limited.
361///
362/// # Execute Breakpoint
363/// We can use a breakpoint to count the number of times that a function gets
364/// called, as long as the compiler does not optimize the function away.
365///
366/// ```
367/// # use perf_event::Builder;
368/// # use perf_event::events::Breakpoint;
369/// #[inline(never)]
370/// fn do_some_things() {
371/// // ...
372/// # println!("test println so the function doesn't get removed")
373/// }
374///
375/// let fnptr = do_some_things as fn() as usize;
376/// let mut counter = Builder::new()
377/// .kind(Breakpoint::execute(fnptr as u64))
378/// .build()?;
379/// counter.enable()?;
380///
381/// for _ in 0..500 {
382/// do_some_things();
383/// }
384///
385/// counter.disable()?;
386/// assert_eq!(counter.read()?, 500);
387/// # Ok::<(), std::io::Error>(())
388/// ```
389///
390/// # Data Breakpoint
391/// We can also use a breakpoint to count the number of times that a memory
392/// location is accessed.
393/// ```
394/// # use perf_event::Builder;
395/// # use perf_event::events::Breakpoint;
396/// #
397/// let mut data: Vec<u64> = (0..1024).rev().collect();
398///
399/// let mut counter = Builder::new()
400/// .kind(Breakpoint::read_write(&data[20] as *const _ as usize as u64, 8))
401/// .build()?;
402/// counter.enable()?;
403/// data.sort();
404/// counter.disable()?;
405///
406/// println!("Position 20 accessed {} times", counter.read()?);
407/// # Ok::<(), std::io::Error>(())
408/// ```
409///
410/// # Usage Notes
411/// - Some systems do not support creating read-only or write-only breakpoints.
412/// If you are getting `EINVAL` errors while trying to build such a counter
413/// using a read-write breakpoint might work instead.
414///
415/// - The valid values of len are quite limited. The [`perf_event_open`][man]
416/// manpage indicates that the only valid values for `bp_len` are 1, 2, 4,
417/// and 8.
418///
419/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
420#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
421pub enum Breakpoint {
422 /// Data breakpoint. Triggers when code reads or writes to the memory area
423 /// as configured by the parameters below.
424 Data {
425 /// Bitfield containing the types of accesses we want the breakpoint to
426 /// trigger on.
427 access: BreakpointAccess,
428
429 /// The address of the memory location on which the breakpoint should
430 /// trigger.
431 addr: u64,
432
433 /// The length of the breakpoint being measured.
434 ///
435 /// There are a limited number of valid values for this field. Basically,
436 /// the options are 1, 2, 4, and 8. Setting this field to anything else
437 /// will cause counter creation to fail with an error.
438 len: u64,
439 },
440
441 /// Code breakpoint. Triggers when the code at the address is executed.
442 Code {
443 /// The address that the breakpoint is monitoring.
444 addr: u64,
445 },
446}
447
448impl Breakpoint {
449 /// Create a code execution breakpoint, that counts the number of
450 /// times the instruction at the provided address was executed.
451 pub const fn execute(addr: u64) -> Self {
452 Self::Code { addr }
453 }
454
455 /// Create a memory read breakpoint, that counts the number of
456 /// times we read from the provided memory location.
457 ///
458 /// See the struct field docs for valid values of `len`.
459 pub const fn read(addr: u64, len: u64) -> Self {
460 Self::Data {
461 access: BreakpointAccess::READ,
462 addr,
463 len,
464 }
465 }
466
467 /// Create a memory write breakpoint, that counts the number of
468 /// times we write to the provided memory location.
469 ///
470 /// See the struct field docs for valid values of `len`.
471 pub const fn write(addr: u64, len: u64) -> Self {
472 Self::Data {
473 access: BreakpointAccess::WRITE,
474 addr,
475 len,
476 }
477 }
478
479 /// Create a memory access breakpoint, that counts the number of
480 /// times we either read from or write to the provided memory
481 /// location.
482 ///
483 /// See the struct field docs for valid values of `len`.
484 pub const fn read_write(addr: u64, len: u64) -> Self {
485 Self::Data {
486 access: BreakpointAccess::READ_WRITE,
487 addr,
488 len,
489 }
490 }
491}
492
493impl From<Breakpoint> for Event {
494 fn from(bp: Breakpoint) -> Self {
495 Event::Breakpoint(bp)
496 }
497}