Skip to main content

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}